diff options
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | boxdraw.c | 194 | ||||
| -rw-r--r-- | boxdraw_data.h | 214 | ||||
| -rw-r--r-- | config.def.h | 12 | ||||
| -rw-r--r-- | st.c | 3 | ||||
| -rw-r--r-- | st.h | 10 | ||||
| -rw-r--r-- | x.c | 21 |
8 files changed, 453 insertions, 6 deletions
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | include config.mk | 5 | include config.mk |
| 6 | 6 | ||
| 7 | SRC = st.c x.c | 7 | SRC = st.c x.c boxdraw.c |
| 8 | OBJ = $(SRC:.c=.o) | 8 | OBJ = $(SRC:.c=.o) |
| 9 | 9 | ||
| 10 | all: options st | 10 | all: options st |
| @@ -23,6 +23,7 @@ config.h: | |||
| 23 | 23 | ||
| 24 | st.o: config.h st.h win.h | 24 | st.o: config.h st.h win.h |
| 25 | x.o: arg.h config.h st.h win.h | 25 | x.o: arg.h config.h st.h win.h |
| 26 | boxdraw.o: config.h st.h boxdraw_data.h | ||
| 26 | 27 | ||
| 27 | $(OBJ): config.h config.mk | 28 | $(OBJ): config.h config.mk |
| 28 | 29 | ||
| @@ -11,6 +11,8 @@ were applied. | |||
| 11 | desktop entry during installation; | 11 | desktop entry during installation; |
| 12 | + [scrollback](https://st.suckless.org/patches/scrollback/) - enables | 12 | + [scrollback](https://st.suckless.org/patches/scrollback/) - enables |
| 13 | buffer scrollback. | 13 | buffer scrollback. |
| 14 | + [boxdraw](https://st.suckless.org/patches/boxdraw/) - handles | ||
| 15 | line/box/braille drawings | ||
| 14 | 16 | ||
| 15 | Requirements | 17 | Requirements |
| 16 | ------------ | 18 | ------------ |
diff --git a/boxdraw.c b/boxdraw.c new file mode 100644 index 0000000..28a92d0 --- /dev/null +++ b/boxdraw.c | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih | ||
| 3 | * MIT/X Consortium License | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <X11/Xft/Xft.h> | ||
| 7 | #include "st.h" | ||
| 8 | #include "boxdraw_data.h" | ||
| 9 | |||
| 10 | /* Rounded non-negative integers division of n / d */ | ||
| 11 | #define DIV(n, d) (((n) + (d) / 2) / (d)) | ||
| 12 | |||
| 13 | static Display *xdpy; | ||
| 14 | static Colormap xcmap; | ||
| 15 | static XftDraw *xd; | ||
| 16 | static Visual *xvis; | ||
| 17 | |||
| 18 | static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort); | ||
| 19 | static void drawboxlines(int, int, int, int, XftColor *, ushort); | ||
| 20 | |||
| 21 | /* public API */ | ||
| 22 | |||
| 23 | void | ||
| 24 | boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis) | ||
| 25 | { | ||
| 26 | xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis; | ||
| 27 | } | ||
| 28 | |||
| 29 | int | ||
| 30 | isboxdraw(Rune u) | ||
| 31 | { | ||
| 32 | Rune block = u & ~0xff; | ||
| 33 | return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) || | ||
| 34 | (boxdraw_braille && block == 0x2800); | ||
| 35 | } | ||
| 36 | |||
| 37 | /* the "index" is actually the entire shape data encoded as ushort */ | ||
| 38 | ushort | ||
| 39 | boxdrawindex(const Glyph *g) | ||
| 40 | { | ||
| 41 | if (boxdraw_braille && (g->u & ~0xff) == 0x2800) | ||
| 42 | return BRL | (uint8_t)g->u; | ||
| 43 | if (boxdraw_bold && (g->mode & ATTR_BOLD)) | ||
| 44 | return BDB | boxdata[(uint8_t)g->u]; | ||
| 45 | return boxdata[(uint8_t)g->u]; | ||
| 46 | } | ||
| 47 | |||
| 48 | void | ||
| 49 | drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg, | ||
| 50 | const XftGlyphFontSpec *specs, int len) | ||
| 51 | { | ||
| 52 | for ( ; len-- > 0; x += cw, specs++) | ||
| 53 | drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph); | ||
| 54 | } | ||
| 55 | |||
| 56 | /* implementation */ | ||
| 57 | |||
| 58 | void | ||
| 59 | drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd) | ||
| 60 | { | ||
| 61 | ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */ | ||
| 62 | if (bd & (BDL | BDA)) { | ||
| 63 | /* lines (light/double/heavy/arcs) */ | ||
| 64 | drawboxlines(x, y, w, h, fg, bd); | ||
| 65 | |||
| 66 | } else if (cat == BBD) { | ||
| 67 | /* lower (8-X)/8 block */ | ||
| 68 | int d = DIV((uint8_t)bd * h, 8); | ||
| 69 | XftDrawRect(xd, fg, x, y + d, w, h - d); | ||
| 70 | |||
| 71 | } else if (cat == BBU) { | ||
| 72 | /* upper X/8 block */ | ||
| 73 | XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8)); | ||
| 74 | |||
| 75 | } else if (cat == BBL) { | ||
| 76 | /* left X/8 block */ | ||
| 77 | XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h); | ||
| 78 | |||
| 79 | } else if (cat == BBR) { | ||
| 80 | /* right (8-X)/8 block */ | ||
| 81 | int d = DIV((uint8_t)bd * w, 8); | ||
| 82 | XftDrawRect(xd, fg, x + d, y, w - d, h); | ||
| 83 | |||
| 84 | } else if (cat == BBQ) { | ||
| 85 | /* Quadrants */ | ||
| 86 | int w2 = DIV(w, 2), h2 = DIV(h, 2); | ||
| 87 | if (bd & TL) | ||
| 88 | XftDrawRect(xd, fg, x, y, w2, h2); | ||
| 89 | if (bd & TR) | ||
| 90 | XftDrawRect(xd, fg, x + w2, y, w - w2, h2); | ||
| 91 | if (bd & BL) | ||
| 92 | XftDrawRect(xd, fg, x, y + h2, w2, h - h2); | ||
| 93 | if (bd & BR) | ||
| 94 | XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2); | ||
| 95 | |||
| 96 | } else if (bd & BBS) { | ||
| 97 | /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */ | ||
| 98 | int d = (uint8_t)bd; | ||
| 99 | XftColor xfc; | ||
| 100 | XRenderColor xrc = { .alpha = 0xffff }; | ||
| 101 | |||
| 102 | xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4); | ||
| 103 | xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4); | ||
| 104 | xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4); | ||
| 105 | |||
| 106 | XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc); | ||
| 107 | XftDrawRect(xd, &xfc, x, y, w, h); | ||
| 108 | XftColorFree(xdpy, xvis, xcmap, &xfc); | ||
| 109 | |||
| 110 | } else if (cat == BRL) { | ||
| 111 | /* braille, each data bit corresponds to one dot at 2x4 grid */ | ||
| 112 | int w1 = DIV(w, 2); | ||
| 113 | int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4); | ||
| 114 | |||
| 115 | if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1); | ||
| 116 | if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1); | ||
| 117 | if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2); | ||
| 118 | if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1); | ||
| 119 | if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1); | ||
| 120 | if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2); | ||
| 121 | if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3); | ||
| 122 | if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3); | ||
| 123 | |||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | void | ||
| 128 | drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd) | ||
| 129 | { | ||
| 130 | /* s: stem thickness. width/8 roughly matches underscore thickness. */ | ||
| 131 | /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */ | ||
| 132 | /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */ | ||
| 133 | int mwh = MIN(w, h); | ||
| 134 | int base_s = MAX(1, DIV(mwh, 8)); | ||
| 135 | int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */ | ||
| 136 | int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s; | ||
| 137 | int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2); | ||
| 138 | /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */ | ||
| 139 | /* The base length (per direction till edge) includes this square. */ | ||
| 140 | |||
| 141 | int light = bd & (LL | LU | LR | LD); | ||
| 142 | int double_ = bd & (DL | DU | DR | DD); | ||
| 143 | |||
| 144 | if (light) { | ||
| 145 | /* d: additional (negative) length to not-draw the center */ | ||
| 146 | /* texel - at arcs and avoid drawing inside (some) doubles */ | ||
| 147 | int arc = bd & BDA; | ||
| 148 | int multi_light = light & (light - 1); | ||
| 149 | int multi_double = double_ & (double_ - 1); | ||
| 150 | /* light crosses double only at DH+LV, DV+LH (ref. shapes) */ | ||
| 151 | int d = arc || (multi_double && !multi_light) ? -s : 0; | ||
| 152 | |||
| 153 | if (bd & LL) | ||
| 154 | XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s); | ||
| 155 | if (bd & LU) | ||
| 156 | XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d); | ||
| 157 | if (bd & LR) | ||
| 158 | XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s); | ||
| 159 | if (bd & LD) | ||
| 160 | XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d); | ||
| 161 | } | ||
| 162 | |||
| 163 | /* double lines - also align with light to form heavy when combined */ | ||
| 164 | if (double_) { | ||
| 165 | /* | ||
| 166 | * going clockwise, for each double-ray: p is additional length | ||
| 167 | * to the single-ray nearer to the previous direction, and n to | ||
| 168 | * the next. p and n adjust from the base length to lengths | ||
| 169 | * which consider other doubles - shorter to avoid intersections | ||
| 170 | * (p, n), or longer to draw the far-corner texel (n). | ||
| 171 | */ | ||
| 172 | int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD; | ||
| 173 | if (dl) { | ||
| 174 | int p = dd ? -s : 0, n = du ? -s : dd ? s : 0; | ||
| 175 | XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s); | ||
| 176 | XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s); | ||
| 177 | } | ||
| 178 | if (du) { | ||
| 179 | int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0; | ||
| 180 | XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p); | ||
| 181 | XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n); | ||
| 182 | } | ||
| 183 | if (dr) { | ||
| 184 | int p = du ? -s : 0, n = dd ? -s : du ? s : 0; | ||
| 185 | XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s); | ||
| 186 | XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s); | ||
| 187 | } | ||
| 188 | if (dd) { | ||
| 189 | int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0; | ||
| 190 | XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p); | ||
| 191 | XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n); | ||
| 192 | } | ||
| 193 | } | ||
| 194 | } | ||
diff --git a/boxdraw_data.h b/boxdraw_data.h new file mode 100644 index 0000000..7890500 --- /dev/null +++ b/boxdraw_data.h | |||
| @@ -0,0 +1,214 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih | ||
| 3 | * MIT/X Consortium License | ||
| 4 | */ | ||
| 5 | |||
| 6 | /* | ||
| 7 | * U+25XX codepoints data | ||
| 8 | * | ||
| 9 | * References: | ||
| 10 | * http://www.unicode.org/charts/PDF/U2500.pdf | ||
| 11 | * http://www.unicode.org/charts/PDF/U2580.pdf | ||
| 12 | * | ||
| 13 | * Test page: | ||
| 14 | * https://github.com/GNOME/vte/blob/master/doc/boxes.txt | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* Each shape is encoded as 16-bits. Higher bits are category, lower are data */ | ||
| 18 | /* Categories (mutually exclusive except BDB): */ | ||
| 19 | /* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */ | ||
| 20 | #define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */ | ||
| 21 | #define BDA (1<<9) /* Box Draw Arc (light) */ | ||
| 22 | |||
| 23 | #define BBD (1<<10) /* Box Block Down (lower) X/8 */ | ||
| 24 | #define BBL (2<<10) /* Box Block Left X/8 */ | ||
| 25 | #define BBU (3<<10) /* Box Block Upper X/8 */ | ||
| 26 | #define BBR (4<<10) /* Box Block Right X/8 */ | ||
| 27 | #define BBQ (5<<10) /* Box Block Quadrants */ | ||
| 28 | #define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */ | ||
| 29 | |||
| 30 | #define BBS (1<<14) /* Box Block Shades */ | ||
| 31 | #define BDB (1<<15) /* Box Draw is Bold */ | ||
| 32 | |||
| 33 | /* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */ | ||
| 34 | /* Heavy is light+double (literally drawing light+double align to form heavy) */ | ||
| 35 | #define LL (1<<0) | ||
| 36 | #define LU (1<<1) | ||
| 37 | #define LR (1<<2) | ||
| 38 | #define LD (1<<3) | ||
| 39 | #define LH (LL+LR) | ||
| 40 | #define LV (LU+LD) | ||
| 41 | |||
| 42 | #define DL (1<<4) | ||
| 43 | #define DU (1<<5) | ||
| 44 | #define DR (1<<6) | ||
| 45 | #define DD (1<<7) | ||
| 46 | #define DH (DL+DR) | ||
| 47 | #define DV (DU+DD) | ||
| 48 | |||
| 49 | #define HL (LL+DL) | ||
| 50 | #define HU (LU+DU) | ||
| 51 | #define HR (LR+DR) | ||
| 52 | #define HD (LD+DD) | ||
| 53 | #define HH (HL+HR) | ||
| 54 | #define HV (HU+HD) | ||
| 55 | |||
| 56 | /* (BBQ) Quadrants Top/Bottom x Left/Right */ | ||
| 57 | #define TL (1<<0) | ||
| 58 | #define TR (1<<1) | ||
| 59 | #define BL (1<<2) | ||
| 60 | #define BR (1<<3) | ||
| 61 | |||
| 62 | /* Data for U+2500 - U+259F except dashes/diagonals */ | ||
| 63 | static const unsigned short boxdata[256] = { | ||
| 64 | /* light lines */ | ||
| 65 | [0x00] = BDL + LH, /* light horizontal */ | ||
| 66 | [0x02] = BDL + LV, /* light vertical */ | ||
| 67 | [0x0c] = BDL + LD + LR, /* light down and right */ | ||
| 68 | [0x10] = BDL + LD + LL, /* light down and left */ | ||
| 69 | [0x14] = BDL + LU + LR, /* light up and right */ | ||
| 70 | [0x18] = BDL + LU + LL, /* light up and left */ | ||
| 71 | [0x1c] = BDL + LV + LR, /* light vertical and right */ | ||
| 72 | [0x24] = BDL + LV + LL, /* light vertical and left */ | ||
| 73 | [0x2c] = BDL + LH + LD, /* light horizontal and down */ | ||
| 74 | [0x34] = BDL + LH + LU, /* light horizontal and up */ | ||
| 75 | [0x3c] = BDL + LV + LH, /* light vertical and horizontal */ | ||
| 76 | [0x74] = BDL + LL, /* light left */ | ||
| 77 | [0x75] = BDL + LU, /* light up */ | ||
| 78 | [0x76] = BDL + LR, /* light right */ | ||
| 79 | [0x77] = BDL + LD, /* light down */ | ||
| 80 | |||
| 81 | /* heavy [+light] lines */ | ||
| 82 | [0x01] = BDL + HH, | ||
| 83 | [0x03] = BDL + HV, | ||
| 84 | [0x0d] = BDL + HR + LD, | ||
| 85 | [0x0e] = BDL + HD + LR, | ||
| 86 | [0x0f] = BDL + HD + HR, | ||
| 87 | [0x11] = BDL + HL + LD, | ||
| 88 | [0x12] = BDL + HD + LL, | ||
| 89 | [0x13] = BDL + HD + HL, | ||
| 90 | [0x15] = BDL + HR + LU, | ||
| 91 | [0x16] = BDL + HU + LR, | ||
| 92 | [0x17] = BDL + HU + HR, | ||
| 93 | [0x19] = BDL + HL + LU, | ||
| 94 | [0x1a] = BDL + HU + LL, | ||
| 95 | [0x1b] = BDL + HU + HL, | ||
| 96 | [0x1d] = BDL + HR + LV, | ||
| 97 | [0x1e] = BDL + HU + LD + LR, | ||
| 98 | [0x1f] = BDL + HD + LR + LU, | ||
| 99 | [0x20] = BDL + HV + LR, | ||
| 100 | [0x21] = BDL + HU + HR + LD, | ||
| 101 | [0x22] = BDL + HD + HR + LU, | ||
| 102 | [0x23] = BDL + HV + HR, | ||
| 103 | [0x25] = BDL + HL + LV, | ||
| 104 | [0x26] = BDL + HU + LD + LL, | ||
| 105 | [0x27] = BDL + HD + LU + LL, | ||
| 106 | [0x28] = BDL + HV + LL, | ||
| 107 | [0x29] = BDL + HU + HL + LD, | ||
| 108 | [0x2a] = BDL + HD + HL + LU, | ||
| 109 | [0x2b] = BDL + HV + HL, | ||
| 110 | [0x2d] = BDL + HL + LD + LR, | ||
| 111 | [0x2e] = BDL + HR + LL + LD, | ||
| 112 | [0x2f] = BDL + HH + LD, | ||
| 113 | [0x30] = BDL + HD + LH, | ||
| 114 | [0x31] = BDL + HD + HL + LR, | ||
| 115 | [0x32] = BDL + HR + HD + LL, | ||
| 116 | [0x33] = BDL + HH + HD, | ||
| 117 | [0x35] = BDL + HL + LU + LR, | ||
| 118 | [0x36] = BDL + HR + LU + LL, | ||
| 119 | [0x37] = BDL + HH + LU, | ||
| 120 | [0x38] = BDL + HU + LH, | ||
| 121 | [0x39] = BDL + HU + HL + LR, | ||
| 122 | [0x3a] = BDL + HU + HR + LL, | ||
| 123 | [0x3b] = BDL + HH + HU, | ||
| 124 | [0x3d] = BDL + HL + LV + LR, | ||
| 125 | [0x3e] = BDL + HR + LV + LL, | ||
| 126 | [0x3f] = BDL + HH + LV, | ||
| 127 | [0x40] = BDL + HU + LH + LD, | ||
| 128 | [0x41] = BDL + HD + LH + LU, | ||
| 129 | [0x42] = BDL + HV + LH, | ||
| 130 | [0x43] = BDL + HU + HL + LD + LR, | ||
| 131 | [0x44] = BDL + HU + HR + LD + LL, | ||
| 132 | [0x45] = BDL + HD + HL + LU + LR, | ||
| 133 | [0x46] = BDL + HD + HR + LU + LL, | ||
| 134 | [0x47] = BDL + HH + HU + LD, | ||
| 135 | [0x48] = BDL + HH + HD + LU, | ||
| 136 | [0x49] = BDL + HV + HL + LR, | ||
| 137 | [0x4a] = BDL + HV + HR + LL, | ||
| 138 | [0x4b] = BDL + HV + HH, | ||
| 139 | [0x78] = BDL + HL, | ||
| 140 | [0x79] = BDL + HU, | ||
| 141 | [0x7a] = BDL + HR, | ||
| 142 | [0x7b] = BDL + HD, | ||
| 143 | [0x7c] = BDL + HR + LL, | ||
| 144 | [0x7d] = BDL + HD + LU, | ||
| 145 | [0x7e] = BDL + HL + LR, | ||
| 146 | [0x7f] = BDL + HU + LD, | ||
| 147 | |||
| 148 | /* double [+light] lines */ | ||
| 149 | [0x50] = BDL + DH, | ||
| 150 | [0x51] = BDL + DV, | ||
| 151 | [0x52] = BDL + DR + LD, | ||
| 152 | [0x53] = BDL + DD + LR, | ||
| 153 | [0x54] = BDL + DR + DD, | ||
| 154 | [0x55] = BDL + DL + LD, | ||
| 155 | [0x56] = BDL + DD + LL, | ||
| 156 | [0x57] = BDL + DL + DD, | ||
| 157 | [0x58] = BDL + DR + LU, | ||
| 158 | [0x59] = BDL + DU + LR, | ||
| 159 | [0x5a] = BDL + DU + DR, | ||
| 160 | [0x5b] = BDL + DL + LU, | ||
| 161 | [0x5c] = BDL + DU + LL, | ||
| 162 | [0x5d] = BDL + DL + DU, | ||
| 163 | [0x5e] = BDL + DR + LV, | ||
| 164 | [0x5f] = BDL + DV + LR, | ||
| 165 | [0x60] = BDL + DV + DR, | ||
| 166 | [0x61] = BDL + DL + LV, | ||
| 167 | [0x62] = BDL + DV + LL, | ||
| 168 | [0x63] = BDL + DV + DL, | ||
| 169 | [0x64] = BDL + DH + LD, | ||
| 170 | [0x65] = BDL + DD + LH, | ||
| 171 | [0x66] = BDL + DD + DH, | ||
| 172 | [0x67] = BDL + DH + LU, | ||
| 173 | [0x68] = BDL + DU + LH, | ||
| 174 | [0x69] = BDL + DH + DU, | ||
| 175 | [0x6a] = BDL + DH + LV, | ||
| 176 | [0x6b] = BDL + DV + LH, | ||
| 177 | [0x6c] = BDL + DH + DV, | ||
| 178 | |||
| 179 | /* (light) arcs */ | ||
| 180 | [0x6d] = BDA + LD + LR, | ||
| 181 | [0x6e] = BDA + LD + LL, | ||
| 182 | [0x6f] = BDA + LU + LL, | ||
| 183 | [0x70] = BDA + LU + LR, | ||
| 184 | |||
| 185 | /* Lower (Down) X/8 block (data is 8 - X) */ | ||
| 186 | [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4, | ||
| 187 | [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0, | ||
| 188 | |||
| 189 | /* Left X/8 block (data is X) */ | ||
| 190 | [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4, | ||
| 191 | [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1, | ||
| 192 | |||
| 193 | /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */ | ||
| 194 | [0x80] = BBU + 4, [0x94] = BBU + 1, | ||
| 195 | [0x90] = BBR + 4, [0x95] = BBR + 7, | ||
| 196 | |||
| 197 | /* Quadrants */ | ||
| 198 | [0x96] = BBQ + BL, | ||
| 199 | [0x97] = BBQ + BR, | ||
| 200 | [0x98] = BBQ + TL, | ||
| 201 | [0x99] = BBQ + TL + BL + BR, | ||
| 202 | [0x9a] = BBQ + TL + BR, | ||
| 203 | [0x9b] = BBQ + TL + TR + BL, | ||
| 204 | [0x9c] = BBQ + TL + TR + BR, | ||
| 205 | [0x9d] = BBQ + TR, | ||
| 206 | [0x9e] = BBQ + BL + TR, | ||
| 207 | [0x9f] = BBQ + BL + TR + BR, | ||
| 208 | |||
| 209 | /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */ | ||
| 210 | [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3, | ||
| 211 | |||
| 212 | /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */ | ||
| 213 | /* U+2571 - U+2573: unsupported (diagonals) */ | ||
| 214 | }; | ||
diff --git a/config.def.h b/config.def.h index c2f3756..685a9aa 100644 --- a/config.def.h +++ b/config.def.h | |||
| @@ -62,6 +62,18 @@ static unsigned int blinktimeout = 800; | |||
| 62 | static unsigned int cursorthickness = 2; | 62 | static unsigned int cursorthickness = 2; |
| 63 | 63 | ||
| 64 | /* | 64 | /* |
| 65 | * 1: render most of the lines/blocks characters without using the font for | ||
| 66 | * perfect alignment between cells (U2500 - U259F except dashes/diagonals). | ||
| 67 | * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. | ||
| 68 | * 0: disable (render all U25XX glyphs normally from the font). | ||
| 69 | */ | ||
| 70 | const int boxdraw = 1; | ||
| 71 | const int boxdraw_bold = 0; | ||
| 72 | |||
| 73 | /* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ | ||
| 74 | const int boxdraw_braille = 1; | ||
| 75 | |||
| 76 | /* | ||
| 65 | * bell volume. It must be a value between -100 and 100. Use 0 for disabling | 77 | * bell volume. It must be a value between -100 and 100. Use 0 for disabling |
| 66 | * it | 78 | * it |
| 67 | */ | 79 | */ |
| @@ -1285,6 +1285,9 @@ tsetchar(Rune u, Glyph *attr, int x, int y) | |||
| 1285 | term.dirty[y] = 1; | 1285 | term.dirty[y] = 1; |
| 1286 | term.line[y][x] = *attr; | 1286 | term.line[y][x] = *attr; |
| 1287 | term.line[y][x].u = u; | 1287 | term.line[y][x].u = u; |
| 1288 | |||
| 1289 | if (isboxdraw(u)) | ||
| 1290 | term.line[y][x].mode |= ATTR_BOXDRAW; | ||
| 1288 | } | 1291 | } |
| 1289 | 1292 | ||
| 1290 | void | 1293 | void |
| @@ -33,6 +33,7 @@ enum glyph_attribute { | |||
| 33 | ATTR_WRAP = 1 << 8, | 33 | ATTR_WRAP = 1 << 8, |
| 34 | ATTR_WIDE = 1 << 9, | 34 | ATTR_WIDE = 1 << 9, |
| 35 | ATTR_WDUMMY = 1 << 10, | 35 | ATTR_WDUMMY = 1 << 10, |
| 36 | ATTR_BOXDRAW = 1 << 11, | ||
| 36 | ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, | 37 | ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, |
| 37 | }; | 38 | }; |
| 38 | 39 | ||
| @@ -114,6 +115,14 @@ void *xmalloc(size_t); | |||
| 114 | void *xrealloc(void *, size_t); | 115 | void *xrealloc(void *, size_t); |
| 115 | char *xstrdup(char *); | 116 | char *xstrdup(char *); |
| 116 | 117 | ||
| 118 | int isboxdraw(Rune); | ||
| 119 | ushort boxdrawindex(const Glyph *); | ||
| 120 | #ifdef XFT_VERSION | ||
| 121 | /* only exposed to x.c, otherwise we'll need Xft.h for the types */ | ||
| 122 | void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *); | ||
| 123 | void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int); | ||
| 124 | #endif | ||
| 125 | |||
| 117 | /* config.h globals */ | 126 | /* config.h globals */ |
| 118 | extern char *utmp; | 127 | extern char *utmp; |
| 119 | extern char *stty_args; | 128 | extern char *stty_args; |
| @@ -124,3 +133,4 @@ extern char *termname; | |||
| 124 | extern unsigned int tabspaces; | 133 | extern unsigned int tabspaces; |
| 125 | extern unsigned int defaultfg; | 134 | extern unsigned int defaultfg; |
| 126 | extern unsigned int defaultbg; | 135 | extern unsigned int defaultbg; |
| 136 | extern const int boxdraw, boxdraw_bold, boxdraw_braille; | ||
| @@ -1294,6 +1294,8 @@ xinit(int cols, int rows) | |||
| 1294 | xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); | 1294 | xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); |
| 1295 | if (xsel.xtarget == None) | 1295 | if (xsel.xtarget == None) |
| 1296 | xsel.xtarget = XA_STRING; | 1296 | xsel.xtarget = XA_STRING; |
| 1297 | |||
| 1298 | boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); | ||
| 1297 | } | 1299 | } |
| 1298 | 1300 | ||
| 1299 | int | 1301 | int |
| @@ -1340,8 +1342,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x | |||
| 1340 | yp = winy + font->ascent; | 1342 | yp = winy + font->ascent; |
| 1341 | } | 1343 | } |
| 1342 | 1344 | ||
| 1343 | /* Lookup character index with default font. */ | 1345 | if (mode & ATTR_BOXDRAW) { |
| 1344 | glyphidx = XftCharIndex(xw.dpy, font->match, rune); | 1346 | /* minor shoehorning: boxdraw uses only this ushort */ |
| 1347 | glyphidx = boxdrawindex(&glyphs[i]); | ||
| 1348 | } else { | ||
| 1349 | /* Lookup character index with default font. */ | ||
| 1350 | glyphidx = XftCharIndex(xw.dpy, font->match, rune); | ||
| 1351 | } | ||
| 1345 | if (glyphidx) { | 1352 | if (glyphidx) { |
| 1346 | specs[numspecs].font = font->match; | 1353 | specs[numspecs].font = font->match; |
| 1347 | specs[numspecs].glyph = glyphidx; | 1354 | specs[numspecs].glyph = glyphidx; |
| @@ -1545,8 +1552,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i | |||
| 1545 | r.width = width; | 1552 | r.width = width; |
| 1546 | XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); | 1553 | XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); |
| 1547 | 1554 | ||
| 1548 | /* Render the glyphs. */ | 1555 | if (base.mode & ATTR_BOXDRAW) { |
| 1549 | XftDrawGlyphFontSpec(xw.draw, fg, specs, len); | 1556 | drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); |
| 1557 | } else { | ||
| 1558 | /* Render the glyphs. */ | ||
| 1559 | XftDrawGlyphFontSpec(xw.draw, fg, specs, len); | ||
| 1560 | } | ||
| 1550 | 1561 | ||
| 1551 | /* Render underline and strikethrough. */ | 1562 | /* Render underline and strikethrough. */ |
| 1552 | if (base.mode & ATTR_UNDERLINE) { | 1563 | if (base.mode & ATTR_UNDERLINE) { |
| @@ -1589,7 +1600,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) | |||
| 1589 | /* | 1600 | /* |
| 1590 | * Select the right color for the right mode. | 1601 | * Select the right color for the right mode. |
| 1591 | */ | 1602 | */ |
| 1592 | g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; | 1603 | g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW; |
| 1593 | 1604 | ||
| 1594 | if (IS_SET(MODE_REVERSE)) { | 1605 | if (IS_SET(MODE_REVERSE)) { |
| 1595 | g.mode |= ATTR_REVERSE; | 1606 | g.mode |= ATTR_REVERSE; |
