dotfiles

Configs for programs I use!
git clone git://shipwreckt.co.uk/dotfiles.git
Log | Files | Refs | README | LICENSE

boxdraw.c (5369B)


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