|
|
@ -251,12 +251,10 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int |
|
|
|
int |
|
|
|
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) |
|
|
|
{ |
|
|
|
char buf[1024]; |
|
|
|
int ty; |
|
|
|
unsigned int ew; |
|
|
|
int i, ty, ellipsis_x = 0; |
|
|
|
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len; |
|
|
|
XftDraw *d = NULL; |
|
|
|
Fnt *usedfont, *curfont, *nextfont; |
|
|
|
size_t i, len; |
|
|
|
int utf8strlen, utf8charlen, render = x || y || w || h; |
|
|
|
long utf8codepoint = 0; |
|
|
|
const char *utf8str; |
|
|
@ -264,13 +262,17 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp |
|
|
|
FcPattern *fcpattern; |
|
|
|
FcPattern *match; |
|
|
|
XftResult result; |
|
|
|
int charexists = 0; |
|
|
|
int charexists = 0, overflow = 0; |
|
|
|
/* keep track of a couple codepoints for which we have no match. */ |
|
|
|
enum { nomatches_len = 64 }; |
|
|
|
static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches; |
|
|
|
static unsigned int ellipsis_width = 0; |
|
|
|
|
|
|
|
if (!drw || (render && !drw->scheme) || !text || !drw->fonts) |
|
|
|
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) |
|
|
|
return 0; |
|
|
|
|
|
|
|
if (!render) { |
|
|
|
w = ~w; |
|
|
|
w = invert ? invert : ~invert; |
|
|
|
} else { |
|
|
|
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); |
|
|
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); |
|
|
@ -282,8 +284,10 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp |
|
|
|
} |
|
|
|
|
|
|
|
usedfont = drw->fonts; |
|
|
|
if (!ellipsis_width && render) |
|
|
|
ellipsis_width = drw_fontset_getwidth(drw, "..."); |
|
|
|
while (1) { |
|
|
|
utf8strlen = 0; |
|
|
|
ew = ellipsis_len = utf8strlen = 0; |
|
|
|
utf8str = text; |
|
|
|
nextfont = NULL; |
|
|
|
while (*text) { |
|
|
@ -291,9 +295,27 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp |
|
|
|
for (curfont = drw->fonts; curfont; curfont = curfont->next) { |
|
|
|
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); |
|
|
|
if (charexists) { |
|
|
|
if (curfont == usedfont) { |
|
|
|
drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL); |
|
|
|
if (ew + ellipsis_width <= w) { |
|
|
|
/* keep track where the ellipsis still fits */ |
|
|
|
ellipsis_x = x + ew; |
|
|
|
ellipsis_w = w - ew; |
|
|
|
ellipsis_len = utf8strlen; |
|
|
|
} |
|
|
|
|
|
|
|
if (ew + tmpw > w) { |
|
|
|
overflow = 1; |
|
|
|
/* called from drw_fontset_getwidth_clamp(): |
|
|
|
* it wants the width AFTER the overflow |
|
|
|
*/ |
|
|
|
if (!render) |
|
|
|
x += tmpw; |
|
|
|
else |
|
|
|
utf8strlen = ellipsis_len; |
|
|
|
} else if (curfont == usedfont) { |
|
|
|
utf8strlen += utf8charlen; |
|
|
|
text += utf8charlen; |
|
|
|
ew += tmpw; |
|
|
|
} else { |
|
|
|
nextfont = curfont; |
|
|
|
} |
|
|
@ -301,36 +323,25 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!charexists || nextfont) |
|
|
|
if (overflow || !charexists || nextfont) |
|
|
|
break; |
|
|
|
else |
|
|
|
charexists = 0; |
|
|
|
} |
|
|
|
|
|
|
|
if (utf8strlen) { |
|
|
|
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); |
|
|
|
/* shorten text if necessary */ |
|
|
|
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) |
|
|
|
drw_font_getexts(usedfont, utf8str, len, &ew, NULL); |
|
|
|
|
|
|
|
if (len) { |
|
|
|
memcpy(buf, utf8str, len); |
|
|
|
buf[len] = '\0'; |
|
|
|
if (len < utf8strlen) |
|
|
|
for (i = len; i && i > len - 3; buf[--i] = '.') |
|
|
|
; /* NOP */ |
|
|
|
|
|
|
|
if (render) { |
|
|
|
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; |
|
|
|
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], |
|
|
|
usedfont->xfont, x, ty, (XftChar8 *)buf, len); |
|
|
|
} |
|
|
|
x += ew; |
|
|
|
w -= ew; |
|
|
|
if (render) { |
|
|
|
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; |
|
|
|
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], |
|
|
|
usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen); |
|
|
|
} |
|
|
|
x += ew; |
|
|
|
w -= ew; |
|
|
|
} |
|
|
|
if (render && overflow) |
|
|
|
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); |
|
|
|
|
|
|
|
if (!*text) { |
|
|
|
if (!*text || overflow) { |
|
|
|
break; |
|
|
|
} else if (nextfont) { |
|
|
|
charexists = 0; |
|
|
@ -340,6 +351,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp |
|
|
|
* character must be drawn. */ |
|
|
|
charexists = 1; |
|
|
|
|
|
|
|
for (i = 0; i < nomatches_len; ++i) { |
|
|
|
/* avoid calling XftFontMatch if we know we won't find a match */ |
|
|
|
if (utf8codepoint == nomatches.codepoint[i]) |
|
|
|
goto no_match; |
|
|
|
} |
|
|
|
|
|
|
|
fccharset = FcCharSetCreate(); |
|
|
|
FcCharSetAddChar(fccharset, utf8codepoint); |
|
|
|
|
|
|
@ -368,6 +385,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp |
|
|
|
curfont->next = usedfont; |
|
|
|
} else { |
|
|
|
xfont_free(usedfont); |
|
|
|
nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; |
|
|
|
no_match: |
|
|
|
usedfont = drw->fonts; |
|
|
|
} |
|
|
|
} |
|
|
@ -397,6 +416,15 @@ drw_fontset_getwidth(Drw *drw, const char *text) |
|
|
|
return drw_text(drw, 0, 0, 0, 0, 0, text, 0); |
|
|
|
} |
|
|
|
|
|
|
|
unsigned int |
|
|
|
drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n) |
|
|
|
{ |
|
|
|
unsigned int tmp = 0; |
|
|
|
if (drw && drw->fonts && text && n) |
|
|
|
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n); |
|
|
|
return MIN(n, tmp); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) |
|
|
|
{ |
|
|
|