Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
6.1 KiB

4 years ago
  1. /*
  2. * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
  3. * MIT/X Consortium License
  4. */
  5. #include <X11/Xft/Xft.h>
  6. #include "st.h"
  7. #include "boxdraw_data.h"
  8. /* Rounded non-negative integers division of n / d */
  9. #define DIV(n, d) (((n) + (d) / 2) / (d))
  10. static Display *xdpy;
  11. static Colormap xcmap;
  12. static XftDraw *xd;
  13. static Visual *xvis;
  14. static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
  15. static void drawboxlines(int, int, int, int, XftColor *, ushort);
  16. /* public API */
  17. void
  18. boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
  19. {
  20. xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
  21. }
  22. int
  23. isboxdraw(Rune u)
  24. {
  25. Rune block = u & ~0xff;
  26. return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
  27. (boxdraw_braille && block == 0x2800);
  28. }
  29. /* the "index" is actually the entire shape data encoded as ushort */
  30. ushort
  31. boxdrawindex(const Glyph *g)
  32. {
  33. if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
  34. return BRL | (uint8_t)g->u;
  35. if (boxdraw_bold && (g->mode & ATTR_BOLD))
  36. return BDB | boxdata[(uint8_t)g->u];
  37. return boxdata[(uint8_t)g->u];
  38. }
  39. void
  40. drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg,
  41. const XftGlyphFontSpec *specs, int len)
  42. {
  43. for ( ; len-- > 0; x += cw, specs++)
  44. drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
  45. }
  46. /* implementation */
  47. void
  48. drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd)
  49. {
  50. ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
  51. if (bd & (BDL | BDA)) {
  52. /* lines (light/double/heavy/arcs) */
  53. drawboxlines(x, y, w, h, fg, bd);
  54. } else if (cat == BBD) {
  55. /* lower (8-X)/8 block */
  56. int d = DIV((uint8_t)bd * h, 8);
  57. XftDrawRect(xd, fg, x, y + d, w, h - d);
  58. } else if (cat == BBU) {
  59. /* upper X/8 block */
  60. XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8));
  61. } else if (cat == BBL) {
  62. /* left X/8 block */
  63. XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h);
  64. } else if (cat == BBR) {
  65. /* right (8-X)/8 block */
  66. int d = DIV((uint8_t)bd * w, 8);
  67. XftDrawRect(xd, fg, x + d, y, w - d, h);
  68. } else if (cat == BBQ) {
  69. /* Quadrants */
  70. int w2 = DIV(w, 2), h2 = DIV(h, 2);
  71. if (bd & TL)
  72. XftDrawRect(xd, fg, x, y, w2, h2);
  73. if (bd & TR)
  74. XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
  75. if (bd & BL)
  76. XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
  77. if (bd & BR)
  78. XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2);
  79. } else if (bd & BBS) {
  80. /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
  81. int d = (uint8_t)bd;
  82. XftColor xfc;
  83. XRenderColor xrc = { .alpha = 0xffff };
  84. xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4);
  85. xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4);
  86. xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4);
  87. XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc);
  88. XftDrawRect(xd, &xfc, x, y, w, h);
  89. XftColorFree(xdpy, xvis, xcmap, &xfc);
  90. } else if (cat == BRL) {
  91. /* braille, each data bit corresponds to one dot at 2x4 grid */
  92. int w1 = DIV(w, 2);
  93. int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
  94. if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1);
  95. if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1);
  96. if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2);
  97. if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1);
  98. if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1);
  99. if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2);
  100. if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3);
  101. if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3);
  102. }
  103. }
  104. void
  105. drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd)
  106. {
  107. /* s: stem thickness. width/8 roughly matches underscore thickness. */
  108. /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
  109. /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
  110. int mwh = MIN(w, h);
  111. int base_s = MAX(1, DIV(mwh, 8));
  112. int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
  113. int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
  114. int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
  115. /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
  116. /* The base length (per direction till edge) includes this square. */
  117. int light = bd & (LL | LU | LR | LD);
  118. int double_ = bd & (DL | DU | DR | DD);
  119. if (light) {
  120. /* d: additional (negative) length to not-draw the center */
  121. /* texel - at arcs and avoid drawing inside (some) doubles */
  122. int arc = bd & BDA;
  123. int multi_light = light & (light - 1);
  124. int multi_double = double_ & (double_ - 1);
  125. /* light crosses double only at DH+LV, DV+LH (ref. shapes) */
  126. int d = arc || (multi_double && !multi_light) ? -s : 0;
  127. if (bd & LL)
  128. XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
  129. if (bd & LU)
  130. XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
  131. if (bd & LR)
  132. XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s);
  133. if (bd & LD)
  134. XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d);
  135. }
  136. /* double lines - also align with light to form heavy when combined */
  137. if (double_) {
  138. /*
  139. * going clockwise, for each double-ray: p is additional length
  140. * to the single-ray nearer to the previous direction, and n to
  141. * the next. p and n adjust from the base length to lengths
  142. * which consider other doubles - shorter to avoid intersections
  143. * (p, n), or longer to draw the far-corner texel (n).
  144. */
  145. int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
  146. if (dl) {
  147. int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
  148. XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s);
  149. XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s);
  150. }
  151. if (du) {
  152. int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
  153. XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p);
  154. XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n);
  155. }
  156. if (dr) {
  157. int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
  158. XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s);
  159. XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s);
  160. }
  161. if (dd) {
  162. int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
  163. XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p);
  164. XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n);
  165. }
  166. }
  167. }