mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-22 20:36:50 +03:00
Reimplement widget focus/selection.
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
parent
599361b3fc
commit
36cc88b5f2
@ -73,14 +73,6 @@ const global_keymap_t *dialog_map = NULL;
|
||||
|
||||
/*** file scope type declarations ****************************************************************/
|
||||
|
||||
/** What to do if the requested widget doesn't take focus */
|
||||
typedef enum
|
||||
{
|
||||
SELECT_NEXT, /* go the the next widget */
|
||||
SELECT_PREV, /* go the the previous widget */
|
||||
SELECT_EXACT /* use current widget */
|
||||
} select_dir_t;
|
||||
|
||||
/* Control widget positions in dialog */
|
||||
typedef struct
|
||||
{
|
||||
@ -125,6 +117,28 @@ dlg_get_next_or_prev_of (const GList * list, gboolean next)
|
||||
return l;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
dlg_select_next_or_prev (WDialog * h, gboolean next)
|
||||
{
|
||||
if (h->widgets != NULL && h->current != NULL)
|
||||
{
|
||||
GList *l = h->current;
|
||||
Widget *w;
|
||||
|
||||
do
|
||||
{
|
||||
l = dlg_get_next_or_prev_of (l, next);
|
||||
w = WIDGET (l->data);
|
||||
}
|
||||
while ((widget_get_state (w, WST_DISABLED) || !widget_get_options (w, WOP_SELECTABLE))
|
||||
&& l != h->current);
|
||||
|
||||
widget_select (l->data);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* broadcast a message to all the widgets in a dialog that have
|
||||
@ -185,24 +199,6 @@ dlg_read_history (WDialog * h)
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static gboolean
|
||||
dlg_unfocus (WDialog * h)
|
||||
{
|
||||
/* we can unfocus disabled widget */
|
||||
if (h->current != NULL)
|
||||
{
|
||||
Widget *wh = WIDGET (h);
|
||||
|
||||
if ((widget_get_state (wh, WST_CONSTRUCT) || widget_get_state (wh, WST_ACTIVE))
|
||||
&& widget_set_state (WIDGET (h->current->data), WST_FOCUSED, FALSE) == MSG_HANDLED)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
dlg_find_widget_callback (const void *a, const void *b)
|
||||
{
|
||||
@ -214,72 +210,6 @@ dlg_find_widget_callback (const void *a, const void *b)
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Put widget on top or bottom of Z-order.
|
||||
*/
|
||||
static void
|
||||
dlg_reorder_widgets (GList * l, gboolean set_top)
|
||||
{
|
||||
WDialog *h = WIDGET (l->data)->owner;
|
||||
|
||||
h->widgets = g_list_remove_link (h->widgets, l);
|
||||
if (set_top)
|
||||
h->widgets = g_list_concat (h->widgets, l);
|
||||
else
|
||||
h->widgets = g_list_concat (l, h->widgets);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Try to select another widget. If forward is set, follow tab order.
|
||||
* Otherwise go to the previous widget.
|
||||
*/
|
||||
|
||||
static void
|
||||
do_select_widget (WDialog * h, GList * w, select_dir_t dir)
|
||||
{
|
||||
Widget *w0 = WIDGET (h->current->data);
|
||||
|
||||
if (!dlg_unfocus (h))
|
||||
return;
|
||||
|
||||
h->current = w;
|
||||
|
||||
do
|
||||
{
|
||||
if (dlg_focus (h))
|
||||
break;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case SELECT_EXACT:
|
||||
h->current = g_list_find (h->widgets, w0);
|
||||
if (dlg_focus (h))
|
||||
return;
|
||||
/* try find another widget that can take focus */
|
||||
dir = SELECT_NEXT;
|
||||
/* fallthrough */
|
||||
case SELECT_NEXT:
|
||||
dlg_set_current_widget_next (h);
|
||||
break;
|
||||
case SELECT_PREV:
|
||||
dlg_set_current_widget_prev (h);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (h->current != w);
|
||||
|
||||
if (widget_get_options (WIDGET (h->current->data), WOP_TOP_SELECT))
|
||||
dlg_reorder_widgets (h->current, TRUE);
|
||||
|
||||
if (widget_overlapped (w0, WIDGET (h->current->data)))
|
||||
widget_set_state (WIDGET (h->current->data), WST_FOCUSED, TRUE);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
refresh_cmd (void)
|
||||
{
|
||||
@ -508,7 +438,7 @@ dlg_try_hotkey (WDialog * h, int d_key)
|
||||
}
|
||||
|
||||
if (handled == MSG_HANDLED)
|
||||
do_select_widget (h, hot_cur, SELECT_EXACT);
|
||||
widget_select (WIDGET (hot_cur->data));
|
||||
|
||||
return handled;
|
||||
}
|
||||
@ -1005,6 +935,8 @@ del_widget (void *w)
|
||||
dlg_set_current_widget_next (h);
|
||||
|
||||
h->widgets = g_list_remove_link (h->widgets, d);
|
||||
if (h->widgets == NULL)
|
||||
h->current = NULL;
|
||||
send_message (d->data, NULL, MSG_DESTROY, 0, NULL);
|
||||
g_free (d->data);
|
||||
g_list_free_1 (d);
|
||||
@ -1013,7 +945,7 @@ del_widget (void *w)
|
||||
if (widget_get_state (WIDGET (h), WST_ACTIVE))
|
||||
{
|
||||
dlg_redraw (h);
|
||||
dlg_focus (h);
|
||||
dlg_select_current_widget (h);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1051,30 +983,6 @@ dlg_broadcast_msg (WDialog * h, widget_msg_t msg)
|
||||
dlg_broadcast_msg_to (h, msg, FALSE, 0);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
gboolean
|
||||
dlg_focus (WDialog * h)
|
||||
{
|
||||
/* cannot focus disabled widget */
|
||||
if (h->current != NULL)
|
||||
{
|
||||
Widget *wh = WIDGET (h);
|
||||
|
||||
if (widget_get_state (wh, WST_CONSTRUCT) || widget_get_state (wh, WST_ACTIVE))
|
||||
{
|
||||
Widget *current = WIDGET (h->current->data);
|
||||
|
||||
if (widget_get_options (current, WOP_SELECTABLE)
|
||||
&& !widget_get_state (current, WST_DISABLED)
|
||||
&& widget_set_state (current, WST_FOCUSED, TRUE) == MSG_HANDLED)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/** Find the widget with the given callback in the dialog h */
|
||||
|
||||
@ -1088,6 +996,14 @@ find_widget_type (const WDialog * h, widget_cb_fn callback)
|
||||
return (w == NULL) ? NULL : WIDGET (w->data);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
GList *
|
||||
dlg_find (const WDialog * h, const Widget * w)
|
||||
{
|
||||
return (w->owner == NULL || w->owner != h) ? NULL : g_list_find (h->widgets, w);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/** Find the widget with the given id */
|
||||
|
||||
@ -1113,40 +1029,13 @@ dlg_select_by_id (const WDialog * h, unsigned long id)
|
||||
widget_select (w);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Try to select widget in the dialog.
|
||||
*/
|
||||
|
||||
void
|
||||
widget_select (Widget * w)
|
||||
{
|
||||
WDialog *h = w->owner;
|
||||
|
||||
do_select_widget (h, g_list_find (h->widgets, w), SELECT_EXACT);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Set widget at bottom of widget list.
|
||||
*/
|
||||
|
||||
void
|
||||
widget_set_bottom (Widget * w)
|
||||
{
|
||||
WDialog *h = w->owner;
|
||||
|
||||
dlg_reorder_widgets (g_list_find (h->widgets, w), FALSE);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/** Try to select previous widget in the tab order */
|
||||
|
||||
void
|
||||
dlg_select_prev_widget (WDialog * h)
|
||||
{
|
||||
if (h->widgets != NULL)
|
||||
do_select_widget (h, dlg_get_widget_prev_of (h->current), SELECT_PREV);
|
||||
dlg_select_next_or_prev (h, FALSE);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
@ -1155,8 +1044,7 @@ dlg_select_prev_widget (WDialog * h)
|
||||
void
|
||||
dlg_select_next_widget (WDialog * h)
|
||||
{
|
||||
if (h->widgets != NULL)
|
||||
do_select_widget (h, dlg_get_widget_next_of (h->current), SELECT_NEXT);
|
||||
dlg_select_next_or_prev (h, TRUE);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
@ -1247,15 +1135,15 @@ dlg_init (WDialog * h)
|
||||
dlg_read_history (h);
|
||||
}
|
||||
|
||||
/* Select the first widget that takes focus */
|
||||
while (h->current != NULL && !widget_get_options (WIDGET (h->current->data), WOP_SELECTABLE)
|
||||
&& !widget_get_state (WIDGET (h->current->data), WST_DISABLED))
|
||||
dlg_set_current_widget_next (h);
|
||||
|
||||
widget_set_state (wh, WST_ACTIVE, TRUE);
|
||||
|
||||
/* first send MSG_DRAW to dialog itself and all widgets... */
|
||||
dlg_redraw (h);
|
||||
|
||||
/* ...then send MSG_FOCUS to select the first widget that can take focus */
|
||||
while (h->current != NULL && !dlg_focus (h))
|
||||
h->current = dlg_get_widget_next_of (h->current);
|
||||
|
||||
/* focus found widget */
|
||||
widget_set_state (WIDGET (h->current->data), WST_FOCUSED, TRUE);
|
||||
|
||||
h->ret_value = 0;
|
||||
}
|
||||
|
@ -147,12 +147,10 @@ void dlg_erase (WDialog * h);
|
||||
void dlg_stop (WDialog * h);
|
||||
|
||||
/* Widget selection */
|
||||
void widget_select (Widget * w);
|
||||
void widget_set_bottom (void *w);
|
||||
void dlg_select_prev_widget (WDialog * h);
|
||||
void dlg_select_next_widget (WDialog * h);
|
||||
gboolean dlg_focus (WDialog * h);
|
||||
Widget *find_widget_type (const WDialog * h, widget_cb_fn callback);
|
||||
GList *dlg_find (const WDialog * h, const Widget * w);
|
||||
Widget *dlg_find_by_id (const WDialog * h, unsigned long id);
|
||||
void dlg_select_by_id (const WDialog * h, unsigned long id);
|
||||
|
||||
@ -180,4 +178,19 @@ dlg_get_current_widget_id (const WDialog * h)
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Select current widget in the Dialog.
|
||||
*
|
||||
* @param h WDialog object
|
||||
*/
|
||||
|
||||
static inline void
|
||||
dlg_select_current_widget (WDialog * h)
|
||||
{
|
||||
if (h->current != NULL)
|
||||
widget_select (WIDGET (h->current->data));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
#endif /* MC__DIALOG_H */
|
||||
|
@ -53,7 +53,63 @@
|
||||
|
||||
/*** file scope variables ************************************************************************/
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/*** file scope functions ************************************************************************/
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
widget_do_focus (Widget * w, gboolean enable)
|
||||
{
|
||||
if (w != NULL && widget_get_state (WIDGET (w->owner), WST_FOCUSED))
|
||||
widget_set_state (w, WST_FOCUSED, enable);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Focus specified widget in it's owner.
|
||||
*
|
||||
* @param w widget to be focused.
|
||||
*/
|
||||
|
||||
static void
|
||||
widget_focus (Widget * w)
|
||||
{
|
||||
WDialog *h = DIALOG (w->owner);
|
||||
|
||||
if (h == NULL)
|
||||
return;
|
||||
|
||||
if (WIDGET (h->current->data) != w)
|
||||
{
|
||||
widget_do_focus (WIDGET (h->current->data), FALSE);
|
||||
/* Test if focus lost was allowed and focus has really been loose */
|
||||
if (h->current == NULL || !widget_get_state (WIDGET (h->current->data), WST_FOCUSED))
|
||||
{
|
||||
widget_do_focus (w, TRUE);
|
||||
h->current = dlg_find (h, w);
|
||||
}
|
||||
}
|
||||
else if (!widget_get_state (w, WST_FOCUSED))
|
||||
widget_do_focus (w, TRUE);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Put widget on top or bottom of Z-order.
|
||||
*/
|
||||
static void
|
||||
widget_reorder (GList * l, gboolean set_top)
|
||||
{
|
||||
WDialog *h = WIDGET (l->data)->owner;
|
||||
|
||||
h->widgets = g_list_remove_link (h->widgets, l);
|
||||
if (set_top)
|
||||
h->widgets = g_list_concat (h->widgets, l);
|
||||
else
|
||||
h->widgets = g_list_concat (l, h->widgets);
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/*** public functions ****************************************************************************/
|
||||
@ -387,7 +443,50 @@ widget_replace (Widget * old_w, Widget * new_w)
|
||||
if (should_focus)
|
||||
widget_select (new_w);
|
||||
|
||||
widget_redraw (new_w);
|
||||
/* draw inactive widget */
|
||||
if (!widget_get_state (new_w, WST_FOCUSED))
|
||||
widget_redraw (new_w);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Select specified widget in it's owner.
|
||||
*
|
||||
* @param w widget to be selected
|
||||
*/
|
||||
|
||||
void
|
||||
widget_select (Widget * w)
|
||||
{
|
||||
WDialog *h;
|
||||
|
||||
if (!widget_get_options (w, WOP_SELECTABLE))
|
||||
return;
|
||||
|
||||
h = w->owner;
|
||||
if (h != NULL)
|
||||
{
|
||||
if (widget_get_options (w, WOP_TOP_SELECT))
|
||||
{
|
||||
GList *l;
|
||||
|
||||
l = dlg_find (h, w);
|
||||
widget_reorder (l, TRUE);
|
||||
}
|
||||
|
||||
widget_focus (w);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Set widget at bottom of widget list.
|
||||
*/
|
||||
|
||||
void
|
||||
widget_set_bottom (Widget * w)
|
||||
{
|
||||
widget_reorder (dlg_find (w->owner, w), FALSE);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
@ -187,6 +187,8 @@ void widget_erase (Widget * w);
|
||||
gboolean widget_is_active (const void *w);
|
||||
gboolean widget_overlapped (const Widget * a, const Widget * b);
|
||||
void widget_replace (Widget * old, Widget * new);
|
||||
void widget_select (Widget * w);
|
||||
void widget_set_bottom (Widget * w);
|
||||
|
||||
/* get mouse pointer location within widget */
|
||||
Gpm_Event mouse_get_local (const Gpm_Event * global, const Widget * w);
|
||||
|
@ -400,7 +400,7 @@ do_enter_key (WDialog * h, int f_pos)
|
||||
ch_flags[f_pos + 6] = '+';
|
||||
update_ownership ();
|
||||
}
|
||||
dlg_focus (h);
|
||||
dlg_select_current_widget (h);
|
||||
if (ok)
|
||||
print_flags ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user