Commit 4a48e94d authored by Eli Zaretskii's avatar Eli Zaretskii
Browse files

Horizontal keys in TTY menus work.

parent 493a1978
......@@ -2197,8 +2197,14 @@ FROM-MENU-BAR, if non-nil, means we are dropping one of menu-bar's menus."
(filter (when (symbolp map)
(plist-get (get map 'menu-prop) :filter))))
(if filter (funcall filter (symbol-function map)) map)))))
event cmd
(position (popup-menu-normalize-position position)))
(frame (selected-frame))
event cmd)
(if from-menu-bar
(let* ((xy (posn-x-y position))
(menu-symbol (menu-bar-menu-at-x-y (car xy) (cdr xy))))
(setq position (list menu-symbol (list frame '(menu-bar)
xy 0))))
(setq position (popup-menu-normalize-position position)))
;; The looping behavior was taken from lmenu's popup-menu-popup
(while (and map (setq event
;; map could be a prefix key, in which case
......@@ -2209,19 +2215,36 @@ FROM-MENU-BAR, if non-nil, means we are dropping one of menu-bar's menus."
;; mouse-major-mode-menu was using a weird:
;; (key-binding (apply 'vector (append '(menu-bar) menu-prefix events)))
(setq cmd
(if (and (not (keymapp map)) (listp map))
;; We were given a list of keymaps. Search them all
;; in sequence until a first binding is found.
(let ((mouse-click (apply 'vector event))
binding)
(while (and map (null binding))
(setq binding (lookup-key (car map) mouse-click))
(if (numberp binding) ; `too long'
(setq binding nil))
(setq map (cdr map)))
binding)
(cond
((and from-menu-bar
(consp event)
(numberp (car event))
(numberp (cdr event)))
(let ((x (car event))
(y (cdr event))
menu-symbol)
(setq menu-symbol (menu-bar-menu-at-x-y x y))
(setq position (list menu-symbol (list frame '(menu-bar)
event 0)))
(setq map
(or
(lookup-key global-map (vector 'menu-bar menu-symbol))
(lookup-key (current-local-map) (vector 'menu-bar
menu-symbol))))))
((and (not (keymapp map)) (listp map))
;; We were given a list of keymaps. Search them all
;; in sequence until a first binding is found.
(let ((mouse-click (apply 'vector event))
binding)
(while (and map (null binding))
(setq binding (lookup-key (car map) mouse-click))
(if (numberp binding) ; `too long'
(setq binding nil))
(setq map (cdr map)))
binding))
(t
;; We were given a single keymap.
(lookup-key map (apply 'vector event))))
(lookup-key map (apply 'vector event)))))
;; Clear out echoing, which perhaps shows a prefix arg.
(message "")
;; Maybe try again but with the submap.
......@@ -2379,7 +2402,7 @@ If FRAME is nil or not given, use the selected frame."
(popup-menu (or
(lookup-key global-map (vector 'menu-bar menu))
(lookup-key (current-local-map) (vector 'menu-bar menu)))
(posn-at-x-y x 0 nil t) t)))
(posn-at-x-y x 0 nil t) nil t)))
(t (with-selected-frame (or frame (selected-frame))
(tmm-menubar))))))
......
......@@ -1036,8 +1036,8 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data
}
#endif /* HAVE_NS */
static int
item_width (const char *str)
int
menu_item_width (const char *str)
{
int len;
const char *p;
......@@ -1104,7 +1104,7 @@ into menu items. */)
if (XINT (pos) <= col
/* We use <= so the blank between 2 items on a TTY is
considered part of the previous item. */
&& col <= XINT (pos) + item_width (SSDATA (str)))
&& col <= XINT (pos) + menu_item_width (SSDATA (str)))
{
item = AREF (items, i);
return item;
......@@ -1160,7 +1160,7 @@ event (indicating that the user invoked the menu with the mouse) then
no quit occurs and `x-popup-menu' returns nil. */)
(Lisp_Object position, Lisp_Object menu)
{
Lisp_Object keymap, tem;
Lisp_Object keymap, tem, tem2;
int xpos = 0, ypos = 0;
Lisp_Object title;
const char *error_name = NULL;
......@@ -1169,6 +1169,7 @@ no quit occurs and `x-popup-menu' returns nil. */)
Lisp_Object x, y, window;
bool keymaps = 0;
bool for_click = 0;
bool kbd_menu_navigation = 0;
ptrdiff_t specpdl_count = SPECPDL_INDEX ();
struct gcpro gcpro1;
......@@ -1202,6 +1203,22 @@ no quit occurs and `x-popup-menu' returns nil. */)
for_click = 1;
tem = Fcar (Fcdr (position)); /* EVENT_START (position) */
window = Fcar (tem); /* POSN_WINDOW (tem) */
tem2 = Fcar (Fcdr (tem)); /* POSN_POSN (tem) */
/* The kbd_menu_navigation flag is set when the menu was
invoked by F10, which probably means they have no
mouse. In that case, we let them switch between
top-level menu-bar menus by using C-f/C-b and
horizontal arrow keys, since they cannot click the
mouse to open a different submenu. This flag is only
supported by tty_menu_show. We set it when POSITION
and last_nonmenu_event are different, which means we
constructed POSITION by hand (in popup-menu, see
menu-bar.el) to look like a mouse click on the menu bar
event. */
if (!EQ (POSN_POSN (last_nonmenu_event),
POSN_POSN (position))
&& CONSP (tem2) && EQ (Fcar (tem2), Qmenu_bar))
kbd_menu_navigation = 1;
tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */
x = Fcar (tem);
y = Fcdr (tem);
......@@ -1434,8 +1451,8 @@ no quit occurs and `x-popup-menu' returns nil. */)
else
#endif
if (FRAME_TERMCAP_P (f))
selection = tty_menu_show (f, xpos, ypos, for_click,
keymaps, title, &error_name);
selection = tty_menu_show (f, xpos, ypos, for_click, keymaps, title,
kbd_menu_navigation, &error_name);
#ifdef HAVE_NS
unbind_to (specpdl_count, Qnil);
......
......@@ -52,5 +52,6 @@ extern Lisp_Object ns_menu_show (struct frame *, int, int, bool, bool,
extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool,
Lisp_Object, const char **, Time);
extern Lisp_Object tty_menu_show (struct frame *, int, int, int, int,
Lisp_Object, const char **);
Lisp_Object, int, const char **);
extern int menu_item_width (const char *);
#endif /* MENU_H */
......@@ -2789,6 +2789,8 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
#define TTYM_SUCCESS 1
#define TTYM_NO_SELECT 2
#define TTYM_IA_SELECT 3
#define TTYM_NEXT 4
#define TTYM_PREV 5
/* These hold text of the current and the previous menu help messages. */
static const char *menu_help_message, *prev_menu_help_message;
......@@ -3174,7 +3176,8 @@ screen_update (struct frame *f, struct glyph_matrix *mtx)
puts us. We only consider mouse movement and click events and
keyboard movement commands; the rest are ignored.
Value is -1 if C-g was pressed, 1 if an item was selected, zero
Value is -1 if C-g was pressed, 1 if an item was selected, 2 or 3
if we need to move to the next or previous menu-bar menu, zero
otherwise. */
static int
read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
......@@ -3219,9 +3222,15 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
*y = my;
}
else if (EQ (cmd, Qtty_menu_next_menu))
*x += 1;
{
usable_input = 0;
st = 2;
}
else if (EQ (cmd, Qtty_menu_prev_menu))
*x -= 1;
{
usable_input = 0;
st = 3;
}
else if (EQ (cmd, Qtty_menu_next_item))
{
if (*y < max_y)
......@@ -3255,10 +3264,11 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
}
/* Display menu, wait for user's response, and return that response. */
int
static int
tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
int x0, int y0, char **txt,
void (*help_callback)(char const *, int, int))
void (*help_callback)(char const *, int, int),
int kbd_navigation)
{
struct tty_menu_state *state;
int statecount, x, y, i, b, leave, result, onepane;
......@@ -3353,6 +3363,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
if (input_status)
{
leave = 1;
if (input_status == -1)
{
/* Remove the last help-echo, so that it doesn't
......@@ -3360,7 +3371,20 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
show_help_echo (Qnil, Qnil, Qnil, Qnil);
result = TTYM_NO_SELECT;
}
leave = 1;
else if (input_status == 2)
{
if (kbd_navigation)
result = TTYM_NEXT;
else
leave = 0;
}
else if (input_status == 3)
{
if (kbd_navigation)
result = TTYM_PREV;
else
leave = 0;
}
}
if (sf->mouse_moved && input_status != -1)
{
......@@ -3509,15 +3533,97 @@ tty_pop_down_menu (Lisp_Object arg)
unblock_input ();
}
/* Return the zero-based index of the last menu-bar item on frame F. */
static int
tty_menu_last_menubar_item (struct frame *f)
{
int i = 0;
eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
{
Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
while (i < ASIZE (items))
{
Lisp_Object str;
str = AREF (items, i + 1);
if (NILP (str))
break;
i += 4;
}
i -= 4; /* went one too far */
}
return i;
}
/* Find in frame F's menu bar the menu item that is next or previous
to the item at X/Y, and return that item's position in X/Y. WHICH
says which one--next or previous--item to look for. X and Y are
measured in character cells. This should only be called on TTY
frames. */
static void
tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
{
eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
{
Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
int last_i = tty_menu_last_menubar_item (f);
int i, prev_x;
/* This loop assumes a single menu-bar line, and will fail to
find an item if it is not in the first line. Note that
make_lispy_event in keyboard.c makes the same assumption. */
for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
{
Lisp_Object pos, str;
int ix;
str = AREF (items, i + 1);
pos = AREF (items, i + 3);
if (NILP (str))
return;
ix = XINT (pos);
if (ix <= *x
/* We use <= so the blank between 2 items on a TTY is
considered part of the previous item. */
&& *x <= ix + menu_item_width (SSDATA (str)))
{
/* Found current item. Now compute the X coordinate of
the previous or next item. */
if (which == TTYM_NEXT)
{
if (i < last_i)
*x = XINT (AREF (items, i + 4 + 3));
else
*x = 0; /* wrap around to the first item */
}
else if (prev_x < 0)
{
/* Wrap around to the last item. */
*x = XINT (AREF (items, last_i + 3));
}
else
*x = prev_x;
return;
}
prev_x = ix;
}
}
}
Lisp_Object
tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
Lisp_Object title, const char **error_name)
Lisp_Object title, int kbd_navigation, const char **error_name)
{
tty_menu *menu;
int pane, selidx, lpane, status;
Lisp_Object entry, pane_prefix;
char *datap;
int ulx, uly, width, height;
int item_x, item_y;
int dispwidth, dispheight;
int i, j, lines, maxlines;
int maxwidth;
......@@ -3551,8 +3657,8 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
inhibit_garbage_collection ();
/* Adjust coordinates to be root-window-relative. */
x += f->left_pos;
y += f->top_pos;
item_x = x += f->left_pos;
item_y = y += f->top_pos;
/* Create all the necessary panes and their items. */
maxwidth = maxlines = lines = i = 0;
......@@ -3710,7 +3816,7 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
specbind (Qoverriding_terminal_local_map,
Fsymbol_value (Qtty_menu_navigation_map));
status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
tty_menu_help_callback);
tty_menu_help_callback, kbd_navigation);
entry = pane_prefix = Qnil;
switch (status)
......@@ -3751,6 +3857,12 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
}
break;
case TTYM_NEXT:
case TTYM_PREV:
tty_menu_new_item_coords (f, status, &item_x, &item_y);
entry = Fcons (make_number (item_x), make_number (item_y));
break;
case TTYM_FAILURE:
*error_name = "Can't activate menu";
case TTYM_IA_SELECT:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment