Find widget API: support groups.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
Andrew Borodin 2016-09-29 11:16:17 +03:00
parent fdf3d9c3b7
commit e9d23e90f0
17 changed files with 368 additions and 97 deletions

View File

@ -284,5 +284,5 @@ buttonbar_set_label (WButtonBar * bb, int idx, const char *text, const global_ke
WButtonBar *
find_buttonbar (const WDialog * h)
{
return BUTTONBAR (find_widget_type (h, buttonbar_callback));
return BUTTONBAR (widget_find_by_type (CONST_WIDGET (h), buttonbar_callback));
}

View File

@ -115,17 +115,6 @@ dlg_read_history (WDialog * h)
/* --------------------------------------------------------------------------------------------- */
static int
dlg_find_widget_callback (const void *a, const void *b)
{
const Widget *w = CONST_WIDGET (a);
const widget_cb_fn f = b;
return (w->callback == f) ? 0 : 1;
}
/* --------------------------------------------------------------------------------------------- */
static void
refresh_cmd (void)
{
@ -468,16 +457,6 @@ frontend_dlg_run (WDialog * h)
/* --------------------------------------------------------------------------------------------- */
static int
dlg_find_widget_by_id (gconstpointer a, gconstpointer b)
{
const Widget *w = CONST_WIDGET (a);
unsigned long id = GPOINTER_TO_UINT (b);
return w->id == id ? 0 : 1;
}
/* --------------------------------------------------------------------------------------------- */
static void
dlg_widget_set_position (gpointer data, gpointer user_data)
{
@ -742,42 +721,6 @@ do_refresh (void)
}
}
/* --------------------------------------------------------------------------------------------- */
/** Find the widget with the given callback in the dialog h */
Widget *
find_widget_type (const WDialog * h, widget_cb_fn callback)
{
GList *w;
w = g_list_find_custom (CONST_GROUP (h)->widgets, (gconstpointer) callback,
dlg_find_widget_callback);
return (w == NULL) ? NULL : WIDGET (w->data);
}
/* --------------------------------------------------------------------------------------------- */
GList *
dlg_find (const WDialog * h, const Widget * w)
{
const WGroup *g = CONST_GROUP (h);
return (w->owner == NULL || w->owner != g) ? NULL : g_list_find (g->widgets, w);
}
/* --------------------------------------------------------------------------------------------- */
/** Find the widget with the given id */
Widget *
dlg_find_by_id (const WDialog * h, unsigned long id)
{
GList *w;
w = g_list_find_custom (CONST_GROUP (h)->widgets, GUINT_TO_POINTER (id), dlg_find_widget_by_id);
return w != NULL ? WIDGET (w->data) : NULL;
}
/* --------------------------------------------------------------------------------------------- */
void

View File

@ -137,11 +137,6 @@ void dlg_default_repaint (WDialog * h);
void dlg_erase (WDialog * h);
void dlg_stop (WDialog * h);
/* Widget selection */
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);
/* Redraw all dialogs */
void do_refresh (void);

View File

