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;
|
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 */
|
/* run event loop */
|
||||||
static void
|
static void
|
||||||
run(struct Menu *currmenu)
|
run(struct Menu *currmenu)
|
||||||
{
|
{
|
||||||
|
char text[BUFSIZ];
|
||||||
|
char buf[32];
|
||||||
struct Menu *menu;
|
struct Menu *menu;
|
||||||
struct Item *item;
|
struct Item *item;
|
||||||
struct Item *previtem = NULL;
|
struct Item *previtem = NULL;
|
||||||
struct Item *lastitem;
|
struct Item *lastitem, *select;
|
||||||
KeySym ksym;
|
KeySym ksym;
|
||||||
|
Status status;
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
int action;
|
int action;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
text[0] = '\0';
|
||||||
mapmenu(currmenu);
|
mapmenu(currmenu);
|
||||||
while (!XNextEvent(dpy, &ev)) {
|
while (!XNextEvent(dpy, &ev)) {
|
||||||
|
if (XFilterEvent(&ev, None))
|
||||||
|
continue;
|
||||||
action = ACTION_NOP;
|
action = ACTION_NOP;
|
||||||
switch(ev.type) {
|
switch(ev.type) {
|
||||||
case Expose:
|
case Expose:
|
||||||
|
@ -1166,14 +1207,14 @@ run(struct Menu *currmenu)
|
||||||
if (menu == NULL || item == NULL || previtem == item)
|
if (menu == NULL || item == NULL || previtem == item)
|
||||||
break;
|
break;
|
||||||
previtem = item;
|
previtem = item;
|
||||||
menu->selected = item;
|
select = menu->selected = item;
|
||||||
if (item->submenu != NULL) {
|
if (item->submenu != NULL) {
|
||||||
currmenu = item->submenu;
|
currmenu = item->submenu;
|
||||||
currmenu->selected = NULL;
|
select = NULL;
|
||||||
} else {
|
} else {
|
||||||
currmenu = menu;
|
currmenu = menu;
|
||||||
}
|
}
|
||||||
action = ACTION_MAP | ACTION_DRAW;
|
action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
|
||||||
break;
|
break;
|
||||||
case ButtonRelease:
|
case ButtonRelease:
|
||||||
if (!isclickbutton(ev.xbutton.button))
|
if (!isclickbutton(ev.xbutton.button))
|
||||||
|
@ -1182,7 +1223,7 @@ run(struct Menu *currmenu)
|
||||||
item = getitem(menu, ev.xbutton.y);
|
item = getitem(menu, ev.xbutton.y);
|
||||||
if (menu == NULL || item == NULL)
|
if (menu == NULL || item == NULL)
|
||||||
break;
|
break;
|
||||||
selectitem:
|
enteritem:
|
||||||
if (item->label == NULL)
|
if (item->label == NULL)
|
||||||
break; /* ignore separators */
|
break; /* ignore separators */
|
||||||
if (item->submenu != NULL) {
|
if (item->submenu != NULL) {
|
||||||
|
@ -1191,8 +1232,8 @@ selectitem:
|
||||||
printf("%s\n", item->output);
|
printf("%s\n", item->output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currmenu->selected = currmenu->list;
|
select = currmenu->list;
|
||||||
action = ACTION_MAP | ACTION_DRAW;
|
action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
|
||||||
break;
|
break;
|
||||||
case ButtonPress:
|
case ButtonPress:
|
||||||
menu = getmenu(currmenu, ev.xbutton.window);
|
menu = getmenu(currmenu, ev.xbutton.window);
|
||||||
|
@ -1200,7 +1241,16 @@ selectitem:
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
case KeyPress:
|
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 */
|
/* esc closes xmenu when current menu is the root menu */
|
||||||
if (ksym == XK_Escape && currmenu->parent == NULL)
|
if (ksym == XK_Escape && currmenu->parent == NULL)
|
||||||
|
@ -1230,21 +1280,30 @@ selectitem:
|
||||||
} else if ((ksym == XK_Return || ksym == XK_Right || ksym == KSYMRIGHT) &&
|
} else if ((ksym == XK_Return || ksym == XK_Right || ksym == KSYMRIGHT) &&
|
||||||
currmenu->selected != NULL) {
|
currmenu->selected != NULL) {
|
||||||
item = currmenu->selected;
|
item = currmenu->selected;
|
||||||
goto selectitem;
|
goto enteritem;
|
||||||
} else if ((ksym == XK_Escape || ksym == XK_Left || ksym == KSYMLEFT) &&
|
} else if ((ksym == XK_Escape || ksym == XK_Left || ksym == KSYMLEFT) &&
|
||||||
currmenu->parent != NULL) {
|
currmenu->parent != NULL) {
|
||||||
item = currmenu->parent->selected;
|
item = currmenu->parent->selected;
|
||||||
currmenu = currmenu->parent;
|
currmenu = currmenu->parent;
|
||||||
action = ACTION_MAP;
|
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;
|
break;
|
||||||
currmenu->selected = item;
|
}
|
||||||
action |= ACTION_DRAW;
|
select = item;
|
||||||
|
action |= ACTION_SELECT | ACTION_DRAW;
|
||||||
break;
|
break;
|
||||||
case LeaveNotify:
|
case LeaveNotify:
|
||||||
previtem = NULL;
|
previtem = NULL;
|
||||||
currmenu->selected = NULL;
|
select = NULL;
|
||||||
action = ACTION_DRAW;
|
action = ACTION_SELECT | ACTION_DRAW;
|
||||||
break;
|
break;
|
||||||
case ConfigureNotify:
|
case ConfigureNotify:
|
||||||
menu = getmenu(currmenu, ev.xconfigure.window);
|
menu = getmenu(currmenu, ev.xconfigure.window);
|
||||||
|
@ -1264,6 +1323,10 @@ selectitem:
|
||||||
action = ACTION_MAP;
|
action = ACTION_MAP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (action & ACTION_SELECT) {
|
||||||
|
currmenu->selected = select;
|
||||||
|
text[0] = '\0';
|
||||||
|
}
|
||||||
if (action & ACTION_MAP)
|
if (action & ACTION_MAP)
|
||||||
mapmenu(currmenu);
|
mapmenu(currmenu);
|
||||||
if (action & ACTION_DRAW)
|
if (action & ACTION_DRAW)
|
||||||
|
|
5
xmenu.h
5
xmenu.h
|
@ -2,8 +2,9 @@
|
||||||
|
|
||||||
/* Actions for the main loop */
|
/* Actions for the main loop */
|
||||||
#define ACTION_NOP 0
|
#define ACTION_NOP 0
|
||||||
#define ACTION_MAP 1<<0
|
#define ACTION_SELECT 1<<0 /* select item and clear text */
|
||||||
#define ACTION_DRAW 1<<1
|
#define ACTION_MAP 1<<1 /* remap menu windows */
|
||||||
|
#define ACTION_DRAW 1<<2 /* redraw menu windows */
|
||||||
|
|
||||||
/* enum for keyboard menu navigation */
|
/* enum for keyboard menu navigation */
|
||||||
enum { ITEMPREV, ITEMNEXT, ITEMFIRST, ITEMLAST };
|
enum { ITEMPREV, ITEMNEXT, ITEMFIRST, ITEMLAST };
|
||||||
|
|
Loading…
Reference in New Issue
Block a user