Fix menu handling.

We now send mouse events to widgets in reverse Z-order, as done in common GUIs.
This makes it easy to implement "invisible" menubars correctly.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
Mooffie 2016-02-23 09:49:58 +03:00 committed by Andrew Borodin
parent c9a437a9c2
commit 781b810c13
4 changed files with 47 additions and 64 deletions

View File

@ -362,7 +362,7 @@ dlg_mouse_event (WDialog * h, Gpm_Event * event)
{
Widget *wh = WIDGET (h);
GList *p, *first;
GList *p;
/* close the dialog by mouse left click out of dialog area */
if (mouse_close_dialog && !h->fullscreen && ((event->buttons & GPM_B_LEFT) != 0)
@ -382,15 +382,12 @@ dlg_mouse_event (WDialog * h, Gpm_Event * event)
return mou;
}
first = h->current;
p = first;
/* send the event to widgets in reverse Z-order */
p = g_list_last (h->widgets);
do
{
Widget *w = WIDGET (p->data);
p = dlg_widget_prev (h, p);
if ((w->options & W_DISABLED) == 0 && w->mouse != NULL)
{
/* put global cursor position to the widget */
@ -400,8 +397,10 @@ dlg_mouse_event (WDialog * h, Gpm_Event * event)
if (ret != MOU_UNHANDLED)
return ret;
}
p = g_list_previous (p);
}
while (p != first);
while (p != NULL);
return MOU_UNHANDLED;
}
@ -1072,12 +1071,8 @@ dlg_select_widget (void *w)
/* --------------------------------------------------------------------------------------------- */
/**
* Set widget at top of widget list and make it current.
*/
void
dlg_set_top_widget (void *w)
static void
dlg_set_top_or_bottom_widget (void *w, gboolean set_top)
{
Widget *widget = WIDGET (w);
WDialog *h = widget->owner;
@ -1088,13 +1083,37 @@ dlg_set_top_widget (void *w)
abort (); /* widget is not in dialog, this should not happen */
/* unfocus prevoius widget and focus current one before widget reordering */
if (h->state == DLG_ACTIVE)
if (set_top && h->state == DLG_ACTIVE)
do_select_widget (h, l, SELECT_EXACT);
/* widget reordering */
h->widgets = g_list_remove_link (h->widgets, l);
if (set_top)
h->widgets = g_list_concat (h->widgets, l);
h->current = l;
else
h->widgets = g_list_concat (l, h->widgets);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Set widget at top of widget list and make it current.
*/
void
dlg_set_top_widget (void *w)
{
dlg_set_top_or_bottom_widget (w, TRUE);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Set widget at bottom of widget list.
*/
void
dlg_set_bottom_widget (void *w)
{
dlg_set_top_or_bottom_widget (w, FALSE);
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -171,6 +171,7 @@ void dlg_stop (WDialog * h);
/* Widget selection */
void dlg_select_widget (void *w);
void dlg_set_top_widget (void *w);
void dlg_set_bottom_widget (void *w);
void dlg_one_up (WDialog * h);
void dlg_one_down (WDialog * h);
gboolean dlg_focus (WDialog * h);

View File

@ -309,6 +309,10 @@ menubar_finish (WMenuBar * menubar)
w->lines = 1;
widget_want_hotkey (w, 0);
/* Move the menubar to the bottom so that widgets displayed on top of
* an "invisible" menubar get the first chance to respond to mouse events. */
dlg_set_bottom_widget (w);
dlg_select_by_id (w->owner, menubar->previous_widget);
do_refresh ();
}
@ -716,15 +720,7 @@ menubar_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
unsigned int selected;
selected = menubar_get_menu_by_x_coord (menubar, event->x);
if (!menubar->is_active)
{
/* menu bar is not active -- activate it */
menubar->previous_widget = dlg_get_current_widget_id (w->owner);
menubar->is_active = TRUE;
dlg_select_widget (w);
}
menubar_activate (menubar, TRUE, selected);
menubar_remove (menubar); /* if already shown */
menubar_drop (menubar, selected);
}
@ -1019,7 +1015,10 @@ menubar_activate (WMenuBar * menubar, gboolean dropped, int which)
menubar->selected = (guint) which;
menubar->previous_widget = dlg_get_current_widget_id (w->owner);
dlg_select_widget (w);
/* Bring it to the top so it receives all mouse events before any other widget.
* See also comment in menubar_finish(). */
dlg_set_top_widget (w);
}
}

View File

@ -1575,42 +1575,6 @@ midnight_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void
}
}
/* --------------------------------------------------------------------------------------------- */
static int
midnight_event (Gpm_Event * event, void *data)
{
Widget *wh = WIDGET (data);
int ret = MOU_UNHANDLED;
if (event->y == wh->y + 1)
{
/* menubar */
if (menubar_visible || the_menubar->is_active)
ret = WIDGET (the_menubar)->mouse (event, the_menubar);
else
{
Widget *w;
w = get_panel_widget (0);
if (w->mouse != NULL)
ret = w->mouse (event, w);
if (ret == MOU_UNHANDLED)
{
w = get_panel_widget (1);
if (w->mouse != NULL)
ret = w->mouse (event, w);
}
if (ret == MOU_UNHANDLED)
ret = WIDGET (the_menubar)->mouse (event, the_menubar);
}
}
return ret;
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
@ -1793,8 +1757,8 @@ do_nc (void)
edit_stack_init ();
#endif
midnight_dlg = dlg_create (FALSE, 0, 0, LINES, COLS, dialog_colors, midnight_callback,
midnight_event, "[main]", NULL, DLG_NONE);
midnight_dlg = dlg_create (FALSE, 0, 0, LINES, COLS, dialog_colors, midnight_callback, NULL,
"[main]", NULL, DLG_NONE);
/* Check if we were invoked as an editor or file viewer */
if (mc_global.mc_run_mode != MC_RUN_FULL)