@ -148,6 +148,102 @@ group_send_broadcast_msg_custom (WGroup * g, widget_msg_t msg, gboolean reverse,
while (first != p);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Default group callback function to find widget in the group.
*
* @param w WGroup object
* @param what widget to find
*
* @return holder of @what if found, NULL otherwise
*/
static GList *
group_default_find (const Widget * w, const Widget * what)
{
GList *w0;
w0 = widget_default_find (w, what);
if (w0 == NULL)
{
GList *iter;
for (iter = GROUP (w)->widgets; iter != NULL; iter = g_list_next (iter))
{
w0 = widget_find (WIDGET (iter->data), what);
if (w0 != NULL)
break;
}
}
return w0;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Default group callback function to find widget in the group using widget callback.
*
* @param w WGroup object
* @param cb widget callback
*
* @return widget object if found, NULL otherwise
*/
static Widget *
group_default_find_by_type (const Widget * w, widget_cb_fn cb)
{
Widget *w0;
w0 = widget_default_find_by_type (w, cb);
if (w0 == NULL)
{
GList *iter;
for (iter = GROUP (w)->widgets; iter != NULL; iter = g_list_next (iter))
{
w0 = widget_find_by_type (WIDGET (iter->data), cb);
if (w0 != NULL)
break;
}
}
return w0;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Default group callback function to find widget by widget ID in the group.
*
* @param w WGroup object
* @param id widget ID
*
* @return widget object if widget with specified id is found in group, NULL otherwise
*/
static Widget *
group_default_find_by_id (const Widget * w, unsigned long id)
{
Widget *w0;
w0 = widget_default_find_by_id (w, id);
if (w0 == NULL)
{
GList *iter;
for (iter = GROUP (w)->widgets; iter != NULL; iter = g_list_next (iter))
{
w0 = widget_find_by_id (WIDGET (iter->data), id);
if (w0 != NULL)
break;
}
}
return w0;
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
@ -172,6 +268,10 @@ group_init (WGroup * g, int y1, int x1, int lines, int cols, widget_cb_fn callba
widget_init (w, y1, x1, lines, cols, callback != NULL ? callback : group_default_callback,
mouse_callback);
w->find = group_default_find;
w->find_by_type = group_default_find_by_type;
w->find_by_id = group_default_find_by_id;
}
/* --------------------------------------------------------------------------------------------- */
@ -398,7 +498,7 @@ group_select_widget_by_id (const WGroup * g, unsigned long id)
{
Widget *w;
w = dlg_find_by_id (DIALOG (g), id);
w = widget_find_by_id (CONST_WIDGET (g), id);
if (w != NULL)
widget_select (w);
}

View File

@ -257,7 +257,7 @@ menubar_draw (const WMenuBar * menubar)
static void
menubar_remove (WMenuBar * menubar)
{
WGroup *g;
Widget *g;
if (!menubar->is_dropped)
return;
@ -266,15 +266,15 @@ menubar_remove (WMenuBar * menubar)
of overlapped widgets. This is useful in multi-window editor.
In general, menubar should be a special object, not an ordinary widget
in the current dialog. */
g = WIDGET (menubar)->owner;
g->current = g_list_find (g->widgets, dlg_find_by_id (DIALOG (g), menubar->previous_widget));
g = WIDGET (WIDGET (menubar)->owner);
GROUP (g)->current = widget_find (g, widget_find_by_id (g, menubar->previous_widget));
menubar->is_dropped = FALSE;
do_refresh ();
menubar->is_dropped = TRUE;
/* restore current widget */
g->current = g_list_find (g->widgets, menubar);
GROUP (g)->current = widget_find (g, WIDGET (menubar));
}
/* --------------------------------------------------------------------------------------------- */
@ -1039,7 +1039,7 @@ menubar_arrange (WMenuBar * menubar)
WMenuBar *
find_menubar (const WDialog * h)
{
return MENUBAR (find_widget_type (h, menubar_callback));
return MENUBAR (widget_find_by_type (CONST_WIDGET (h), menubar_callback));
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -108,7 +108,7 @@ widget_focus (Widget * w)
if (g->current == NULL || !widget_get_state (WIDGET (g->current->data), WST_FOCUSED))
{
widget_do_focus (w, TRUE);
g->current = dlg_find (DIALOG (g), w);
g->current = widget_find (WIDGET (g), w);
}
}
else if (!widget_get_state (w, WST_FOCUSED))
@ -290,6 +290,10 @@ widget_init (Widget * w, int y, int x, int lines, int cols,
w->options = WOP_DEFAULT;
w->state = WST_DEFAULT;
w->find = widget_default_find;
w->find_by_type = widget_default_find_by_type;
w->find_by_id = widget_default_find_by_id;
}
/* --------------------------------------------------------------------------------------------- */
@ -599,19 +603,19 @@ widget_replace (Widget * old_w, Widget * new_w)
void
widget_select (Widget * w)
{
WDialog *h;
WGroup *g;
if (!widget_get_options (w, WOP_SELECTABLE))
return;
h = DIALOG (w->owner);
if (h != NULL)
g = GROUP (w->owner);
if (g != NULL)
{
if (widget_get_options (w, WOP_TOP_SELECT))
{
GList *l;
l = dlg_find (h, w);
l = widget_find (WIDGET (g), w);
widget_reorder (l, TRUE);
}
@ -627,7 +631,7 @@ widget_select (Widget * w)
void
widget_set_bottom (Widget * w)
{
widget_reorder (dlg_find (DIALOG (w->owner), w), FALSE);
widget_reorder (widget_find (WIDGET (w->owner), w), FALSE);
}
/* --------------------------------------------------------------------------------------------- */
@ -646,6 +650,56 @@ widget_overlapped (const Widget * a, const Widget * b)
|| (a->x >= b->x + b->cols) || (b->y >= a->y + a->lines) || (a->y >= b->y + b->lines));
}
/* --------------------------------------------------------------------------------------------- */
/**
* Default callback function to find widget.
*
* @param w widget
* @param what widget to find
*
* @return holder of @what if widget is @what, NULL otherwise
*/
GList *
widget_default_find (const Widget * w, const Widget * what)
{
return (w != what
|| w->owner == NULL) ? NULL : g_list_find (CONST_GROUP (w->owner)->widgets, what);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Default callback function to find widget by widget type using widget callback.
*
* @param w widget
* @param cb widget callback
*
* @return @w if widget callback is @cb, NULL otherwise
*/
Widget *
widget_default_find_by_type (const Widget * w, widget_cb_fn cb)
{
return (w->callback == cb ? WIDGET (w) : NULL);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Default callback function to find widget by widget ID.
*
* @param w widget
* @param id widget ID
*
* @return @w if widget id is equal to @id, NULL otherwise
*/
Widget *
widget_default_find_by_id (const Widget * w, unsigned long id)
{
return (w->id == id ? WIDGET (w) : NULL);
}
/* --------------------------------------------------------------------------------------------- */
/* get mouse pointer location within widget */

View File

@ -146,6 +146,10 @@ struct Widget
mouse_msg_t last_msg; /* The previous event type processed. */
int last_buttons_down;
} mouse;
GList *(*find) (const Widget * w, const Widget * what);
Widget *(*find_by_type) (const Widget * w, widget_cb_fn cb);
Widget *(*find_by_id) (const Widget * w, unsigned long id);
};
/* structure for label (caption) with hotkey, if original text does not contain
@ -197,6 +201,10 @@ void widget_replace (Widget * old, Widget * new);
void widget_select (Widget * w);
void widget_set_bottom (Widget * w);
GList *widget_default_find (const Widget * w, const Widget * what);
Widget *widget_default_find_by_type (const Widget * w, widget_cb_fn cb);
Widget *widget_default_find_by_id (const Widget * w, unsigned long id);
/* get mouse pointer location within widget */
Gpm_Event mouse_get_local (const Gpm_Event * global, const Widget * w);
gboolean mouse_global_in_widget (const Gpm_Event * event, const Widget * w);
@ -251,4 +259,54 @@ widget_get_state (const Widget * w, widget_state_t state)
/* --------------------------------------------------------------------------------------------- */
/**
* Find widget.
*
* @param w widget
* @param what widget to find
*
* @return result of @w->find()
*/
static inline GList *
widget_find (const Widget * w, const Widget * what)
{
return w->find (w, what);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Find widget by widget type using widget callback.
*
* @param w widget
* @param cb widget callback
*
* @return result of @w->find_by_type()
*/
static inline Widget *
widget_find_by_type (const Widget * w, widget_cb_fn cb)
{
return w->find_by_type (w, cb);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Find widget by widget ID.
*
* @param w widget
* @param id widget ID
*
* @return result of @w->find_by_id()
*/
static inline Widget *
widget_find_by_id (const Widget * w, unsigned long id)
{
return w->find_by_id (w, id);
}
/* --------------------------------------------------------------------------------------------- */
#endif /* MC__WIDGET_INTERNAL_H */

View File

@ -3394,7 +3394,7 @@ dview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
return dview_execute_cmd (NULL, parm);
case MSG_VALIDATE:
dview = (WDiff *) find_widget_type (h, dview_callback);
dview = (WDiff *) widget_find_by_type (CONST_WIDGET (h), dview_callback);
/* don't stop the dialog before final decision */
widget_set_state (w, WST_ACTIVE, TRUE);
if (dview_ok_to_exit (dview))
@ -3417,7 +3417,7 @@ dview_get_title (const WDialog * h, size_t len)
size_t len1;
GString *title;
dview = (const WDiff *) find_widget_type (h, dview_callback);
dview = (const WDiff *) widget_find_by_type (CONST_WIDGET (h), dview_callback);
len1 = (len - str_term_width1 (_("Diff:")) - strlen (modified) - 3) / 2;
title = g_string_sized_new (len);

View File

@ -156,7 +156,7 @@ edit_save_mode_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm
{
Widget *ww;
ww = dlg_find_by_id (DIALOG (w), edit_save_mode_input_id);
ww = widget_find_by_id (w, edit_save_mode_input_id);
widget_disable (ww, RADIO (sender)->sel != 2);
return MSG_HANDLED;
}

View File

@ -1272,7 +1272,7 @@ find_editor (const WDialog * h)
if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))
return (WEdit *) g->current->data;
return (WEdit *) find_widget_type (h, edit_callback);
return (WEdit *) widget_find_by_type (CONST_WIDGET (h), edit_callback);
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -136,7 +136,7 @@ configure_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, voi
Widget *ww;
/* input line */
ww = dlg_find_by_id (DIALOG (w), configure_time_out_id);
ww = widget_find_by_id (w, configure_time_out_id);
widget_disable (ww, not_single);
return MSG_HANDLED;
@ -274,8 +274,6 @@ sel_skin_button (WButton * button, int action)
static cb_ret_t
panel_listing_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
{
WDialog *h = DIALOG (w);
switch (msg)
{
case MSG_NOTIFY:
@ -284,10 +282,10 @@ panel_listing_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
WCheck *ch;
WInput *in1, *in2, *in3;
in1 = INPUT (dlg_find_by_id (h, panel_user_format_id));
in2 = INPUT (dlg_find_by_id (h, panel_brief_cols_id));
ch = CHECK (dlg_find_by_id (h, mini_user_status_id));
in3 = INPUT (dlg_find_by_id (h, mini_user_format_id));
in1 = INPUT (widget_find_by_id (w, panel_user_format_id));
in2 = INPUT (widget_find_by_id (w, panel_brief_cols_id));
ch = CHECK (widget_find_by_id (w, mini_user_status_id));
in3 = INPUT (widget_find_by_id (w, mini_user_format_id));
if (!ch->state)
input_assign_text (in3, status_format[RADIO (sender)->sel]);
@ -303,7 +301,7 @@ panel_listing_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
{
WInput *in;
in = INPUT (dlg_find_by_id (h, mini_user_format_id));
in = INPUT (widget_find_by_id (w, mini_user_format_id));
if (CHECK (sender)->state)
{
@ -314,7 +312,7 @@ panel_listing_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
{
WRadio *r;
r = RADIO (dlg_find_by_id (h, panel_list_formats_id));
r = RADIO (widget_find_by_id (w, panel_list_formats_id));
widget_disable (WIDGET (in), TRUE);
input_assign_text (in, status_format[r->sel]);
}
@ -407,7 +405,7 @@ confvfs_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void
Widget *wi;
/* input */
wi = dlg_find_by_id (DIALOG (w), ftpfs_proxy_host_id);
wi = widget_find_by_id (w, ftpfs_proxy_host_id);
widget_disable (wi, not_use);
return MSG_HANDLED;
}

View File

@ -1332,9 +1332,9 @@ sync_tree (const vfs_path_t * vpath)
/* --------------------------------------------------------------------------------------------- */
WTree *
find_tree (WDialog * h)
find_tree (const WDialog * h)
{
return (WTree *) find_widget_type (h, tree_callback);
return (WTree *) widget_find_by_type (CONST_WIDGET (h), tree_callback);
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -29,7 +29,7 @@ const vfs_path_t *tree_selected_name (const WTree * tree);
void sync_tree (const vfs_path_t * vpath);
WTree *find_tree (WDialog * h);
WTree *find_tree (const WDialog * h);
/*** inline functions ****************************************************************************/
#endif /* MC__TREE_H */

View File

@ -784,9 +784,9 @@ mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
return mcview_execute_cmd (NULL, parm);
case MSG_VALIDATE:
view = (WView *) find_widget_type (h, mcview_callback);
view = (WView *) widget_find_by_type (w, mcview_callback);
/* don't stop the dialog before final decision */
widget_set_state (WIDGET (h), WST_ACTIVE, TRUE);
widget_set_state (w, WST_ACTIVE, TRUE);
if (mcview_ok_to_quit (view))
dlg_stop (h);
else

View File

@ -375,12 +375,14 @@ mcview_eol (WView * view, off_t current)
char *
mcview_get_title (const WDialog * h, size_t len)
{
const WView *view = (const WView *) find_widget_type (h, mcview_callback);
const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
const WView *view;
const char *modified;
const char *file_label;
const char *view_filename;
char *ret_str;
view = (const WView *) widget_find_by_type (CONST_WIDGET (h), mcview_callback);
modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
view_filename = vfs_path_as_str (view->filename_vpath);
len -= 4;

View File

@ -18,7 +18,8 @@ endif
TESTS = \
complete_engine \
hotkey_equal \
group_init_destroy
group_init_destroy \
widget_find_by_id
check_PROGRAMS = $(TESTS)
@ -30,3 +31,6 @@ hotkey_equal_SOURCES = \
group_init_destroy_SOURCES = \
group_init_destroy.c
widget_find_by_id_SOURCES = \
widget_find_by_id.c

View File

@ -0,0 +1,117 @@
/*
libmc - checks for search widget with requested ID
Copyright (C) 2020
The Free Software Foundation, Inc.
Written by:
Andrew Borodin <aborodin@vmail.ru>, 2020
This file is part of the Midnight Commander.
The Midnight Commander is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
The Midnight Commander is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define TEST_SUITE_NAME "lib/widget"
#include <config.h>
#include <check.h>
#include "lib/widget.h"
/* --------------------------------------------------------------------------------------------- */
/* *INDENT-OFF* */
START_TEST (test_widget_find_by_id)
/* *INDENT-ON* */
{
WGroup *g, *g0;
Widget *w0;
g = g_new0 (WGroup, 1);
group_init (g, 0, 0, 20, 20, NULL, NULL); /* ID = 0 */
g0 = g_new0 (WGroup, 1);
group_init (g0, 0, 0, 10, 10, NULL, NULL); /* ID = 1 */
group_add_widget (g, g0);
w0 = g_new0 (Widget, 1);
widget_init (w0, 0, 0, 5, 5, widget_default_callback, NULL); /* ID = 2 */
group_add_widget (g0, w0);
w0 = g_new0 (Widget, 1);
widget_init (w0, 5, 5, 5, 5, widget_default_callback, NULL); /* ID = 3 */
group_add_widget (g0, w0);
g0 = g_new0 (WGroup, 1);
group_init (g0, 10, 10, 10, 10, NULL, NULL); /* ID = 4 */
group_add_widget (g, g0);
w0 = g_new0 (Widget, 1);
widget_init (w0, 10, 10, 5, 5, widget_default_callback, NULL); /* ID = 5 */
group_add_widget (g0, w0);
w0 = g_new0 (Widget, 1);
widget_init (w0, 15, 15, 5, 5, widget_default_callback, NULL); /* ID = 6 */
group_add_widget (g0, w0);
w0 = g_new0 (Widget, 1);
widget_init (w0, 5, 5, 10, 10, widget_default_callback, NULL); /* ID = 7 */
group_add_widget (g, w0);
w0 = WIDGET (g);
fail_unless (widget_find_by_id (w0, 0) != NULL, "Not found ID=0");
fail_unless (widget_find_by_id (w0, 1) != NULL, "Not found ID=1");
fail_unless (widget_find_by_id (w0, 2) != NULL, "Not found ID=2");
fail_unless (widget_find_by_id (w0, 3) != NULL, "Not found ID=3");
fail_unless (widget_find_by_id (w0, 4) != NULL, "Not found ID=4");
fail_unless (widget_find_by_id (w0, 5) != NULL, "Not found ID=5");
fail_unless (widget_find_by_id (w0, 6) != NULL, "Not found ID=6");
fail_unless (widget_find_by_id (w0, 7) != NULL, "Not found ID=7");
fail_unless (widget_find_by_id (w0, 8) == NULL, "Found ID=8");
send_message (g, NULL, MSG_INIT, 0, NULL);
widget_destroy (w0);
}
/* *INDENT-OFF* */
END_TEST
/* *INDENT-ON* */
/* --------------------------------------------------------------------------------------------- */
int
main (void)
{
int number_failed;
Suite *s = suite_create (TEST_SUITE_NAME);
TCase *tc_core = tcase_create ("Core");
SRunner *sr;
/* Add new tests here: *************** */
tcase_add_test (tc_core, test_widget_find_by_id);
/* *********************************** */
suite_add_tcase (s, tc_core);
sr = srunner_create (s);
srunner_set_log (sr, "widget_find_by_id.log");
srunner_run_all (sr, CK_NORMAL);
number_failed = srunner_ntests_failed (sr);
srunner_free (sr);
return (number_failed == 0) ? 0 : 1;
}
/* --------------------------------------------------------------------------------------------- */