Merge branch '212_menu_keybind'

* 212_menu_keybind:
  Menubar: support Home and End actions for Menubar.
  Menu: implement drop/execute menu by hotkey.
  Ticket #212: implement keybinding for menu.
This commit is contained in:
Andrew Borodin 2019-06-09 12:07:01 +03:00
commit 934a2d9314
7 changed files with 195 additions and 126 deletions

View File

@ -13,6 +13,7 @@
#define KEYMAP_SECTION_MAIN_EXT "main:xmap"
#define KEYMAP_SECTION_PANEL "panel"
#define KEYMAP_SECTION_DIALOG "dialog"
#define KEYMAP_SECTION_MENU "menu"
#define KEYMAP_SECTION_INPUT "input"
#define KEYMAP_SECTION_LISTBOX "listbox"
#define KEYMAP_SECTION_TREE "tree"

View File

@ -39,12 +39,15 @@
#include "lib/tty/tty.h"
#include "lib/skin.h"
#include "lib/tty/key.h" /* key macros */
#include "lib/keybind.h" /* global_keymap_t */
#include "lib/strutil.h"
#include "lib/widget.h"
#include "lib/event.h" /* mc_event_raise() */
/*** global variables ****************************************************************************/
const global_keymap_t *menu_map;
/*** file scope macro definitions ****************************************************************/
#define MENUENTRY(x) ((menu_entry_t *)(x))
@ -397,28 +400,36 @@ menubar_up (WMenuBar * menubar)
static void
menubar_first (WMenuBar * menubar)
{
menu_t *menu = MENU (g_list_nth_data (menubar->menu, menubar->selected));
if (menu->selected == 0)
return;
menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
menu->selected = 0;
while (TRUE)
if (menubar->is_dropped)
{
menu_entry_t *entry;
menu_t *menu = MENU (g_list_nth_data (menubar->menu, menubar->selected));
entry = MENUENTRY (g_list_nth_data (menu->entries, menu->selected));
if (menu->selected == 0)
return;
if ((entry == NULL) || (entry->command == CK_IgnoreKey))
menu->selected++;
else
break;
menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
menu->selected = 0;
while (TRUE)
{
menu_entry_t *entry;
entry = MENUENTRY (g_list_nth_data (menu->entries, menu->selected));
if ((entry == NULL) || (entry->command == CK_IgnoreKey))
menu->selected++;
else
break;
}
menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
}
else
{
menubar->selected = 0;
menubar_draw (menubar);
}
menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
}
/* --------------------------------------------------------------------------------------------- */
@ -426,46 +437,92 @@ menubar_first (WMenuBar * menubar)
static void
menubar_last (WMenuBar * menubar)
{
menu_t *menu = MENU (g_list_nth_data (menubar->menu, menubar->selected));
const unsigned int len = g_list_length (menu->entries);
menu_entry_t *entry;
if (menu->selected == len - 1)
return;
menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
menu->selected = len;
do
if (menubar->is_dropped)
{
menu->selected--;
entry = MENUENTRY (g_list_nth_data (menu->entries, menu->selected));
}
while ((entry == NULL) || (entry->command == CK_IgnoreKey));
menu_t *menu = MENU (g_list_nth_data (menubar->menu, menubar->selected));
const unsigned int len = g_list_length (menu->entries);
menu_entry_t *entry;
menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
if (menu->selected == len - 1)
return;
menubar_paint_idx (menubar, menu->selected, MENU_ENTRY_COLOR);
menu->selected = len;
do
{
menu->selected--;
entry = MENUENTRY (g_list_nth_data (menu->entries, menu->selected));
}
while ((entry == NULL) || (entry->command == CK_IgnoreKey));
menubar_paint_idx (menubar, menu->selected, MENU_SELECTED_COLOR);
}
else
{
menubar->selected = g_list_length (menubar->menu) - 1;
menubar_draw (menubar);
}
}
/* --------------------------------------------------------------------------------------------- */
static int
menubar_handle_key (WMenuBar * menubar, int key)
static cb_ret_t
menubar_try_drop_menu (WMenuBar * menubar, int hotkey)
{
/* Lowercase */
if (isascii (key))
key = g_ascii_tolower (key);
GList *i;
if (is_abort_char (key))
for (i = menubar->menu; i != NULL; i = g_list_next (i))
{
menubar_finish (menubar);
return 1;
menu_t *menu = MENU (i->data);
if (menu->text.hotkey != NULL && hotkey == g_ascii_tolower (menu->text.hotkey[0]))
{
menubar_drop (menubar, g_list_position (menubar->menu, i));
return MSG_HANDLED;
}
}
/* menubar help or menubar navigation */
switch (key)
return MSG_NOT_HANDLED;
}
/* --------------------------------------------------------------------------------------------- */
static cb_ret_t
menubar_try_exec_menu (WMenuBar * menubar, int hotkey)
{
menu_t *menu;
GList *i;
menu = g_list_nth_data (menubar->menu, menubar->selected);
for (i = menu->entries; i != NULL; i = g_list_next (i))
{
case KEY_F (1):
const menu_entry_t *entry = MENUENTRY (i->data);
if (entry != NULL && entry->text.hotkey != NULL
&& hotkey == g_ascii_tolower (entry->text.hotkey[0]))
{
menu->selected = g_list_position (menu->entries, i);
menubar_execute (menubar);
return MSG_HANDLED;
}
}
return MSG_NOT_HANDLED;
}
/* --------------------------------------------------------------------------------------------- */
static cb_ret_t
menubar_execute_cmd (WMenuBar * menubar, unsigned long command, int key)
{
cb_ret_t ret = MSG_HANDLED;
switch (command)
{
case CK_Help:
{
ev_help_t event_data = { NULL, NULL };
@ -477,98 +534,65 @@ menubar_handle_key (WMenuBar * menubar, int key)
mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
menubar_draw (menubar);
return 1;
}
break;
case KEY_LEFT:
case XCTRL ('b'):
case CK_Left:
menubar_left (menubar);
return 1;
case KEY_RIGHT:
case XCTRL ('f'):
break;
case CK_Right:
menubar_right (menubar);
return 1;
break;
case CK_Up:
if (menubar->is_dropped)
menubar_up (menubar);
break;
case CK_Down:
if (menubar->is_dropped)
menubar_down (menubar);
else
menubar_drop (menubar, menubar->selected);
break;
case CK_Home:
menubar_first (menubar);
break;
case CK_End:
menubar_last (menubar);
break;
case CK_Enter:
if (menubar->is_dropped)
menubar_execute (menubar);
else
menubar_drop (menubar, menubar->selected);
break;
case CK_Quit:
menubar_finish (menubar);
break;
default:
if (menubar->is_dropped)
ret = menubar_try_exec_menu (menubar, key);
else
ret = menubar_try_drop_menu (menubar, key);
break;
}
if (!menubar->is_dropped)
{
GList *i;
return ret;
}
/* drop menu by hotkey */
for (i = menubar->menu; i != NULL; i = g_list_next (i))
{
menu_t *menu = MENU (i->data);
/* --------------------------------------------------------------------------------------------- */
if ((menu->text.hotkey != NULL) && (key == g_ascii_tolower (menu->text.hotkey[0])))
{
menubar_drop (menubar, g_list_position (menubar->menu, i));
return 1;
}
}
static int
menubar_handle_key (WMenuBar * menubar, int key)
{
unsigned long cmd;
/* drop menu by Enter or Dowwn key */
if (key == KEY_ENTER || key == XCTRL ('n') || key == KEY_DOWN || key == '\n')
menubar_drop (menubar, menubar->selected);
cmd = keybind_lookup_keymap_command (menu_map, key);
return 1;
}
{
menu_t *menu = MENU (g_list_nth_data (menubar->menu, menubar->selected));
GList *i;
/* execute menu command by hotkey */
for (i = menu->entries; i != NULL; i = g_list_next (i))
{
const menu_entry_t *entry = MENUENTRY (i->data);
if ((entry != NULL) && (entry->command != CK_IgnoreKey)
&& (entry->text.hotkey != NULL) && (key == g_ascii_tolower (entry->text.hotkey[0])))
{
menu->selected = g_list_position (menu->entries, i);
menubar_execute (menubar);
return 1;
}
}
/* menu execute by Enter or menu navigation */
switch (key)
{
case KEY_ENTER:
case '\n':
menubar_execute (menubar);
return 1;
case KEY_HOME:
case ALT ('<'):
menubar_first (menubar);
break;
case KEY_END:
case ALT ('>'):
menubar_last (menubar);
break;
case KEY_DOWN:
case XCTRL ('n'):
menubar_down (menubar);
break;
case KEY_UP:
case XCTRL ('p'):
menubar_up (menubar);
break;
default:
break;
}
}
return 0;
return (cmd == CK_IgnoreKey
|| menubar_execute_cmd (menubar, cmd,
key) == MSG_NOT_HANDLED) ? MSG_NOT_HANDLED : MSG_HANDLED;
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -143,6 +143,17 @@ ScreenList = alt-prime
ScreenNext = alt-rbrace
ScreenPrev = alt-lbrace
[menu]
Help = f1
Left = left; ctrl-b
Right = right; ctrl-f
Up = up; ctrl-p
Down = down; ctrl-n
Home = home; alt-lt; ctr-a
End = end; alt-gt ctrl-e
Enter = enter
Quit = F10; esc; ctrl-g
[input]
Home = ctrl-a; alt-lt; home; a1
End = ctrl-e; alt-gt; end; c1

View File

@ -143,6 +143,17 @@ ScreenList = alt-prime
ScreenNext = alt-rbrace
ScreenPrev = alt-lbrace
[menu]
Help = f1
Left = left; ctrl-b
Right = right; ctrl-f
Up = up; ctrl-p
Down = down; ctrl-n
Home = home; alt-lt; ctr-a
End = end; alt-gt ctrl-e
Enter = enter
Quit = F10; esc; ctrl-g
[input]
Home = ctrl-a; alt-lt; home; a1
End = ctrl-e; alt-gt; end; c1

View File

@ -38,6 +38,7 @@ GArray *main_keymap = NULL;
GArray *main_x_keymap = NULL;
GArray *panel_keymap = NULL;
GArray *dialog_keymap = NULL;
GArray *menu_keymap = NULL;
GArray *input_keymap = NULL;
GArray *listbox_keymap = NULL;
GArray *tree_keymap = NULL;
@ -55,6 +56,7 @@ GArray *diff_keymap = NULL;
const global_keymap_t *main_map = NULL;
const global_keymap_t *main_x_map = NULL;
const global_keymap_t *panel_map = NULL;
const global_keymap_t *menu_map = NULL;
const global_keymap_t *tree_map = NULL;
const global_keymap_t *help_map = NULL;
@ -225,6 +227,20 @@ static const global_keymap_ini_t default_dialog_keymap[] = {
{NULL, NULL}
};
/* menubar */
static const global_keymap_ini_t default_menu_keymap[] = {
{"Help", "f1"},
{"Left", "left; ctrl-b"},
{"Right", "right; ctrl-f"},
{"Up", "up; ctrl-p"},
{"Down", "down; enter; ctrl-n"},
{"Home", "home; alt-lt; ctrl-a"},
{"End", "end; alt-gt; ctrl-e"},
{"Enter", "enter"},
{"Quit", "f10; ctrl-g; esc"},
{NULL, NULL}
};
/* input line */
static const global_keymap_ini_t default_input_keymap[] = {
/* Motion */
@ -590,6 +606,7 @@ create_default_keymap (void)
create_default_keymap_section (keymap, KEYMAP_SECTION_MAIN_EXT, default_main_x_keymap);
create_default_keymap_section (keymap, KEYMAP_SECTION_PANEL, default_panel_keymap);
create_default_keymap_section (keymap, KEYMAP_SECTION_DIALOG, default_dialog_keymap);
create_default_keymap_section (keymap, KEYMAP_SECTION_MENU, default_menu_keymap);
create_default_keymap_section (keymap, KEYMAP_SECTION_INPUT, default_input_keymap);
create_default_keymap_section (keymap, KEYMAP_SECTION_LISTBOX, default_listbox_keymap);
create_default_keymap_section (keymap, KEYMAP_SECTION_TREE, default_tree_keymap);

View File

@ -17,6 +17,7 @@ extern GArray *main_keymap;
extern GArray *main_x_keymap;
extern GArray *panel_keymap;
extern GArray *dialog_keymap;
extern GArray *menu_keymap;
extern GArray *input_keymap;
extern GArray *listbox_keymap;
extern GArray *tree_keymap;
@ -31,10 +32,10 @@ extern GArray *viewer_hex_keymap;
extern GArray *diff_keymap;
#endif
extern const global_keymap_t *main_map;
extern const global_keymap_t *main_x_map;
extern const global_keymap_t *panel_map;
extern const global_keymap_t *menu_map;
extern const global_keymap_t *tree_map;
extern const global_keymap_t *help_map;

View File

@ -1365,6 +1365,9 @@ load_keymap_defs (gboolean load_from_file)
dialog_keymap = g_array_new (TRUE, FALSE, sizeof (global_keymap_t));
load_keymap_from_section (KEYMAP_SECTION_DIALOG, dialog_keymap, mc_global_keymap);
menu_keymap = g_array_new (TRUE, FALSE, sizeof (global_keymap_t));
load_keymap_from_section (KEYMAP_SECTION_MENU, menu_keymap, mc_global_keymap);
input_keymap = g_array_new (TRUE, FALSE, sizeof (global_keymap_t));
load_keymap_from_section (KEYMAP_SECTION_INPUT, input_keymap, mc_global_keymap);
@ -1401,6 +1404,7 @@ load_keymap_defs (gboolean load_from_file)
main_x_map = (global_keymap_t *) main_x_keymap->data;
panel_map = (global_keymap_t *) panel_keymap->data;
dialog_map = (global_keymap_t *) dialog_keymap->data;
menu_map = (global_keymap_t *) menu_keymap->data;
input_map = (global_keymap_t *) input_keymap->data;
listbox_map = (global_keymap_t *) listbox_keymap->data;
tree_map = (global_keymap_t *) tree_keymap->data;