246 lines
6.9 KiB
Diff
246 lines
6.9 KiB
Diff
|
diff --git a/dmenu.c b/dmenu.c
|
||
|
index 5c835dd..71efe52 100644
|
||
|
--- a/dmenu.c
|
||
|
+++ b/dmenu.c
|
||
|
@@ -131,9 +131,10 @@ drawitem(struct item *item, int x, int y, int w)
|
||
|
static void
|
||
|
drawmenu(void)
|
||
|
{
|
||
|
- unsigned int curpos;
|
||
|
+ static int curpos, oldcurlen;
|
||
|
struct item *item;
|
||
|
int x = 0, y = 0, w;
|
||
|
+ int curlen, rcurlen;
|
||
|
|
||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||
|
drw_rect(drw, 0, 0, mw, mh, 1, 1);
|
||
|
@@ -144,14 +145,21 @@ drawmenu(void)
|
||
|
}
|
||
|
/* draw input field */
|
||
|
w = (lines > 0 || !matches) ? mw - x : inputw;
|
||
|
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||
|
- drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
|
||
|
+ w -= lrpad / 2;
|
||
|
+ x += lrpad / 2;
|
||
|
|
||
|
- curpos = TEXTW(text) - TEXTW(&text[cursor]);
|
||
|
- if ((curpos += lrpad / 2 - 1) < w) {
|
||
|
- drw_setscheme(drw, scheme[SchemeNorm]);
|
||
|
- drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
|
||
|
- }
|
||
|
+ rcurlen = drw_fontset_getwidth(drw, text + cursor);
|
||
|
+ curlen = drw_fontset_getwidth(drw, text) - rcurlen;
|
||
|
+ curpos += curlen - oldcurlen;
|
||
|
+ curpos = MIN(w, MAX(0, curpos));
|
||
|
+ curpos = MAX(curpos, w - rcurlen);
|
||
|
+ curpos = MIN(curpos, curlen);
|
||
|
+ oldcurlen = curlen;
|
||
|
+
|
||
|
+ drw_setscheme(drw, scheme[SchemeNorm]);
|
||
|
+ drw_text_align(drw, x, 0, curpos, bh, text, cursor, AlignR);
|
||
|
+ drw_text_align(drw, x + curpos, 0, w - curpos, bh, text + cursor, strlen(text) - cursor, AlignL);
|
||
|
+ drw_rect(drw, x + curpos - 1, 2, 2, bh - 4, 1, 0);
|
||
|
|
||
|
if (lines > 0) {
|
||
|
/* draw vertical list */
|
||
|
diff --git a/drw.c b/drw.c
|
||
|
index c638323..bfffbc1 100644
|
||
|
--- a/drw.c
|
||
|
+++ b/drw.c
|
||
|
@@ -364,6 +364,175 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||
|
return x + (render ? w : 0);
|
||
|
}
|
||
|
|
||
|
+int
|
||
|
+utf8nextchar(const char *str, int len, int i, int inc)
|
||
|
+{
|
||
|
+ int n;
|
||
|
+
|
||
|
+ for (n = i + inc; n + inc >= 0 && n + inc <= len
|
||
|
+ && (str[n] & 0xc0) == 0x80; n += inc)
|
||
|
+ ;
|
||
|
+ return n;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align)
|
||
|
+{
|
||
|
+ int ty;
|
||
|
+ unsigned int ew;
|
||
|
+ XftDraw *d = NULL;
|
||
|
+ Fnt *usedfont, *curfont, *nextfont;
|
||
|
+ size_t len;
|
||
|
+ int utf8strlen, utf8charlen, render = x || y || w || h;
|
||
|
+ long utf8codepoint = 0;
|
||
|
+ const char *utf8str;
|
||
|
+ FcCharSet *fccharset;
|
||
|
+ FcPattern *fcpattern;
|
||
|
+ FcPattern *match;
|
||
|
+ XftResult result;
|
||
|
+ int charexists = 0;
|
||
|
+ int i, n;
|
||
|
+
|
||
|
+ if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0
|
||
|
+ || (align != AlignL && align != AlignR))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (!render) {
|
||
|
+ w = ~w;
|
||
|
+ } else {
|
||
|
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
|
||
|
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||
|
+ d = XftDrawCreate(drw->dpy, drw->drawable,
|
||
|
+ DefaultVisual(drw->dpy, drw->screen),
|
||
|
+ DefaultColormap(drw->dpy, drw->screen));
|
||
|
+ }
|
||
|
+
|
||
|
+ usedfont = drw->fonts;
|
||
|
+ i = align == AlignL ? 0 : textlen;
|
||
|
+ x = align == AlignL ? x : x + w;
|
||
|
+ while (1) {
|
||
|
+ utf8strlen = 0;
|
||
|
+ nextfont = NULL;
|
||
|
+ /* if (align == AlignL) */
|
||
|
+ utf8str = text + i;
|
||
|
+
|
||
|
+ while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) {
|
||
|
+ if (align == AlignL) {
|
||
|
+ utf8charlen = utf8decode(text + i, &utf8codepoint, MIN(textlen - i, UTF_SIZ));
|
||
|
+ if (!utf8charlen) {
|
||
|
+ textlen = i;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ n = utf8nextchar(text, textlen, i, -1);
|
||
|
+ utf8charlen = utf8decode(text + n, &utf8codepoint, MIN(textlen - n, UTF_SIZ));
|
||
|
+ if (!utf8charlen) {
|
||
|
+ textlen -= i;
|
||
|
+ text += i;
|
||
|
+ i = 0;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||
|
+ charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||
|
+ if (charexists) {
|
||
|
+ if (curfont == usedfont) {
|
||
|
+ utf8strlen += utf8charlen;
|
||
|
+ i += align == AlignL ? utf8charlen : -utf8charlen;
|
||
|
+ } else {
|
||
|
+ nextfont = curfont;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!charexists || nextfont)
|
||
|
+ break;
|
||
|
+ else
|
||
|
+ charexists = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (align == AlignR)
|
||
|
+ utf8str = text + i;
|
||
|
+
|
||
|
+ if (utf8strlen) {
|
||
|
+ drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
|
||
|
+ /* shorten text if necessary */
|
||
|
+ if (align == AlignL) {
|
||
|
+ for (len = utf8strlen; len && ew > w; ) {
|
||
|
+ len = utf8nextchar(utf8str, len, len, -1);
|
||
|
+ drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ for (len = utf8strlen; len && ew > w; ) {
|
||
|
+ n = utf8nextchar(utf8str, len, 0, +1);
|
||
|
+ utf8str += n;
|
||
|
+ len -= n;
|
||
|
+ drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (len) {
|
||
|
+ if (render) {
|
||
|
+ ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||
|
+ XftDrawStringUtf8(d, &drw->scheme[ColFg],
|
||
|
+ usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len);
|
||
|
+ }
|
||
|
+ x += align == AlignL ? ew : -ew;
|
||
|
+ w -= ew;
|
||
|
+ }
|
||
|
+ if (len < utf8strlen)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) {
|
||
|
+ break;
|
||
|
+ } else if (nextfont) {
|
||
|
+ charexists = 0;
|
||
|
+ usedfont = nextfont;
|
||
|
+ } else {
|
||
|
+ /* Regardless of whether or not a fallback font is found, the
|
||
|
+ * character must be drawn. */
|
||
|
+ charexists = 1;
|
||
|
+
|
||
|
+ fccharset = FcCharSetCreate();
|
||
|
+ FcCharSetAddChar(fccharset, utf8codepoint);
|
||
|
+
|
||
|
+ if (!drw->fonts->pattern) {
|
||
|
+ /* Refer to the comment in xfont_create for more information. */
|
||
|
+ die("the first font in the cache must be loaded from a font string.");
|
||
|
+ }
|
||
|
+
|
||
|
+ fcpattern = FcPatternDuplicate(drw->fonts->pattern);
|
||
|
+ FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||
|
+ FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
|
||
|
+
|
||
|
+ FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
|
||
|
+ FcDefaultSubstitute(fcpattern);
|
||
|
+ match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
|
||
|
+
|
||
|
+ FcCharSetDestroy(fccharset);
|
||
|
+ FcPatternDestroy(fcpattern);
|
||
|
+
|
||
|
+ if (match) {
|
||
|
+ usedfont = xfont_create(drw, NULL, match);
|
||
|
+ if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
|
||
|
+ for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
|
||
|
+ ; /* NOP */
|
||
|
+ curfont->next = usedfont;
|
||
|
+ } else {
|
||
|
+ xfont_free(usedfont);
|
||
|
+ usedfont = drw->fonts;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (d)
|
||
|
+ XftDrawDestroy(d);
|
||
|
+
|
||
|
+ return x;
|
||
|
+}
|
||
|
+
|
||
|
void
|
||
|
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
||
|
{
|
||
|
diff --git a/drw.h b/drw.h
|
||
|
index 4c67419..b66a83e 100644
|
||
|
--- a/drw.h
|
||
|
+++ b/drw.h
|
||
|
@@ -13,6 +13,7 @@ typedef struct Fnt {
|
||
|
} Fnt;
|
||
|
|
||
|
enum { ColFg, ColBg }; /* Clr scheme index */
|
||
|
+enum { AlignL, AlignR };
|
||
|
typedef XftColor Clr;
|
||
|
|
||
|
typedef struct {
|
||
|
@@ -52,6 +53,7 @@ void drw_setscheme(Drw *drw, Clr *scm);
|
||
|
/* Drawing functions */
|
||
|
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
|
||
|
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
|
||
|
+int drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align);
|
||
|
|
||
|
/* Map functions */
|
||
|
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
|