add type-to-select support
This commit is contained in:
parent
6bbc0e45ea
commit
b33886d7a2
91
xmenu.c
91
xmenu.c
|
@ -1140,20 +1140,61 @@ isclickbutton(unsigned int button)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* append buf into text */
|
||||
static int
|
||||
append(char *text, char *buf, size_t textsize, size_t buflen)
|
||||
{
|
||||
size_t textlen;
|
||||
|
||||
textlen = strlen(text);
|
||||
if (iscntrl(*buf))
|
||||
return 0;
|
||||
if (textlen + buflen > textsize - 1)
|
||||
return 0;
|
||||
if (buflen < 1)
|
||||
return 0;
|
||||
memcpy(text + textlen, buf, buflen);
|
||||
text[textlen + buflen] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* get item in menu matching text */
|
||||
static struct Item *
|
||||
matchitem(struct Menu *menu, char *text)
|
||||
{
|
||||
struct Item *item;
|
||||
char *s;
|
||||
size_t textlen;
|
||||
|
||||
textlen = strlen(text);
|
||||
for (item = menu->list; item; item = item->next)
|
||||
for (s = item->label; s && *s; s++)
|
||||
if (strncasecmp(s, text, textlen) == 0)
|
||||
return item;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* run event loop */
|
||||
static void
|
||||
run(struct Menu *currmenu)
|
||||
{
|
||||
char text[BUFSIZ];
|
||||
char buf[32];
|
||||
struct Menu *menu;
|
||||
struct Item *item;
|
||||
struct Item *previtem = NULL;
|
||||
struct Item *lastitem;
|
||||
struct Item *lastitem, *select;
|
||||
KeySym ksym;
|
||||
Status status;
|
||||
XEvent ev;
|
||||
int action;
|
||||
int len;
|
||||
|
||||
text[0] = '\0';
|
||||
mapmenu(currmenu);
|
||||
while (!XNextEvent(dpy, &ev)) {
|
||||
if (XFilterEvent(&ev, None))
|
||||
continue;
|
||||
action = ACTION_NOP;
|
||||
switch(ev.type) {
|
||||
case Expose:
|
||||
|
@ -1166,14 +1207,14 @@ run(struct Menu *currmenu)
|
|||
if (menu == NULL || item == NULL || previtem == item)
|
||||
break;
|
||||
previtem = item;
|
||||
menu->selected = item;
|
||||
select = menu->selected = item;
|
||||
if (item->submenu != NULL) {
|
||||
currmenu = item->submenu;
|
||||
currmenu->selected = NULL;
|
||||
select = NULL;
|
||||
} else {
|
||||
currmenu = menu;
|
||||
}
|
||||
action = ACTION_MAP | ACTION_DRAW;
|
||||
action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
|
||||
break;
|
||||
case ButtonRelease:
|
||||
if (!isclickbutton(ev.xbutton.button))
|
||||
|
@ -1182,7 +1223,7 @@ run(struct Menu *currmenu)
|
|||
item = getitem(menu, ev.xbutton.y);
|
||||
if (menu == NULL || item == NULL)
|
||||
break;
|
||||
selectitem:
|
||||
enteritem:
|
||||
if (item->label == NULL)
|
||||
break; /* ignore separators */
|
||||
if (item->submenu != NULL) {
|
||||
|
@ -1191,8 +1232,8 @@ selectitem:
|
|||
printf("%s\n", item->output);
|
||||
return;
|
||||
}
|
||||
currmenu->selected = currmenu->list;
|
||||
action = ACTION_MAP | ACTION_DRAW;
|
||||
select = currmenu->list;
|
||||
action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
|
||||
break;
|
||||
case ButtonPress:
|
||||
menu = getmenu(currmenu, ev.xbutton.window);
|
||||
|
@ -1200,7 +1241,16 @@ selectitem:
|
|||
return;
|
||||
break;
|
||||
case KeyPress:
|
||||
ksym = XkbKeycodeToKeysym(dpy, ev.xkey.keycode, 0, 0);
|
||||
len = XmbLookupString(currmenu->xic, &ev.xkey, buf, sizeof buf, &ksym, &status);
|
||||
switch(status) {
|
||||
default: /* XLookupNone, XBufferOverflow */
|
||||
continue;
|
||||
case XLookupChars:
|
||||
goto append;
|
||||
case XLookupKeySym: /* FALLTHROUGH */
|
||||
case XLookupBoth:
|
||||
break;
|
||||
}
|
||||
|
||||
/* esc closes xmenu when current menu is the root menu */
|
||||
if (ksym == XK_Escape && currmenu->parent == NULL)
|
||||
|
@ -1230,21 +1280,30 @@ selectitem:
|
|||
} else if ((ksym == XK_Return || ksym == XK_Right || ksym == KSYMRIGHT) &&
|
||||
currmenu->selected != NULL) {
|
||||
item = currmenu->selected;
|
||||
goto selectitem;
|
||||
goto enteritem;
|
||||
} else if ((ksym == XK_Escape || ksym == XK_Left || ksym == KSYMLEFT) &&
|
||||
currmenu->parent != NULL) {
|
||||
item = currmenu->parent->selected;
|
||||
currmenu = currmenu->parent;
|
||||
action = ACTION_MAP;
|
||||
} else
|
||||
} else {
|
||||
append:
|
||||
if (append(text, buf, sizeof text, len)) {
|
||||
currmenu->selected = matchitem(currmenu, text);
|
||||
action = ACTION_DRAW;
|
||||
} else {
|
||||
select = NULL;
|
||||
action = ACTION_SELECT | ACTION_DRAW;
|
||||
}
|
||||
break;
|
||||
currmenu->selected = item;
|
||||
action |= ACTION_DRAW;
|
||||
}
|
||||
select = item;
|
||||
action |= ACTION_SELECT | ACTION_DRAW;
|
||||
break;
|
||||
case LeaveNotify:
|
||||
previtem = NULL;
|
||||
currmenu->selected = NULL;
|
||||
action = ACTION_DRAW;
|
||||
select = NULL;
|
||||
action = ACTION_SELECT | ACTION_DRAW;
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
menu = getmenu(currmenu, ev.xconfigure.window);
|
||||
|
@ -1264,6 +1323,10 @@ selectitem:
|
|||
action = ACTION_MAP;
|
||||
break;
|
||||
}
|
||||
if (action & ACTION_SELECT) {
|
||||
currmenu->selected = select;
|
||||
text[0] = '\0';
|
||||
}
|
||||
if (action & ACTION_MAP)
|
||||
mapmenu(currmenu);
|
||||
if (action & ACTION_DRAW)
|
||||
|
|
5
xmenu.h
5
xmenu.h
|
@ -2,8 +2,9 @@
|
|||
|
||||
/* Actions for the main loop */
|
||||
#define ACTION_NOP 0
|
||||
#define ACTION_MAP 1<<0
|
||||
#define ACTION_DRAW 1<<1
|
||||
#define ACTION_SELECT 1<<0 /* select item and clear text */
|
||||
#define ACTION_MAP 1<<1 /* remap menu windows */
|
||||
#define ACTION_DRAW 1<<2 /* redraw menu windows */
|
||||
|
||||
/* enum for keyboard menu navigation */
|
||||
enum { ITEMPREV, ITEMNEXT, ITEMFIRST, ITEMLAST };
|
||||
|
|
Loading…
Reference in New Issue
Block a user