mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-23 04:46:55 +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 ****************************************************************/
|
/*** 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 */
|
/* Control widget positions in dialog */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -125,6 +117,28 @@ dlg_get_next_or_prev_of (const GList * list, gboolean next)
|
|||||||
return l;
|
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
|
* 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
|
static int
|
||||||
dlg_find_widget_callback (const void *a, const void *b)
|
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
|
static void
|
||||||
refresh_cmd (void)
|
refresh_cmd (void)
|
||||||
{
|
{
|
||||||
@ -508,7 +438,7 @@ dlg_try_hotkey (WDialog * h, int d_key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (handled == MSG_HANDLED)
|
if (handled == MSG_HANDLED)
|
||||||
do_select_widget (h, hot_cur, SELECT_EXACT);
|
widget_select (WIDGET (hot_cur->data));
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
@ -1005,6 +935,8 @@ del_widget (void *w)
|
|||||||
dlg_set_current_widget_next (h);
|
dlg_set_current_widget_next (h);
|
||||||
|
|
||||||
h->widgets = g_list_remove_link (h->widgets, d);
|
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);
|
send_message (d->data, NULL, MSG_DESTROY, 0, NULL);
|
||||||
g_free (d->data);
|
g_free (d->data);
|
||||||
g_list_free_1 (d);
|
g_list_free_1 (d);
|
||||||
@ -1013,7 +945,7 @@ del_widget (void *w)
|
|||||||
if (widget_get_state (WIDGET (h), WST_ACTIVE))
|
if (widget_get_state (WIDGET (h), WST_ACTIVE))
|
||||||
{
|
{
|
||||||
dlg_redraw (h);
|
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);
|
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 */
|
/** 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);
|
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 */
|
/** Find the widget with the given id */
|
||||||
|
|
||||||
@ -1113,40 +1029,13 @@ dlg_select_by_id (const WDialog * h, unsigned long id)
|
|||||||
widget_select (w);
|
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 */
|
/** Try to select previous widget in the tab order */
|
||||||
|
|
||||||
void
|
void
|
||||||
dlg_select_prev_widget (WDialog * h)
|
dlg_select_prev_widget (WDialog * h)
|
||||||
{
|
{
|
||||||
if (h->widgets != NULL)
|
dlg_select_next_or_prev (h, FALSE);
|
||||||
do_select_widget (h, dlg_get_widget_prev_of (h->current), SELECT_PREV);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
@ -1155,8 +1044,7 @@ dlg_select_prev_widget (WDialog * h)
|
|||||||
void
|
void
|
||||||
dlg_select_next_widget (WDialog * h)
|
dlg_select_next_widget (WDialog * h)
|
||||||
{
|
{
|
||||||
if (h->widgets != NULL)
|
dlg_select_next_or_prev (h, TRUE);
|
||||||
do_select_widget (h, dlg_get_widget_next_of (h->current), SELECT_NEXT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
@ -1247,15 +1135,15 @@ dlg_init (WDialog * h)
|
|||||||
dlg_read_history (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);
|
widget_set_state (wh, WST_ACTIVE, TRUE);
|
||||||
|
|
||||||
/* first send MSG_DRAW to dialog itself and all widgets... */
|
|
||||||
dlg_redraw (h);
|
dlg_redraw (h);
|
||||||
|
/* focus found widget */
|
||||||
/* ...then send MSG_FOCUS to select the first widget that can take focus */
|
widget_set_state (WIDGET (h->current->data), WST_FOCUSED, TRUE);
|
||||||
while (h->current != NULL && !dlg_focus (h))
|
|
||||||
h->current = dlg_get_widget_next_of (h->current);
|
|
||||||
|
|
||||||
|
|
||||||
h->ret_value = 0;
|
h->ret_value = 0;
|
||||||
}
|
}
|
||||||
|
@ -147,12 +147,10 @@ void dlg_erase (WDialog * h);
|
|||||||
void dlg_stop (WDialog * h);
|
void dlg_stop (WDialog * h);
|
||||||
|
|
||||||
/* Widget selection */
|
/* Widget selection */
|
||||||
void widget_select (Widget * w);
|
|
||||||
void widget_set_bottom (void *w);
|
|
||||||
void dlg_select_prev_widget (WDialog * h);
|
void dlg_select_prev_widget (WDialog * h);
|
||||||
void dlg_select_next_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);
|
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);
|
Widget *dlg_find_by_id (const WDialog * h, unsigned long id);
|
||||||
void dlg_select_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 */
|
#endif /* MC__DIALOG_H */
|
||||||
|
@ -53,7 +53,63 @@
|
|||||||
|
|
||||||
/*** file scope variables ************************************************************************/
|
/*** file scope variables ************************************************************************/
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
/*** file scope functions ************************************************************************/
|
/*** 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 ****************************************************************************/
|
/*** public functions ****************************************************************************/
|
||||||
@ -387,7 +443,50 @@ widget_replace (Widget * old_w, Widget * new_w)
|
|||||||
if (should_focus)
|
if (should_focus)
|
||||||
widget_select (new_w);
|
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_is_active (const void *w);
|
||||||
gboolean widget_overlapped (const Widget * a, const Widget * b);
|
gboolean widget_overlapped (const Widget * a, const Widget * b);
|
||||||
void widget_replace (Widget * old, Widget * new);
|
void widget_replace (Widget * old, Widget * new);
|
||||||
|
void widget_select (Widget * w);
|
||||||
|
void widget_set_bottom (Widget * w);
|
||||||
|
|
||||||
/* get mouse pointer location within widget */
|
/* get mouse pointer location within widget */
|
||||||
Gpm_Event mouse_get_local (const Gpm_Event * global, const Widget * w);
|
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] = '+';
|
ch_flags[f_pos + 6] = '+';
|
||||||
update_ownership ();
|
update_ownership ();
|
||||||
}
|
}
|
||||||
dlg_focus (h);
|
dlg_select_current_widget (h);
|
||||||
if (ok)
|
if (ok)
|
||||||
print_flags ();
|
print_flags ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user