1
2 /** \file widget-common.h
3 * \brief Header: shared stuff of widgets
4 */
5
6 #ifndef MC__WIDGET_COMMON_H
7 #define MC__WIDGET_COMMON_H
8
9 #include "lib/keybind.h" // global_keymap_t
10 #include "lib/tty/mouse.h"
11 #include "lib/widget/mouse.h" // mouse_msg_t, mouse_event_t
12
13 /*** typedefs(not structures) and defined constants **********************************************/
14
15 #define WIDGET(x) ((Widget *) (x))
16 #define CONST_WIDGET(x) ((const Widget *) (x))
17
18 #define widget_gotoyx(w, _y, _x) \
19 tty_gotoyx (CONST_WIDGET (w)->rect.y + (_y), CONST_WIDGET (w)->rect.x + (_x))
20 /* Sets/clear the specified flag in the options field */
21 #define widget_want_cursor(w, i) widget_set_options (w, WOP_WANT_CURSOR, i)
22 #define widget_want_hotkey(w, i) widget_set_options (w, WOP_WANT_HOTKEY, i)
23 #define widget_want_tab(w, i) widget_set_options (w, WOP_WANT_TAB, i)
24 #define widget_idle(w, i) widget_set_state (w, WST_IDLE, i)
25 #define widget_disable(w, i) widget_set_state (w, WST_DISABLED, i)
26
27 /*** enums ***************************************************************************************/
28
29 /* Widget messages */
30 typedef enum
31 {
32 MSG_INIT = 0, // Initialize widget
33 MSG_FOCUS, // Draw widget in focused state or widget has got focus
34 MSG_UNFOCUS, // Draw widget in unfocused state or widget has been unfocused
35 MSG_CHANGED_FOCUS, // Notification to owner about focus state change
36 MSG_ENABLE, // Change state to enabled
37 MSG_DISABLE, // Change state to disabled
38 MSG_DRAW, // Draw widget on screen
39 MSG_KEY, // Sent to widgets on key press
40 MSG_HOTKEY, // Sent to widget to catch preprocess key
41 MSG_HOTKEY_HANDLED, // A widget has got the hotkey
42 MSG_UNHANDLED_KEY, // Key that no widget handled
43 MSG_POST_KEY, // The key has been handled
44 MSG_ACTION, // Send to widget to handle command
45 MSG_NOTIFY, /* Typically sent to dialog to inform it of state-change
46 * of listboxes, check- and radiobuttons. */
47 MSG_CURSOR, // Sent to widget to position the cursor
48 MSG_IDLE, // The idle state is active
49 MSG_RESIZE, // Screen size has changed
50 MSG_VALIDATE, // Dialog is to be closed
51 MSG_END, // Shut down dialog
52 MSG_DESTROY // Sent to widget at destruction time
53 } widget_msg_t;
54
55 /* Widgets are expected to answer to the following messages:
56 MSG_FOCUS: MSG_HANDLED if the accept the focus, MSG_NOT_HANDLED if they do not.
57 MSG_UNFOCUS: MSG_HANDLED if they accept to release the focus, MSG_NOT_HANDLED if they don't.
58 MSG_KEY: MSG_HANDLED if they actually used the key, MSG_NOT_HANDLED if not.
59 MSG_HOTKEY: MSG_HANDLED if they actually used the key, MSG_NOT_HANDLED if not.
60 */
61
62 typedef enum
63 {
64 MSG_NOT_HANDLED = 0,
65 MSG_HANDLED = 1
66 } cb_ret_t;
67
68 /* Widget options */
69 typedef enum
70 {
71 WOP_DEFAULT = (0 << 0),
72 WOP_WANT_HOTKEY = (1 << 0),
73 WOP_WANT_CURSOR = (1 << 1),
74 WOP_WANT_TAB = (1 << 2), // Should the tab key be sent to the dialog?
75 WOP_IS_INPUT = (1 << 3),
76 WOP_SELECTABLE = (1 << 4),
77 WOP_TOP_SELECT = (1 << 5)
78 } widget_options_t;
79
80 /* Widget state */
81 typedef enum
82 {
83 WST_DEFAULT = (0 << 0),
84 WST_VISIBLE = (1 << 0), // Widget is visible
85 WST_DISABLED = (1 << 1), // Widget cannot be selected
86 WST_IDLE = (1 << 2),
87 WST_MODAL = (1 << 3), // Widget (dialog) is modal
88 WST_FOCUSED = (1 << 4),
89
90 WST_CONSTRUCT = (1 << 15), // Widget has been constructed but not run yet
91 WST_ACTIVE = (1 << 16), // Dialog is visible and active
92 WST_SUSPENDED = (1 << 17), // Dialog is suspended
93 WST_CLOSED = (1 << 18) // Dialog is closed
94 } widget_state_t;
95
96 /* Flags for widget repositioning on dialog resize */
97 typedef enum
98 {
99 WPOS_FULLSCREEN = (1 << 0), // widget occupies the whole screen
100 WPOS_CENTER_HORZ = (1 << 1), // center widget in horizontal
101 WPOS_CENTER_VERT = (1 << 2), // center widget in vertical
102 WPOS_CENTER = WPOS_CENTER_HORZ | WPOS_CENTER_VERT, // center widget
103 WPOS_TRYUP = (1 << 3), // try to move two lines up the widget
104 WPOS_KEEP_LEFT = (1 << 4), // keep widget distance to left border of dialog
105 WPOS_KEEP_RIGHT = (1 << 5), // keep widget distance to right border of dialog
106 WPOS_KEEP_TOP = (1 << 6), // keep widget distance to top border of dialog
107 WPOS_KEEP_BOTTOM = (1 << 7), // keep widget distance to bottom border of dialog
108 WPOS_KEEP_HORZ = WPOS_KEEP_LEFT | WPOS_KEEP_RIGHT,
109 WPOS_KEEP_VERT = WPOS_KEEP_TOP | WPOS_KEEP_BOTTOM,
110 WPOS_KEEP_ALL = WPOS_KEEP_HORZ | WPOS_KEEP_VERT,
111 WPOS_KEEP_DEFAULT = WPOS_KEEP_LEFT | WPOS_KEEP_TOP
112 } widget_pos_flags_t;
113 /* NOTES:
114 * If WPOS_FULLSCREEN is set then all other position flags are ignored.
115 * If WPOS_CENTER_HORZ flag is used, other horizontal flags (WPOS_KEEP_LEFT, WPOS_KEEP_RIGHT,
116 * and WPOS_KEEP_HORZ) are ignored.
117 * If WPOS_CENTER_VERT flag is used, other horizontal flags (WPOS_KEEP_TOP, WPOS_KEEP_BOTTOM,
118 * and WPOS_KEEP_VERT) are ignored.
119 */
120
121 /*** structures declarations (and typedefs of structures)*****************************************/
122
123 /* Widget callback */
124 typedef cb_ret_t (*widget_cb_fn) (Widget *widget, Widget *sender, widget_msg_t msg, int parm,
125 void *data);
126 /* Widget mouse callback */
127 typedef void (*widget_mouse_cb_fn) (Widget *w, mouse_msg_t msg, mouse_event_t *event);
128 /* translate mouse event and process it */
129 typedef int (*widget_mouse_handle_fn) (Widget *w, Gpm_Event *event);
130
131 /* Every Widget must have this as its first element */
132 struct Widget
133 {
134 WRect rect; // position and size
135 /* ATTENTION! For groups, don't change @rect members directly to avoid
136 incorrect reposion and resize of group members. */
137 widget_pos_flags_t pos_flags; // repositioning flags
138 widget_options_t options;
139 widget_state_t state;
140 unsigned long id; // uniq widget ID
141 widget_cb_fn callback;
142 widget_mouse_cb_fn mouse_callback;
143 WGroup *owner;
144
145 // Key-related fields
146 const global_keymap_t *keymap; // main keymap
147 const global_keymap_t *ext_keymap; // extended keymap
148 gboolean ext_mode; // use keymap or ext_keymap
149
150 // Mouse-related fields.
151 widget_mouse_handle_fn mouse_handler;
152 struct
153 {
154 // Public members:
155 gboolean
156 forced_capture; // Overrides the 'capture' member. Set explicitly by the programmer.
157
158 // Implementation details:
159 gboolean capture; // Whether the widget "owns" the mouse.
160 mouse_msg_t last_msg; // The previous event type processed.
161 int last_buttons_down;
162 } mouse;
163
164 void (*make_global) (Widget *w, const WRect *delta);
165 void (*make_local) (Widget *w, const WRect *delta);
166
167 GList *(*find) (const Widget *w, const Widget *what);
168 Widget *(*find_by_type) (const Widget *w, widget_cb_fn cb);
169 Widget *(*find_by_id) (const Widget *w, unsigned long id);
170
171 cb_ret_t (*set_state) (Widget *w, widget_state_t state, gboolean enable);
172 void (*destroy) (Widget *w);
173
174 const int *(*get_colors) (const Widget *w);
175 };
176
177 /* structure for label (caption) with hotkey, if original text does not contain
178 * hotkey, only start is valid and is equal to original text
179 * hotkey is defined as char*, but mc support only singlebyte hotkey
180 */
181 typedef struct hotkey_t
182 {
183 char *start; // never NULL
184 char *hotkey; // can be NULL
185 char *end; // can be NULL
186 } hotkey_t;
187
188 /*** global variables defined in .c file *********************************************************/
189
190 /*** declarations of public functions ************************************************************/
191
192 /* create hotkey from text */
193 hotkey_t hotkey_new (const char *text);
194 /* release hotkey, free all mebers of hotkey_t */
195 void hotkey_free (const hotkey_t hotkey);
196 /* return width on terminal of hotkey */
197 int hotkey_width (const hotkey_t hotkey);
198 /* compare two hotkeys */
199 gboolean hotkey_equal (const hotkey_t hotkey1, const hotkey_t hotkey2);
200 /* draw hotkey of widget */
201 void hotkey_draw (const Widget *w, const hotkey_t hotkey, gboolean focused);
202 /* get text of hotkey */
203 char *hotkey_get_text (const hotkey_t hotkey);
204
205 /* widget initialization */
206 void widget_init (Widget *w, const WRect *r, widget_cb_fn callback,
207 widget_mouse_cb_fn mouse_callback);
208 /* Default callback for widgets */
209 cb_ret_t widget_default_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm,
210 void *data);
211 void widget_set_options (Widget *w, widget_options_t options, gboolean enable);
212 void widget_adjust_position (widget_pos_flags_t pos_flags, WRect *r);
213 void widget_set_size (Widget *w, int y, int x, int lines, int cols);
214 void widget_set_size_rect (Widget *w, WRect *r);
215 /* select color for widget in dependence of state */
216 void widget_selectcolor (const Widget *w, gboolean focused, gboolean hotkey);
217 cb_ret_t widget_draw (Widget *w);
218 void widget_erase (Widget *w);
219 void widget_set_visibility (Widget *w, gboolean make_visible);
220 gboolean widget_is_active (const void *w);
221 void widget_replace (Widget *old, Widget *new);
222 gboolean widget_is_focusable (const Widget *w);
223 void widget_select (Widget *w);
224 void widget_set_bottom (Widget *w);
225
226 long widget_lookup_key (Widget *w, int key);
227
228 void widget_default_make_global (Widget *w, const WRect *delta);
229 void widget_default_make_local (Widget *w, const WRect *delta);
230
231 GList *widget_default_find (const Widget *w, const Widget *what);
232 Widget *widget_default_find_by_type (const Widget *w, widget_cb_fn cb);
233 Widget *widget_default_find_by_id (const Widget *w, unsigned long id);
234
235 cb_ret_t widget_default_set_state (Widget *w, widget_state_t state, gboolean enable);
236
237 void widget_default_destroy (Widget *w);
238
239 /* get mouse pointer location within widget */
240 Gpm_Event mouse_get_local (const Gpm_Event *global, const Widget *w);
241 gboolean mouse_global_in_widget (const Gpm_Event *event, const Widget *w);
242
243 /* --------------------------------------------------------------------------------------------- */
244 /*** inline functions ****************************************************************************/
245 /* --------------------------------------------------------------------------------------------- */
246
247 static inline cb_ret_t
248 send_message (void *w, void *sender, widget_msg_t msg, int parm, void *data)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
249 {
250 cb_ret_t ret = MSG_NOT_HANDLED;
251
252 #if 1
253 if (w != NULL) // This must be always true, but...
254 #endif
255 ret = WIDGET (w)->callback (WIDGET (w), WIDGET (sender), msg, parm, data);
256
257 return ret;
258 }
259
260 /* --------------------------------------------------------------------------------------------- */
261 /**
262 * Check whether one or several option flags are set or not.
263 * @param w widget
264 * @param options widget option flags
265 *
266 * @return TRUE if all requested option flags are set, FALSE otherwise.
267 */
268
269 static inline gboolean
270 widget_get_options (const Widget *w, widget_options_t options)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
271 {
272 return ((w->options & options) == options);
273 }
274
275 /* --------------------------------------------------------------------------------------------- */
276
277 /**
278 * Check whether one or several state flags are set or not.
279 * @param w widget
280 * @param state widget state flags
281 *
282 * @return TRUE if all requested state flags are set, FALSE otherwise.
283 */
284
285 static inline gboolean
286 widget_get_state (const Widget *w, widget_state_t state)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
287 {
288 return ((w->state & state) == state);
289 }
290
291 /* --------------------------------------------------------------------------------------------- */
292
293 /**
294 * Convert widget coordinates from local (relative to owner) to global (relative to screen).
295 *
296 * @param w widget
297 */
298
299 static inline void
300 widget_make_global (Widget *w)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
301 {
302 w->make_global (w, NULL);
303 }
304
305 /* --------------------------------------------------------------------------------------------- */
306
307 /**
308 * Convert widget coordinates from global (relative to screen) to local (relative to owner).
309 *
310 * @param w widget
311 */
312
313 static inline void
314 widget_make_local (Widget *w)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
315 {
316 w->make_local (w, NULL);
317 }
318
319 /* --------------------------------------------------------------------------------------------- */
320
321 /**
322 * Find widget.
323 *
324 * @param w widget
325 * @param what widget to find
326 *
327 * @return result of @w->find()
328 */
329
330 static inline GList *
331 widget_find (const Widget *w, const Widget *what)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
332 {
333 return w->find (w, what);
334 }
335
336 /* --------------------------------------------------------------------------------------------- */
337
338 /**
339 * Find widget by widget type using widget callback.
340 *
341 * @param w widget
342 * @param cb widget callback
343 *
344 * @return result of @w->find_by_type()
345 */
346
347 static inline Widget *
348 widget_find_by_type (const Widget *w, widget_cb_fn cb)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
349 {
350 return w->find_by_type (w, cb);
351 }
352
353 /* --------------------------------------------------------------------------------------------- */
354 /**
355 * Find widget by widget ID.
356 *
357 * @param w widget
358 * @param id widget ID
359 *
360 * @return result of @w->find_by_id()
361 */
362
363 static inline Widget *
364 widget_find_by_id (const Widget *w, unsigned long id)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
365 {
366 return w->find_by_id (w, id);
367 }
368
369 /* --------------------------------------------------------------------------------------------- */
370 /**
371 * Modify state of widget.
372 *
373 * @param w widget
374 * @param state widget state flag to modify
375 * @param enable specifies whether to turn the flag on (TRUE) or off (FALSE).
376 * Only one flag per call can be modified.
377 * @return MSG_HANDLED if set was handled successfully, MSG_NOT_HANDLED otherwise.
378 */
379
380 static inline cb_ret_t
381 widget_set_state (Widget *w, widget_state_t state, gboolean enable)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
382 {
383 return w->set_state (w, state, enable);
384 }
385
386 /* --------------------------------------------------------------------------------------------- */
387 /**
388 * Destroy widget.
389 *
390 * @param w widget
391 */
392
393 static inline void
394 widget_destroy (Widget *w)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
395 {
396 w->destroy (w);
397 }
398
399 /* --------------------------------------------------------------------------------------------- */
400
401 /**
402 * Get color colors of widget.
403 *
404 * @param w widget
405 * @return color colors
406 */
407 static inline const int *
408 widget_get_colors (const Widget *w)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
409 {
410 return w->get_colors (w);
411 }
412
413 /* --------------------------------------------------------------------------------------------- */
414 /**
415 * Update cursor position in the specified widget.
416 *
417 * @param w widget
418 *
419 * @return TRUE if cursor was updated successfully, FALSE otherwise
420 */
421
422 static inline gboolean
423 widget_update_cursor (Widget *w)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
424 {
425 return (send_message (w, NULL, MSG_CURSOR, 0, NULL) == MSG_HANDLED);
426 }
427
428 /* --------------------------------------------------------------------------------------------- */
429
430 static inline void
431 widget_show (Widget *w)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
432 {
433 widget_set_visibility (w, TRUE);
434 }
435
436 /* --------------------------------------------------------------------------------------------- */
437
438 static inline void
439 widget_hide (Widget *w)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
440 {
441 widget_set_visibility (w, FALSE);
442 }
443
444 /* --------------------------------------------------------------------------------------------- */
445 /**
446 * Check whether two widgets are overlapped or not.
447 * @param a 1st widget
448 * @param b 2nd widget
449 *
450 * @return TRUE if widgets are overlapped, FALSE otherwise.
451 */
452
453 static inline gboolean
454 widget_overlapped (const Widget *a, const Widget *b)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
455 {
456 return rects_are_overlapped (&a->rect, &b->rect);
457 }
458
459 /* --------------------------------------------------------------------------------------------- */
460
461 #endif