Move widget add/del API from WDialog to WGroup.
[midnight-commander.git] / lib / widget / group.c
blob73a78db65b747de2482d2199df6a1a3624b1bf4e
1 /*
2 Widget group features module for the Midnight Commander
4 Copyright (C) 2020
5 The Free Software Foundation, Inc.
7 Written by:
8 Andrew Borodin <aborodin@vmail.ru>, 2020
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /** \file group.c
27 * \brief Source: widget group features module
30 #include <config.h>
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <string.h>
36 #include "lib/global.h"
38 #include "lib/widget.h"
40 /*** global variables ****************************************************************************/
42 /*** file scope macro definitions ****************************************************************/
44 /*** file scope type declarations ****************************************************************/
46 /*** file scope variables ************************************************************************/
48 /* --------------------------------------------------------------------------------------------- */
49 /*** file scope functions ************************************************************************/
50 /* --------------------------------------------------------------------------------------------- */
52 static GList *
53 group_get_next_or_prev_of (GList * list, gboolean next)
55 GList *l = NULL;
57 if (list != NULL)
59 WGroup *owner = WIDGET (list->data)->owner;
61 if (owner != NULL)
63 if (next)
65 l = g_list_next (list);
66 if (l == NULL)
67 l = owner->widgets;
69 else
71 l = g_list_previous (list);
72 if (l == NULL)
73 l = g_list_last (owner->widgets);
78 return l;
81 /* --------------------------------------------------------------------------------------------- */
83 static void
84 group_select_next_or_prev (WGroup * g, gboolean next)
86 if (g->widgets != NULL && g->current != NULL)
88 GList *l = g->current;
89 Widget *w;
93 l = group_get_next_or_prev_of (l, next);
94 w = WIDGET (l->data);
96 while ((widget_get_state (w, WST_DISABLED) || !widget_get_options (w, WOP_SELECTABLE))
97 && l != g->current);
99 widget_select (l->data);
103 /* --------------------------------------------------------------------------------------------- */
104 /*** public functions ****************************************************************************/
105 /* --------------------------------------------------------------------------------------------- */
108 * Insert widget to group before specified widget with specified positioning.
109 * Make the inserted widget current.
111 * @param g WGroup object
112 * @param w widget to be added
113 * @pos positioning flags
114 * @param before add @w before this widget
116 * @return widget ID
119 unsigned long
120 group_add_widget_autopos (WGroup * g, void *w, widget_pos_flags_t pos_flags, const void *before)
122 Widget *wg = WIDGET (g);
123 Widget *ww = WIDGET (w);
124 GList *new_current;
126 /* Don't accept NULL widget. This shouldn't happen */
127 assert (ww != NULL);
129 if ((pos_flags & WPOS_CENTER_HORZ) != 0)
130 ww->x = (wg->cols - ww->cols) / 2;
131 ww->x += wg->x;
133 if ((pos_flags & WPOS_CENTER_VERT) != 0)
134 ww->y = (wg->lines - ww->lines) / 2;
135 ww->y += wg->y;
137 ww->owner = g;
138 ww->pos_flags = pos_flags;
139 ww->id = g->widget_id++;
141 if (g->widgets == NULL || before == NULL)
143 g->widgets = g_list_append (g->widgets, ww);
144 new_current = g_list_last (g->widgets);
146 else
148 GList *b;
150 b = g_list_find (g->widgets, before);
152 /* don't accept widget not from group. This shouldn't happen */
153 assert (b != NULL);
155 b = g_list_next (b);
156 g->widgets = g_list_insert_before (g->widgets, b, ww);
157 if (b != NULL)
158 new_current = g_list_previous (b);
159 else
160 new_current = g_list_last (g->widgets);
163 /* widget has been added at runtime */
164 if (widget_get_state (wg, WST_ACTIVE))
166 send_message (ww, NULL, MSG_INIT, 0, NULL);
167 widget_select (ww);
169 else
170 g->current = new_current;
172 return ww->id;
175 /* --------------------------------------------------------------------------------------------- */
178 * Delete widget from group.
180 * @param w Widget object
182 void
183 group_del_widget (void *w)
185 WGroup *g;
186 GList *d;
188 /* Don't accept NULL widget. This shouldn't happen */
189 assert (w != NULL);
191 g = WIDGET (w)->owner;
193 d = g_list_find (g->widgets, w);
194 if (d == g->current)
195 group_set_current_widget_next (g);
197 g->widgets = g_list_remove_link (g->widgets, d);
198 if (g->widgets == NULL)
199 g->current = NULL;
201 /* widget has been deleted at runtime */
202 if (widget_get_state (WIDGET (g), WST_ACTIVE))
204 dlg_draw (DIALOG (g)); /* FIXME */
205 group_select_current_widget (g);
209 /* --------------------------------------------------------------------------------------------- */
212 * Switch current widget to widget after current in group.
214 * @param g WGroup object
217 void
218 group_set_current_widget_next (WGroup * g)
220 g->current = group_get_next_or_prev_of (g->current, TRUE);
223 /* --------------------------------------------------------------------------------------------- */
225 * Switch current widget to widget before current in group.
227 * @param g WGroup object
230 void
231 group_set_current_widget_prev (WGroup * g)
233 g->current = group_get_next_or_prev_of (g->current, FALSE);
236 /* --------------------------------------------------------------------------------------------- */
238 * Get widget that is after specified widget in group.
240 * @param w widget holder
242 * @return widget that is after "w" or NULL if "w" is NULL or widget doesn't have owner
245 GList *
246 group_get_widget_next_of (GList * w)
248 return group_get_next_or_prev_of (w, TRUE);
251 /* --------------------------------------------------------------------------------------------- */
253 * Get widget that is before specified widget in group.
255 * @param w widget holder
257 * @return widget that is before "w" or NULL if "w" is NULL or widget doesn't have owner
260 GList *
261 group_get_widget_prev_of (GList * w)
263 return group_get_next_or_prev_of (w, FALSE);
266 /* --------------------------------------------------------------------------------------------- */
268 * Try to select next widget in the Z order.
270 * @param g WGroup object
273 void
274 group_select_next_widget (WGroup * g)
276 group_select_next_or_prev (g, TRUE);
279 /* --------------------------------------------------------------------------------------------- */
281 * Try to select previous widget in the Z order.
283 * @param g WGroup object
286 void
287 group_select_prev_widget (WGroup * g)
289 group_select_next_or_prev (g, FALSE);
292 /* --------------------------------------------------------------------------------------------- */
294 * Find the widget with the specified ID in the group and select it
296 * @param g WGroup object
297 * @param id widget ID
300 void
301 group_select_widget_by_id (const WGroup * g, unsigned long id)
303 Widget *w;
305 w = dlg_find_by_id (DIALOG (g), id);
306 if (w != NULL)
307 widget_select (w);
310 /* --------------------------------------------------------------------------------------------- */