st-noxz

[fork] suckless st - personal fork
git clone https://noxz.tech/git/st-noxz.git
Log | Files | README | LICENSE

boxdraw.c
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
13static Display *xdpy;
14static Colormap xcmap;
15static XftDraw *xd;
16static Visual *xvis;
17
18static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
19static void drawboxlines(int, int, int, int, XftColor *, ushort);
20
21/* public API */
22
23void
24boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
25{
26	xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
27}
28
29int
30isboxdraw(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 */
38ushort
39boxdrawindex(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
48void
49drawboxes(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
58void
59drawbox(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
127void
128drawboxlines(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}