make tab cycle through matched items
authorphillbush <phillbush@cock.li>
Thu, 31 Dec 2020 07:58:05 +0000 (04:58 -0300)
committerphillbush <phillbush@cock.li>
Thu, 31 Dec 2020 07:58:05 +0000 (04:58 -0300)
xmenu.c
xmenu.h

diff --git a/xmenu.c b/xmenu.c
index f597aeb..61e154c 100644 (file)
--- a/xmenu.c
+++ b/xmenu.c
@@ -1158,19 +1158,53 @@ append(char *text, char *buf, size_t textsize, size_t buflen)
        return 1;
 }
 
        return 1;
 }
 
-/* get item in menu matching text */
+/* get item in menu matching text from given direction (or from beginning, if dir = 0) */
 static struct Item *
 static struct Item *
-matchitem(struct Menu *menu, char *text)
+matchitem(struct Menu *menu, char *text, int dir)
 {
 {
-       struct Item *item;
+       struct Item *item, *lastitem;
        char *s;
        size_t textlen;
 
        char *s;
        size_t textlen;
 
+       for (lastitem = menu->list; lastitem && lastitem->next; lastitem = lastitem->next)
+               ;
        textlen = strlen(text);
        textlen = strlen(text);
-       for (item = menu->list; item; item = item->next)
+       if (dir < 0) {
+               if (menu->selected && menu->selected->prev)
+                       item = menu->selected->prev;
+               else
+                       item = lastitem;
+       } else if (dir > 0) {
+               if (menu->selected && menu->selected->next)
+                       item = menu->selected->next;
+               else
+                       item = menu->list;
+       } else {
+               item = menu->list;
+       }
+       /* find next item from selected item */
+       for ( ; item; item = (dir < 0) ? item->prev : item->next)
                for (s = item->label; s && *s; s++)
                        if (strncasecmp(s, text, textlen) == 0)
                                return item;
                for (s = item->label; s && *s; s++)
                        if (strncasecmp(s, text, textlen) == 0)
                                return item;
+       /* if not found, try to find from the beginning/end of list */
+       if (dir > 0) {
+               for (item = menu->list ; item; item = item->next) {
+                       for (s = item->label; s && *s; s++) {
+                               if (strncasecmp(s, text, textlen) == 0) {
+                                       return item;
+                               }
+                       }
+               }
+       } else {
+               for (item = lastitem ; item; item = item->prev) {
+                       for (s = item->label; s && *s; s++) {
+                               if (strncasecmp(s, text, textlen) == 0) {
+                                       return item;
+                               }
+                       }
+               }
+       }
        return NULL;
 }
 
        return NULL;
 }
 
@@ -1214,7 +1248,7 @@ run(struct Menu *currmenu)
                        } else {
                                currmenu = menu;
                        }
                        } else {
                                currmenu = menu;
                        }
-                       action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
+                       action = ACTION_CLEAR | ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
                        break;
                case ButtonRelease:
                        if (!isclickbutton(ev.xbutton.button))
                        break;
                case ButtonRelease:
                        if (!isclickbutton(ev.xbutton.button))
@@ -1233,7 +1267,7 @@ enteritem:
                                return;
                        }
                        select = currmenu->list;
                                return;
                        }
                        select = currmenu->list;
-                       action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
+                       action = ACTION_CLEAR | ACTION_SELECT | ACTION_MAP | ACTION_DRAW;
                        break;
                case ButtonPress:
                        menu = getmenu(currmenu, ev.xbutton.window);
                        break;
                case ButtonPress:
                        menu = getmenu(currmenu, ev.xbutton.window);
@@ -1264,12 +1298,24 @@ enteritem:
                        item = NULL;
                        if (ksym == XK_Home || ksym == KSYMFIRST) {
                                item = itemcycle(currmenu, ITEMFIRST);
                        item = NULL;
                        if (ksym == XK_Home || ksym == KSYMFIRST) {
                                item = itemcycle(currmenu, ITEMFIRST);
+                               action = ACTION_CLEAR;
                        } else if (ksym == XK_End || ksym == KSYMLAST) {
                                item = itemcycle(currmenu, ITEMLAST);
                        } else if (ksym == XK_End || ksym == KSYMLAST) {
                                item = itemcycle(currmenu, ITEMLAST);
+                               action = ACTION_CLEAR;
                        } else if (ksym == XK_ISO_Left_Tab || ksym == XK_Up || ksym == KSYMUP) {
                        } else if (ksym == XK_ISO_Left_Tab || ksym == XK_Up || ksym == KSYMUP) {
-                               item = itemcycle(currmenu, ITEMPREV);
+                               if (*text) {
+                                       item = matchitem(currmenu, text, -1);
+                               } else {
+                                       item = itemcycle(currmenu, ITEMPREV);
+                                       action = ACTION_CLEAR;
+                               }
                        } else if (ksym == XK_Tab || ksym == XK_Down || ksym == KSYMDOWN) {
                        } else if (ksym == XK_Tab || ksym == XK_Down || ksym == KSYMDOWN) {
-                               item = itemcycle(currmenu, ITEMNEXT);
+                               if (*text) {
+                                       item = matchitem(currmenu, text, 1);
+                               } else {
+                                       item = itemcycle(currmenu, ITEMNEXT);
+                                       action = ACTION_CLEAR;
+                               }
                        } else if (ksym >= XK_1 && ksym <= XK_9){
                                item = itemcycle(currmenu, ITEMFIRST);
                                lastitem = itemcycle(currmenu, ITEMLAST);
                        } else if (ksym >= XK_1 && ksym <= XK_9){
                                item = itemcycle(currmenu, ITEMFIRST);
                                lastitem = itemcycle(currmenu, ITEMLAST);
@@ -1277,6 +1323,7 @@ enteritem:
                                        currmenu->selected = item;
                                        item = itemcycle(currmenu, ITEMNEXT);
                                }
                                        currmenu->selected = item;
                                        item = itemcycle(currmenu, ITEMNEXT);
                                }
