mirror of
https://github.com/labwc/labwc.git
synced 2026-04-20 06:46:53 -04:00
menu: implement menu accelerators
Menu accelerators are one-letter mnemonics to quickly select/exec items from the current menu. For each menu item, the accelerator is defined as the first character of the item label, converted to lowercase. A different accelerator can be explicitly defined in menu.xml with the special '_' character before the target letter. - Add a field `accelerator` to the `menuitem` struct - Implement `menu_item_select_by_accelerator()` Example: The accelerator for an item with the label "e_macs" is 'm'.
This commit is contained in:
parent
afaed4af63
commit
a3971feca8
2 changed files with 70 additions and 1 deletions
|
|
@ -23,6 +23,7 @@ struct menuitem {
|
||||||
char *text;
|
char *text;
|
||||||
char *icon_name;
|
char *icon_name;
|
||||||
const char *arrow;
|
const char *arrow;
|
||||||
|
char accelerator;
|
||||||
struct menu *parent;
|
struct menu *parent;
|
||||||
struct menu *submenu;
|
struct menu *submenu;
|
||||||
bool selectable;
|
bool selectable;
|
||||||
|
|
@ -66,6 +67,19 @@ struct menu {
|
||||||
/* For keyboard support */
|
/* For keyboard support */
|
||||||
void menu_item_select_next(void);
|
void menu_item_select_next(void);
|
||||||
void menu_item_select_previous(void);
|
void menu_item_select_previous(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* menu_item_select_by_accelerator - selects the next menu item with
|
||||||
|
* a matching accelerator, starting after the current selection
|
||||||
|
*
|
||||||
|
* @accelerator a shortcut to quickly select/open an item, defined in menu.xml
|
||||||
|
* with an underscore in the item label before the target letter.
|
||||||
|
*
|
||||||
|
* Return: a boolean value that represents whether the newly selected item
|
||||||
|
* needs to be executed.
|
||||||
|
*/
|
||||||
|
bool menu_item_select_by_accelerator(char accelerator);
|
||||||
|
|
||||||
void menu_submenu_enter(void);
|
void menu_submenu_enter(void);
|
||||||
void menu_submenu_leave(void);
|
void menu_submenu_leave(void);
|
||||||
bool menu_call_selected_actions(void);
|
bool menu_call_selected_actions(void);
|
||||||
|
|
@ -100,7 +114,7 @@ void menu_open_root(struct menu *menu, int x, int y);
|
||||||
void menu_process_cursor_motion(struct wlr_scene_node *node);
|
void menu_process_cursor_motion(struct wlr_scene_node *node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* menu_close_root- close root menu
|
* menu_close_root - close root menu
|
||||||
*
|
*
|
||||||
* This function will close server.menu_current and set it to NULL.
|
* This function will close server.menu_current and set it to NULL.
|
||||||
* Asserts that server.input_mode is set to LAB_INPUT_STATE_MENU.
|
* Asserts that server.input_mode is set to LAB_INPUT_STATE_MENU.
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include "menu/menu.h"
|
#include "menu/menu.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -143,6 +144,16 @@ item_create(struct menu *menu, const char *text, const char *icon_name, bool sho
|
||||||
menuitem->text = xstrdup(text);
|
menuitem->text = xstrdup(text);
|
||||||
menuitem->arrow = show_arrow ? "›" : NULL;
|
menuitem->arrow = show_arrow ? "›" : NULL;
|
||||||
|
|
||||||
|
const char *it = text;
|
||||||
|
menuitem->accelerator = tolower(*it);
|
||||||
|
while (*it != '\0') {
|
||||||
|
if (*it == '_' && *it != '\0') {
|
||||||
|
menuitem->accelerator = *(++it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
#if HAVE_LIBSFDO
|
#if HAVE_LIBSFDO
|
||||||
if (rc.menu_show_icons && !string_null_or_empty(icon_name)) {
|
if (rc.menu_show_icons && !string_null_or_empty(icon_name)) {
|
||||||
menuitem->icon_name = xstrdup(icon_name);
|
menuitem->icon_name = xstrdup(icon_name);
|
||||||
|
|
@ -1460,6 +1471,50 @@ menu_item_select_previous(void)
|
||||||
menu_item_select(/* forward */ false);
|
menu_item_select(/* forward */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
menu_item_select_by_accelerator(char accelerator)
|
||||||
|
{
|
||||||
|
struct menu *menu = get_selection_leaf();
|
||||||
|
if (!menu) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needs_exec = true;
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
|
struct menuitem *selection = menu->selection.item;
|
||||||
|
struct wl_list *start = selection ? &selection->link : &menu->menuitems;
|
||||||
|
struct wl_list *current = start;
|
||||||
|
struct menuitem *item = NULL;
|
||||||
|
struct menuitem *next_selection = NULL;
|
||||||
|
do {
|
||||||
|
current = current->next;
|
||||||
|
item = wl_container_of(current, item, link);
|
||||||
|
if (!matched && item->accelerator == accelerator) {
|
||||||
|
/* Menuentry with a matching accelerator found */
|
||||||
|
next_selection = item;
|
||||||
|
matched = true;
|
||||||
|
} else if (matched && item->accelerator == accelerator) {
|
||||||
|
/* Another menuentry with such accelerator found,
|
||||||
|
cycle selection instead of executing */
|
||||||
|
needs_exec = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (current != start);
|
||||||
|
|
||||||
|
if (next_selection) {
|
||||||
|
menu_process_item_selection(next_selection);
|
||||||
|
if (needs_exec && next_selection->submenu) {
|
||||||
|
/* Submenu was opened, select the first menuitem
|
||||||
|
without executing */
|
||||||
|
needs_exec = false;
|
||||||
|
menu_submenu_enter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return needs_exec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
menu_call_selected_actions(void)
|
menu_call_selected_actions(void)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue