summaryrefslogtreecommitdiffstats
path: root/lib/widget/widget-common.h
blob: 19acec11dde9f453c7f681a7edc4067d1c2c50d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
/** \file widget-common.h
 *  \brief Header: shared stuff of widgets
 */

#ifndef MC__WIDGET_COMMON_H
#define MC__WIDGET_COMMON_H

#include "lib/keybind.h"        /* global_keymap_t */
#include "lib/tty/mouse.h"
#include "lib/widget/mouse.h"   /* mouse_msg_t, mouse_event_t */

/*** typedefs(not structures) and defined constants **********************************************/

#define WIDGET(x) ((Widget *)(x))
#define CONST_WIDGET(x) ((const Widget *)(x))

#define widget_gotoyx(w, _y, _x) tty_gotoyx (CONST_WIDGET(w)->rect.y + (_y), CONST_WIDGET(w)->rect.x + (_x))
/* Sets/clear the specified flag in the options field */
#define widget_want_cursor(w,i) widget_set_options(w, WOP_WANT_CURSOR, i)
#define widget_want_hotkey(w,i) widget_set_options(w, WOP_WANT_HOTKEY, i)
#define widget_want_tab(w,i) widget_set_options(w, WOP_WANT_TAB, i)
#define widget_idle(w,i) widget_set_state(w, WST_IDLE, i)
#define widget_disable(w,i) widget_set_state(w, WST_DISABLED, i)

/*** enums ***************************************************************************************/

/* Widget messages */
typedef enum
{
    MSG_INIT = 0,               /* Initialize widget */
    MSG_FOCUS,                  /* Draw widget in focused state or widget has got focus */
    MSG_UNFOCUS,                /* Draw widget in unfocused state or widget has been unfocused */
    MSG_CHANGED_FOCUS,          /* Notification to owner about focus state change */
    MSG_ENABLE,                 /* Change state to enabled */
    MSG_DISABLE,                /* Change state to disabled */
    MSG_DRAW,                   /* Draw widget on screen */
    MSG_KEY,                    /* Sent to widgets on key press */
    MSG_HOTKEY,                 /* Sent to widget to catch preprocess key */
    MSG_HOTKEY_HANDLED,         /* A widget has got the hotkey */
    MSG_UNHANDLED_KEY,          /* Key that no widget handled */
    MSG_POST_KEY,               /* The key has been handled */
    MSG_ACTION,                 /* Send to widget to handle command */
    MSG_NOTIFY,                 /* Typically sent to dialog to inform it of state-change
                                 * of listboxes, check- and radiobuttons. */
    MSG_CURSOR,                 /* Sent to widget to position the cursor */
    MSG_IDLE,                   /* The idle state is active */
    MSG_RESIZE,                 /* Screen size has changed */
    MSG_VALIDATE,               /* Dialog is to be closed */
    MSG_END,                    /* Shut down dialog */
    MSG_DESTROY                 /* Sent to widget at destruction time */
} widget_msg_t;

/* Widgets are expected to answer to the following messages:
   MSG_FOCUS:   MSG_HANDLED if the accept the focus, MSG_NOT_HANDLED if they do not.
   MSG_UNFOCUS: MSG_HANDLED if they accept to release the focus, MSG_NOT_HANDLED if they don't.
   MSG_KEY:     MSG_HANDLED if they actually used the key, MSG_NOT_HANDLED if not.
   MSG_HOTKEY:  MSG_HANDLED if they actually used the key, MSG_NOT_HANDLED if not.
 */

typedef enum
{
    MSG_NOT_HANDLED = 0,
    MSG_HANDLED = 1
} cb_ret_t;

/* Widget options */
typedef enum
{
    WOP_DEFAULT = (0 << 0),
    WOP_WANT_HOTKEY = (1 << 0),
    WOP_WANT_CURSOR = (1 << 1),
    WOP_WANT_TAB = (1 << 2),    /* Should the tab key be sent to the dialog? */
    WOP_IS_INPUT = (1 << 3),
    WOP_SELECTABLE = (1 << 4),
    WOP_TOP_SELECT = (1 << 5)
} widget_options_t;

/* Widget state */
typedef enum
{
    WST_DEFAULT = (0 << 0),
    WST_VISIBLE = (1 << 0),     /* Widget is visible */
    WST_DISABLED = (1 << 1),    /* Widget cannot be selected */
    WST_IDLE = (1 << 2),
    WST_MODAL = (1 << 3),       /* Widget (dialog) is modal */
    WST_FOCUSED = (1 << 4),

    WST_CONSTRUCT = (1 << 15),  /* Widget has been constructed but not run yet */
    WST_ACTIVE = (1 << 16),     /* Dialog is visible and active */
    WST_SUSPENDED = (1 << 17),  /* Dialog is suspended */
    WST_CLOSED = (1 << 18)      /* Dialog is closed */
} widget_state_t;

/* Flags for widget repositioning on dialog resize */
typedef enum
{
    WPOS_FULLSCREEN = (1 << 0), /* widget occupies the whole screen */
    WPOS_CENTER_HORZ = (1 << 1),        /* center widget in horizontal */
    WPOS_CENTER_VERT = (1 << 2),        /* center widget in vertical */
    WPOS_CENTER = WPOS_CENTER_HORZ | WPOS_CENTER_VERT,  /* center widget */
    WPOS_TRYUP = (1 << 3),      /* try to move two lines up the widget */
    WPOS_KEEP_LEFT = (1 << 4),  /* keep widget distance to left border of dialog */
    WPOS_KEEP_RIGHT = (1 << 5), /* keep widget distance to right border of dialog */
    WPOS_KEEP_TOP = (1 << 6),   /* keep widget distance to top border of dialog */
    WPOS_KEEP_BOTTOM = (1 << 7),        /* keep widget distance to bottom border of dialog */
    WPOS_KEEP_HORZ = WPOS_KEEP_LEFT | WPOS_KEEP_RIGHT,
    WPOS_KEEP_VERT = WPOS_KEEP_TOP | WPOS_KEEP_BOTTOM,
    WPOS_KEEP_ALL = WPOS_KEEP_HORZ | WPOS_KEEP_VERT,
    WPOS_KEEP_DEFAULT = WPOS_KEEP_LEFT | WPOS_KEEP_TOP
} widget_pos_flags_t;
/* NOTES:
 * If WPOS_FULLSCREEN is set then all other position flags are ignored.
 * If WPOS_CENTER_HORZ flag is used, other horizontal flags (WPOS_KEEP_LEFT, WPOS_KEEP_RIGHT,
 * and WPOS_KEEP_HORZ) are ignored.
 * If WPOS_CENTER_VERT flag is used, other horizontal flags (WPOS_KEEP_TOP, WPOS_KEEP_BOTTOM,
 * and WPOS_KEEP_VERT) are ignored.
 */

/*** structures declarations (and typedefs of structures)*****************************************/

/* Widget callback */
typedef cb_ret_t (*widget_cb_fn) (Widget * widget, Widget * sender, widget_msg_t msg, int parm,
                                  void *data);
/* Widget mouse callback */
typedef void (*widget_mouse_cb_fn) (Widget * w, mouse_msg_t msg, mouse_event_t * event);
/* translate mouse event and process it */
typedef int (*widget_mouse_handle_fn) (Widget * w, Gpm_Event * event);

/* Every Widget must have this as its first element */
struct Widget
{
    WRect rect;                 /* position and size */
    /* ATTENTION! For groups, don't change @rect members directly to avoid
       incorrect reposion and resize of group members.  */
    widget_pos_flags_t pos_flags;       /* repositioning flags */
    widget_options_t options;
    widget_state_t state;
    unsigned long id;           /* uniq widget ID */
    widget_cb_fn callback;
    widget_mouse_cb_fn mouse_callback;
    WGroup *owner;

    /* Key-related fields */
    const global_keymap_t *keymap;      /* main keymap */
    const global_keymap_t *ext_keymap;  /* extended keymap */
    gboolean ext_mode;          /* use keymap or ext_keymap */

    /* Mouse-related fields. */
    widget_mouse_handle_fn mouse_handler;
    struct
    {
        /* Public members: */
        gboolean forced_capture;        /* Overrides the 'capture' member. Set explicitly by the programmer. */

        /* Implementation details: */
        gboolean capture;       /* Whether the widget "owns" the mouse. */
        mouse_msg_t last_msg;   /* The previous event type processed. */
        int last_buttons_down;
    } mouse;

    void (*make_global) (Widget * w, const WRect * delta);
    void (*make_local) (Widget * w, const WRect * delta);

    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);

    /* *INDENT-OFF* */
    cb_ret_t (*set_state) (Widget * w, widget_state_t state, gboolean enable);
    /* *INDENT-ON* */
    void (*destroy) (Widget * w);

    const int *(*get_colors) (const Widget * w);
};

/* structure for label (caption) with hotkey, if original text does not contain
 * hotkey, only start is valid and is equal to original text
 * hotkey is defined as char*, but mc support only singlebyte hotkey
 */
typedef struct hotkey_t
{
    char *start;                /* never NULL */
    char *hotkey;               /* can be NULL */
    char *end;                  /* can be NULL */
} hotkey_t;

/*** global variables defined in .c file *********************************************************/

/*** declarations of public functions ************************************************************/

/* create hotkey from text */
hotkey_t hotkey_new (const char *text);
/* release hotkey, free all mebers of hotkey_t */
void hotkey_free (const hotkey_t hotkey);
/* return width on terminal of hotkey */
int hotkey_width (const hotkey_t hotkey);
/* compare two hotkeys */
gboolean hotkey_equal (const hotkey_t hotkey1, const hotkey_t hotkey2);
/* draw hotkey of widget */
void hotkey_draw (const Widget * w, const hotkey_t hotkey, gboolean focused);
/* get text of hotkey */
char *hotkey_get_text (const hotkey_t hotkey);

/* widget initialization */
void widget_init (Widget * w, const WRect * r, widget_cb_fn callback,
                  widget_mouse_cb_fn mouse_callback);
/* Default callback for widgets */
cb_ret_t widget_default_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
                                  void *data);
void widget_set_options (Widget * w, widget_options_t options, gboolean enable);
void widget_adjust_position (widget_pos_flags_t pos_flags, WRect * r);
void widget_set_size (Widget * w, int y, int x, int lines, int cols);
void widget_set_size_rect (Widget * w, WRect * r);
/* select color for widget in dependence of state */
void widget_selectcolor (const Widget * w, gboolean focused, gboolean hotkey);
cb_ret_t widget_draw (Widget * w);
void widget_erase (Widget * w);
void widget_set_visibility (Widget * w, gboolean make_visible);
gboolean widget_is_active (const void *w);
void widget_replace (Widget * old, Widget * new);
gboolean widget_is_focusable (const Widget * w);
void widget_select (Widget * w);
void widget_set_bottom (Widget * w);

long widget_lookup_key (Widget * w, int key);

void widget_default_make_global (Widget * w, const WRect * delta);
void widget_default_make_local (Widget * w, const WRect * delta);

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);

cb_ret_t widget_default_set_state (Widget * w, widget_state_t state, gboolean enable);

void widget_default_destroy (Widget * w);

/* 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);

/* --------------------------------------------------------------------------------------------- */
/*** inline functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */

static inline cb_ret_t
send_message (void *w, void *sender, widget_msg_t msg, int parm, void *data)
{
    cb_ret_t ret = MSG_NOT_HANDLED;

#if 1
    if (w != NULL)              /* This must be always true, but... */
#endif
        ret = WIDGET (w)->callback (WIDGET (w), WIDGET (sender), msg, parm, data);

    return ret;
}

/* --------------------------------------------------------------------------------------------- */
/**
  * Check whether one or several option flags are set or not.
  * @param w widget
  * @param options widget option flags
  *
  * @return TRUE if all requested option flags are set, FALSE otherwise.
  */

static inline gboolean
widget_get_options (const Widget * w, widget_options_t options)
{
    return ((w->options & options) == options);
}

/* --------------------------------------------------------------------------------------------- */

/**
  * Check whether one or several state flags are set or not.
  * @param w widget
  * @param state widget state flags
  *
  * @return TRUE if all requested state flags are set, FALSE otherwise.
  */

static inline gboolean
widget_get_state (const Widget * w, widget_state_t state)
{
    return ((w->state & state) == state);
}

/* --------------------------------------------------------------------------------------------- */

/**
  * Convert widget coordinates from local (relative to owner) to global (relative to screen).
  *
  * @param w widget
  */

static inline void
widget_make_global (Widget * w)
{
    w->make_global (w, NULL);
}

/* --------------------------------------------------------------------------------------------- */

/**
  * Convert widget coordinates from global (relative to screen) to local (relative to owner).
  *
  * @param w widget
  */

static inline void
widget_make_local (Widget * w)
{
    w->make_local (w, NULL);
}

/* --------------------------------------------------------------------------------------------- */

/**
 * 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);
}

/* --------------------------------------------------------------------------------------------- */
/**
 * Modify state of widget.
 *
 * @param w      widget
 * @param state  widget state flag to modify
 * @param enable specifies whether to turn the flag on (TRUE) or off (FALSE).
 *               Only one flag per call can be modified.
 * @return       MSG_HANDLED if set was handled successfully, MSG_NOT_HANDLED otherwise.
 */

static inline cb_ret_t
widget_set_state (Widget * w, widget_state_t state, gboolean enable)
{
    return w->set_state (w, state, enable);
}

/* --------------------------------------------------------------------------------------------- */
/**
 * Destroy widget.
 *
 * @param w widget
 */

static inline void
widget_destroy (Widget * w)
{
    w->destroy (w);
}

/* --------------------------------------------------------------------------------------------- */

/**
 * Get color colors of widget.
 *
 * @param w widget
 * @return  color colors
 */
static inline const int *
widget_get_colors (const Widget * w)
{
    return w->get_colors (w);
}

/* --------------------------------------------------------------------------------------------- */
/**
 * Update cursor position in the specified widget.
 *
 * @param w widget
 *
 * @return TRUE if cursor was updated successfully, FALSE otherwise
 */

static inline gboolean
widget_update_cursor (Widget * w)
{
    return (send_message (w, NULL, MSG_CURSOR, 0, NULL) == MSG_HANDLED);
}

/* --------------------------------------------------------------------------------------------- */

static inline void
widget_show (Widget * w)
{
    widget_set_visibility (w, TRUE);
}

/* --------------------------------------------------------------------------------------------- */

static inline void
widget_hide (Widget * w)
{
    widget_set_visibility (w, FALSE);
}


/* --------------------------------------------------------------------------------------------- */
/**
  * Check whether two widgets are overlapped or not.
  * @param a 1st widget
  * @param b 2nd widget
  *
  * @return TRUE if widgets are overlapped, FALSE otherwise.
  */

static inline gboolean
widget_overlapped (const Widget * a, const Widget * b)
{
    return rects_are_overlapped (&a->rect, &b->rect);
}

/* --------------------------------------------------------------------------------------------- */

#endif /* MC__WIDGET_COMMON_H */