+                               action = ACTION_CLEAR;
                        } else if ((ksym == XK_Return || ksym == XK_Right || ksym == KSYMRIGHT) &&
                                    currmenu->selected != NULL) {
                                item = currmenu->selected;
                        } else if ((ksym == XK_Return || ksym == XK_Right || ksym == KSYMRIGHT) &&
                                    currmenu->selected != NULL) {
                                item = currmenu->selected;
@@ -1285,18 +1332,19 @@ enteritem:
                                   currmenu->parent != NULL) {
                                item = currmenu->parent->selected;
                                currmenu = currmenu->parent;
                                   currmenu->parent != NULL) {
                                item = currmenu->parent->selected;
                                currmenu = currmenu->parent;
-                               action = ACTION_MAP;
+                               action = ACTION_CLEAR | ACTION_MAP;
+                       } else if (ksym == XK_BackSpace || ksym == XK_Clear || ksym == XK_Delete) {
+                               action = ACTION_CLEAR;
+                               break;
                        } else {
 append:
                                if (append(text, buf, sizeof text, len)) {
                        } else {
 append:
                                if (append(text, buf, sizeof text, len)) {
-                                       if ((currmenu->selected = matchitem(currmenu, text))) {
-                                               action = ACTION_DRAW;
-                                               break;
+                                       if (!(item = matchitem(currmenu, text, 0))) {
+                                               item = NULL;
                                        }
                                        }
+                               } else if (len == 0) {
+                                       break; /* we may have pressed a dead key */
                                }
                                }
-                               select = NULL;
-                               action = ACTION_SELECT | ACTION_DRAW;
-                               break;
                        }
                        select = item;
                        action |= ACTION_SELECT | ACTION_DRAW;
                        }
                        select = item;
                        action |= ACTION_SELECT | ACTION_DRAW;
@@ -1304,7 +1352,7 @@ append:
                case LeaveNotify:
                        previtem = NULL;
                        select = NULL;
                case LeaveNotify:
                        previtem = NULL;
                        select = NULL;
-                       action = ACTION_SELECT | ACTION_DRAW;
+                       action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW;
                        break;
                case ConfigureNotify:
                        menu = getmenu(currmenu, ev.xconfigure.window);
                        break;
                case ConfigureNotify:
                        menu = getmenu(currmenu, ev.xconfigure.window);
@@ -1324,10 +1372,10 @@ append:
                        action = ACTION_MAP;
                        break;
                }
                        action = ACTION_MAP;
                        break;
                }
-               if (action & ACTION_SELECT) {
-                       currmenu->selected = select;
+               if (action & ACTION_CLEAR)
                        text[0] = '\0';
                        text[0] = '\0';
-               }
+               if (action & ACTION_SELECT)
+                       currmenu->selected = select;
                if (action & ACTION_MAP)
                        mapmenu(currmenu);
                if (action & ACTION_DRAW)
                if (action & ACTION_MAP)
                        mapmenu(currmenu);
                if (action & ACTION_DRAW)
diff --git a/xmenu.h b/xmenu.h
index bccc39e..b5f1556 100644 (file)
--- a/xmenu.h
+++ b/xmenu.h
@@ -2,9 +2,10 @@
 
 /* Actions for the main loop */
 #define ACTION_NOP    0
 
 /* Actions for the main loop */
 #define ACTION_NOP    0
-#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 */
+#define ACTION_CLEAR  1<<0      /* clear text */
+#define ACTION_SELECT 1<<1      /* select item */
+#define ACTION_MAP    1<<2      /* remap menu windows */
+#define ACTION_DRAW   1<<3      /* redraw menu windows */
 
 /* enum for keyboard menu navigation */
 enum { ITEMPREV, ITEMNEXT, ITEMFIRST, ITEMLAST };
 
 /* enum for keyboard menu navigation */
 enum { ITEMPREV, ITEMNEXT, ITEMFIRST, ITEMLAST };