[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[E-devel] e_menu Keyboard Navigation using First Characters



The patch attached to adds keyboard navigation to the menu using the
first character of the menu label. It automatically executes anything
with a single entry in the menu and just activates those that have
multiple entries. If you don't like it's behaviour I can change it.

The patch is based on successful application of the patch from my
previous mail, as it's just too messy (it is a little bit already),
without accurate menu list item tracking.

One item that I'm not happy with, and I can't seem to see the issue is
that when hitting an item with a submenu and the submenu is activated,
the first item is not highlighted. I don't quite understand this as it's
using the same function as pressing the right arrow on the keyboard. It
can be a little bit confusing without the marker.

One REALLY useful feature of having menus like this is, say the Favorite
Applications menu is shown by Win+C. If Firefox is in the menu then
Win+C, F, will launch firefox.

Again, let me know what you think and if it needs mods, I'm happy to
make them.

metrics
--- e_menu.c.old	2006-09-27 12:48:58.000000000 +1000
+++ e_menu.c	2006-09-27 15:12:24.000000000 +1000
@@ -53,6 +53,7 @@
 static void _e_menu_item_activate_first           (void);
 static void _e_menu_item_activate_last            (void);
 static void _e_menu_item_activate_nth             (int n);
+static void _e_menu_item_activate_char            (char * key_compose);
 static void _e_menu_activate_next                 (void);
 static void _e_menu_activate_previous             (void);
 static void _e_menu_activate_first                (void);
@@ -2070,6 +2071,104 @@
 }
 
 static void
+_e_menu_item_activate_char(char * key_compose)
+{
+   E_Menu *m;
+   E_Menu_Item *mi;
+   Evas_List *ll, *ll_orig;
+   int match_count = 0;
+
+   /* Ignore modifiers and such. */
+   if (!key_compose) return;
+
+   /* Check we've got a menu and it's active. */
+   m = _e_menu_active_get();
+   if (!m) 
+     {
+	if (!_e_active_menus) return;
+	m = _e_active_menus->data;
+	if (!m) return;
+     }
+
+   /* Count the number of items that match */
+   ll = m->items;
+   while (ll) 
+     {
+	mi = ll->data;
+	if (!mi->separator && !strncasecmp(key_compose, mi->label, strlen(key_compose)))
+	  match_count++;
+	ll = ll->next;
+     }
+
+   if (!match_count) return;
+
+   ll = _e_menu_list_item_active_get();
+   /* If we don't have an active item, start from the top of the list. */
+   if (!ll)
+     {
+	ll = m->items;
+	mi = ll->data;
+	/* Only check the current item if it wasn't active before. */
+	if (!mi->separator && mi->label && !strncasecmp(key_compose, mi->label, strlen(key_compose))) 
+	  {
+	     e_menu_item_active_set(mi, 1);
+	     _e_menu_item_ensure_onscreen(mi);
+	     if (match_count <= 1)
+	       {
+		  if (mi->submenu) 
+		    _e_menu_activate_next();
+		  else
+		    {
+		       _e_menu_active_call();
+		       _e_menu_deactivate_all();
+		    }
+	       }
+	     return;
+	  }
+     }
+
+   mi = ll->data;
+   if (!(ll->next)) 
+     ll = mi->menu->items;
+   else
+     ll = ll->next;
+   mi = ll->data;
+
+   /* While we don't have a label OR we don't match */
+   while ((!mi->label || strncasecmp(key_compose, mi->label, strlen(key_compose))))
+     {
+	if (!(ll->next)) 
+	  ll = mi->menu->items;
+	else
+	  ll = ll->next;
+	mi = ll->data;
+
+	while (mi->separator)
+	  { 
+	     if (!(ll->next)) 
+	       ll = mi->menu->items;
+	     else
+	       ll = ll->next;
+	     mi = ll->data;
+	  }
+     }
+
+   e_menu_item_active_set(mi, 1);
+   _e_menu_item_ensure_onscreen(mi);
+   if (match_count <= 1)
+     {
+	if (mi->submenu) 
+	  _e_menu_activate_next();
+	else
+	  {
+	     _e_menu_active_call();
+	     _e_menu_deactivate_all();
+	  }
+     }
+   return;
+}
+
+static void
 _e_menu_activate_next(void)
 {
    E_Menu_Item *mi;
@@ -2531,6 +2630,8 @@
      _e_menu_item_activate_nth(8);
    else if ((!strcmp(ev->keysymbol, "0")) || (!strcmp(ev->keysymbol, "KP_0")))
      _e_menu_item_activate_last();
+   else if (ev->key_compose)
+     _e_menu_item_activate_char(ev->key_compose);
    return 1;
 }