This source file includes following definitions.
- group_widget_init
- group_get_next_or_prev_of
- group_select_next_or_prev
- group_widget_set_state
- group_send_broadcast_msg_custom
- group_default_find
- group_default_find_by_type
- group_default_find_by_id
- group_update_cursor
- group_widget_set_position
- group_set_position
- group_default_resize
- group_draw
- group_handle_key
- group_handle_hotkey
- group_init
- group_default_callback
- group_default_set_state
- group_handle_mouse_event
- group_add_widget_autopos
- group_remove_widget
- group_set_current_widget_next
- group_set_current_widget_prev
- group_get_widget_next_of
- group_get_widget_prev_of
- group_select_next_widget
- group_select_prev_widget
- group_select_widget_by_id
- group_send_broadcast_msg
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 #include <config.h>
31
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "lib/global.h"
37
38 #include "lib/tty/key.h"
39
40 #include "lib/widget.h"
41
42
43
44
45
46
47
48
49 typedef struct
50 {
51 int shift_x;
52 int scale_x;
53 int shift_y;
54 int scale_y;
55 } widget_shift_scale_t;
56
57 typedef struct
58 {
59 widget_state_t state;
60 gboolean enable;
61 } widget_state_info_t;
62
63
64
65
66
67
68
69 static void
70 group_widget_init (void *data, void *user_data)
71 {
72 (void) user_data;
73
74 send_message (WIDGET (data), NULL, MSG_INIT, 0, NULL);
75 }
76
77
78
79 static GList *
80 group_get_next_or_prev_of (GList * list, gboolean next)
81 {
82 GList *l = NULL;
83
84 if (list != NULL)
85 {
86 WGroup *owner = WIDGET (list->data)->owner;
87
88 if (owner != NULL)
89 {
90 if (next)
91 {
92 l = g_list_next (list);
93 if (l == NULL)
94 l = owner->widgets;
95 }
96 else
97 {
98 l = g_list_previous (list);
99 if (l == NULL)
100 l = g_list_last (owner->widgets);
101 }
102 }
103 }
104
105 return l;
106 }
107
108
109
110 static void
111 group_select_next_or_prev (WGroup * g, gboolean next)
112 {
113 if (g->widgets != NULL && g->current != NULL)
114 {
115 GList *l = g->current;
116 Widget *w;
117
118 do
119 {
120 l = group_get_next_or_prev_of (l, next);
121 w = WIDGET (l->data);
122 }
123 while ((widget_get_state (w, WST_DISABLED) || !widget_get_options (w, WOP_SELECTABLE))
124 && l != g->current);
125
126 widget_select (l->data);
127 }
128 }
129
130
131
132 static void
133 group_widget_set_state (gpointer data, gpointer user_data)
134 {
135 widget_state_info_t *state = (widget_state_info_t *) user_data;
136
137 widget_set_state (WIDGET (data), state->state, state->enable);
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151 static void
152 group_send_broadcast_msg_custom (WGroup * g, widget_msg_t msg, gboolean reverse,
153 widget_options_t options)
154 {
155 GList *p, *first;
156
157 if (g->widgets == NULL)
158 return;
159
160 if (g->current == NULL)
161 g->current = g->widgets;
162
163 p = group_get_next_or_prev_of (g->current, !reverse);
164 first = p;
165
166 do
167 {
168 Widget *w = WIDGET (p->data);
169
170 p = group_get_next_or_prev_of (p, !reverse);
171
172 if (options == WOP_DEFAULT || (options & w->options) != 0)
173 send_message (w, NULL, msg, 0, NULL);
174 }
175 while (first != p);
176 }
177
178
179
180
181
182
183
184
185
186
187
188
189 static GList *
190 group_default_find (const Widget * w, const Widget * what)
191 {
192 GList *w0;
193
194 w0 = widget_default_find (w, what);
195 if (w0 == NULL)
196 {
197 GList *iter;
198
199 for (iter = GROUP (w)->widgets; iter != NULL; iter = g_list_next (iter))
200 {
201 w0 = widget_find (WIDGET (iter->data), what);
202 if (w0 != NULL)
203 break;
204 }
205 }
206
207 return w0;
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221 static Widget *
222 group_default_find_by_type (const Widget * w, widget_cb_fn cb)
223 {
224 Widget *w0;
225
226 w0 = widget_default_find_by_type (w, cb);
227 if (w0 == NULL)
228 {
229 GList *iter;
230
231 for (iter = GROUP (w)->widgets; iter != NULL; iter = g_list_next (iter))
232 {
233 w0 = widget_find_by_type (WIDGET (iter->data), cb);
234 if (w0 != NULL)
235 break;
236 }
237 }
238
239 return w0;
240 }
241
242
243
244
245
246
247
248
249
250
251
252
253 static Widget *
254 group_default_find_by_id (const Widget * w, unsigned long id)
255 {
256 Widget *w0;
257
258 w0 = widget_default_find_by_id (w, id);
259 if (w0 == NULL)
260 {
261 GList *iter;
262
263 for (iter = GROUP (w)->widgets; iter != NULL; iter = g_list_next (iter))
264 {
265 w0 = widget_find_by_id (WIDGET (iter->data), id);
266 if (w0 != NULL)
267 break;
268 }
269 }
270
271 return w0;
272 }
273
274
275
276
277
278
279
280
281
282
283 static cb_ret_t
284 group_update_cursor (WGroup * g)
285 {
286 GList *p = g->current;
287
288 if (p != NULL && widget_get_state (WIDGET (g), WST_ACTIVE))
289 do
290 {
291 Widget *w = WIDGET (p->data);
292
293 if (widget_get_options (w, WOP_WANT_CURSOR) && !widget_get_state (w, WST_DISABLED)
294 && widget_update_cursor (WIDGET (p->data)))
295 return MSG_HANDLED;
296
297 p = group_get_widget_next_of (p);
298 }
299 while (p != g->current);
300
301 return MSG_NOT_HANDLED;
302 }
303
304
305
306 static void
307 group_widget_set_position (gpointer data, gpointer user_data)
308 {
309
310
311
312
313
314 Widget *c = WIDGET (data);
315 Widget *g = WIDGET (c->owner);
316 const widget_shift_scale_t *wss = (const widget_shift_scale_t *) user_data;
317 WRect r = { c->y, c->x, c->lines, c->cols };
318
319 if ((c->pos_flags & WPOS_CENTER_HORZ) != 0)
320 r.x = g->x + (g->cols - c->cols) / 2;
321 else if ((c->pos_flags & WPOS_KEEP_LEFT) != 0 && (c->pos_flags & WPOS_KEEP_RIGHT) != 0)
322 {
323 r.x += wss->shift_x;
324 r.cols += wss->scale_x;
325 }
326 else if ((c->pos_flags & WPOS_KEEP_LEFT) != 0)
327 r.x += wss->shift_x;
328 else if ((c->pos_flags & WPOS_KEEP_RIGHT) != 0)
329 r.x += wss->shift_x + wss->scale_x;
330
331 if ((c->pos_flags & WPOS_CENTER_VERT) != 0)
332 r.y = g->y + (g->lines - c->lines) / 2;
333 else if ((c->pos_flags & WPOS_KEEP_TOP) != 0 && (c->pos_flags & WPOS_KEEP_BOTTOM) != 0)
334 {
335 r.y += wss->shift_y;
336 r.lines += wss->scale_y;
337 }
338 else if ((c->pos_flags & WPOS_KEEP_TOP) != 0)
339 r.y += wss->shift_y;
340 else if ((c->pos_flags & WPOS_KEEP_BOTTOM) != 0)
341 r.y += wss->shift_y + wss->scale_y;
342
343 send_message (c, NULL, MSG_RESIZE, 0, &r);
344 }
345
346
347
348 static void
349 group_set_position (WGroup * g, const WRect * r)
350 {
351 Widget *w = WIDGET (g);
352 widget_shift_scale_t wss;
353
354 WRect or = { w->y, w->x, w->lines, w->cols };
355
356 w->x = r->x;
357 w->y = r->y;
358 w->lines = r->lines;
359 w->cols = r->cols;
360
361
362 if (g->widgets == NULL)
363 return;
364
365 if (g->current == NULL)
366 g->current = g->widgets;
367
368
369 wss.shift_x = w->x - or.x;
370 wss.scale_x = w->cols - or.cols;
371 wss.shift_y = w->y - or.y;
372 wss.scale_y = w->lines - or.lines;
373
374 if (wss.shift_x != 0 || wss.shift_y != 0 || wss.scale_x != 0 || wss.scale_y != 0)
375 g_list_foreach (g->widgets, group_widget_set_position, &wss);
376 }
377
378
379
380 static void
381 group_default_resize (WGroup * g, WRect * r)
382 {
383
384
385
386
387
388
389 Widget *w = WIDGET (g);
390 WRect r0;
391
392 if (r == NULL)
393 rect_init (&r0, w->y, w->x, w->lines, w->cols);
394 else
395 r0 = *r;
396
397 widget_adjust_position (w->pos_flags, &r0.y, &r0.x, &r0.lines, &r0.cols);
398 group_set_position (g, &r0);
399 }
400
401
402
403 static void
404 group_draw (WGroup * g)
405 {
406 Widget *wg = WIDGET (g);
407
408
409 if (widget_get_state (wg, WST_ACTIVE))
410 {
411 GList *p;
412
413 if (g->winch_pending)
414 {
415 g->winch_pending = FALSE;
416 send_message (wg, NULL, MSG_RESIZE, 0, NULL);
417 }
418
419 for (p = g->widgets; p != NULL; p = g_list_next (p))
420 widget_draw (WIDGET (p->data));
421
422 widget_update_cursor (wg);
423 }
424 }
425
426
427
428 static cb_ret_t
429 group_handle_key (WGroup * g, int key)
430 {
431 cb_ret_t handled;
432
433
434 handled = send_message (g, NULL, MSG_HOTKEY, key, NULL);
435
436
437 if (handled == MSG_NOT_HANDLED)
438 handled = send_message (g->current->data, NULL, MSG_KEY, key, NULL);
439
440
441 if (handled == MSG_NOT_HANDLED)
442 handled = send_message (g, g->current->data, MSG_UNHANDLED_KEY, key, NULL);
443
444 return handled;
445 }
446
447
448
449 static cb_ret_t
450 group_handle_hotkey (WGroup * g, int key)
451 {
452 GList *current;
453 Widget *w;
454 cb_ret_t handled = MSG_NOT_HANDLED;
455 int c;
456
457 if (g->widgets == NULL)
458 return MSG_NOT_HANDLED;
459
460 if (g->current == NULL)
461 g->current = g->widgets;
462
463 w = WIDGET (g->current->data);
464
465 if (widget_get_state (w, WST_DISABLED))
466 return MSG_NOT_HANDLED;
467
468
469
470 if (widget_get_options (w, WOP_IS_INPUT))
471 {
472
473 if (key >= 32 && key < 256)
474 return MSG_NOT_HANDLED;
475 }
476
477
478 c = key & ~ALT (0);
479 if (key & ALT (0) && g_ascii_isalpha (c))
480 key = g_ascii_tolower (c);
481
482 if (widget_get_options (w, WOP_WANT_HOTKEY))
483 handled = send_message (w, NULL, MSG_HOTKEY, key, NULL);
484
485
486 if (handled == MSG_HANDLED)
487 return MSG_HANDLED;
488
489 current = group_get_widget_next_of (g->current);
490
491
492 while (g->current != current && handled == MSG_NOT_HANDLED)
493 {
494 w = WIDGET (current->data);
495
496 if (widget_get_options (w, WOP_WANT_HOTKEY) && !widget_get_state (w, WST_DISABLED))
497 handled = send_message (w, NULL, MSG_HOTKEY, key, NULL);
498
499 if (handled == MSG_NOT_HANDLED)
500 current = group_get_widget_next_of (current);
501 }
502
503 if (handled == MSG_HANDLED)
504 {
505 w = WIDGET (current->data);
506 widget_select (w);
507 send_message (g, w, MSG_HOTKEY_HANDLED, 0, NULL);
508 }
509
510 return handled;
511 }
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529 void
530 group_init (WGroup * g, int y1, int x1, int lines, int cols, widget_cb_fn callback,
531 widget_mouse_cb_fn mouse_callback)
532 {
533 Widget *w = WIDGET (g);
534
535 widget_init (w, y1, x1, lines, cols, callback != NULL ? callback : group_default_callback,
536 mouse_callback);
537
538 w->mouse_handler = group_handle_mouse_event;
539
540 w->find = group_default_find;
541 w->find_by_type = group_default_find_by_type;
542 w->find_by_id = group_default_find_by_id;
543
544 w->set_state = group_default_set_state;
545
546 g->mouse_status = MOU_UNHANDLED;
547 }
548
549
550
551 cb_ret_t
552 group_default_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
553 {
554 WGroup *g = GROUP (w);
555
556 switch (msg)
557 {
558 case MSG_INIT:
559 g_list_foreach (g->widgets, group_widget_init, NULL);
560 return MSG_HANDLED;
561
562 case MSG_DRAW:
563 group_draw (g);
564 return MSG_HANDLED;
565
566 case MSG_KEY:
567 return group_handle_key (g, parm);
568
569 case MSG_HOTKEY:
570 return group_handle_hotkey (g, parm);
571
572 case MSG_CURSOR:
573 return group_update_cursor (g);
574
575 case MSG_RESIZE:
576 group_default_resize (g, RECT (data));
577 return MSG_HANDLED;
578
579 case MSG_DESTROY:
580 g_list_foreach (g->widgets, (GFunc) widget_destroy, NULL);
581 g_list_free (g->widgets);
582 return MSG_HANDLED;
583
584 default:
585 return widget_default_callback (w, sender, msg, parm, data);
586 }
587 }
588
589
590
591
592
593
594
595
596
597
598
599
600 cb_ret_t
601 group_default_set_state (Widget * w, widget_state_t state, gboolean enable)
602 {
603 gboolean ret = MSG_HANDLED;
604 WGroup *g = GROUP (w);
605 widget_state_info_t st = {
606 .state = state,
607 .enable = enable
608 };
609
610 ret = widget_default_set_state (w, state, enable);
611
612 if (state == WST_ACTIVE || state == WST_SUSPENDED || state == WST_CLOSED)
613
614 g_list_foreach (g->widgets, group_widget_set_state, &st);
615
616 if ((w->state & WST_ACTIVE) != 0)
617 {
618 if ((w->state & WST_FOCUSED) != 0)
619 {
620
621 if (g->current != NULL)
622 widget_set_state (WIDGET (g->current->data), WST_FOCUSED, enable);
623 }
624 else
625
626 g_list_foreach (g->widgets, group_widget_set_state, &st);
627 }
628
629 return ret;
630 }
631
632
633
634
635
636
637
638
639
640
641
642 int
643 group_handle_mouse_event (Widget * w, Gpm_Event * event)
644 {
645 WGroup *g = GROUP (w);
646
647 if (g->widgets != NULL)
648 {
649 GList *p;
650
651
652 p = g_list_last (g->widgets);
653 do
654 {
655 Widget *wp = WIDGET (p->data);
656
657 if (!widget_get_state (wp, WST_DISABLED))
658 {
659
660 int ret;
661
662 ret = wp->mouse_handler (wp, event);
663 if (ret != MOU_UNHANDLED)
664 return ret;
665 }
666
667 p = g_list_previous (p);
668 }
669 while (p != NULL);
670 }
671
672 return MOU_UNHANDLED;
673 }
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689 unsigned long
690 group_add_widget_autopos (WGroup * g, void *w, widget_pos_flags_t pos_flags, const void *before)
691 {
692 Widget *wg = WIDGET (g);
693 Widget *ww = WIDGET (w);
694 GList *new_current;
695
696
697 assert (ww != NULL);
698
699 if ((pos_flags & WPOS_CENTER_HORZ) != 0)
700 ww->x = (wg->cols - ww->cols) / 2;
701 ww->x += wg->x;
702
703 if ((pos_flags & WPOS_CENTER_VERT) != 0)
704 ww->y = (wg->lines - ww->lines) / 2;
705 ww->y += wg->y;
706
707 ww->owner = g;
708 ww->pos_flags = pos_flags;
709
710 if (g->widgets == NULL || before == NULL)
711 {
712 g->widgets = g_list_append (g->widgets, ww);
713 new_current = g_list_last (g->widgets);
714 }
715 else
716 {
717 GList *b;
718
719 b = g_list_find (g->widgets, before);
720
721
722 assert (b != NULL);
723
724 b = g_list_next (b);
725 g->widgets = g_list_insert_before (g->widgets, b, ww);
726 if (b != NULL)
727 new_current = g_list_previous (b);
728 else
729 new_current = g_list_last (g->widgets);
730 }
731
732
733 if (widget_get_state (wg, WST_ACTIVE))
734 {
735 group_widget_init (ww, NULL);
736 widget_select (ww);
737 }
738 else
739 g->current = new_current;
740
741 return ww->id;
742 }
743
744
745
746
747
748
749
750
751 void
752 group_remove_widget (void *w)
753 {
754 WGroup *g;
755 GList *d;
756
757
758 assert (w != NULL);
759
760 g = WIDGET (w)->owner;
761
762 d = g_list_find (g->widgets, w);
763 if (d == g->current)
764 group_set_current_widget_next (g);
765
766 g->widgets = g_list_delete_link (g->widgets, d);
767 if (g->widgets == NULL)
768 g->current = NULL;
769
770
771 if (widget_get_state (WIDGET (g), WST_ACTIVE))
772 {
773 group_draw (g);
774 group_select_current_widget (g);
775 }
776
777 WIDGET (w)->owner = NULL;
778 }
779
780
781
782
783
784
785
786
787
788 void
789 group_set_current_widget_next (WGroup * g)
790 {
791 g->current = group_get_next_or_prev_of (g->current, TRUE);
792 }
793
794
795
796
797
798
799
800
801 void
802 group_set_current_widget_prev (WGroup * g)
803 {
804 g->current = group_get_next_or_prev_of (g->current, FALSE);
805 }
806
807
808
809
810
811
812
813
814
815
816 GList *
817 group_get_widget_next_of (GList * w)
818 {
819 return group_get_next_or_prev_of (w, TRUE);
820 }
821
822
823
824
825
826
827
828
829
830
831 GList *
832 group_get_widget_prev_of (GList * w)
833 {
834 return group_get_next_or_prev_of (w, FALSE);
835 }
836
837
838
839
840
841
842
843
844 void
845 group_select_next_widget (WGroup * g)
846 {
847 group_select_next_or_prev (g, TRUE);
848 }
849
850
851
852
853
854
855
856
857 void
858 group_select_prev_widget (WGroup * g)
859 {
860 group_select_next_or_prev (g, FALSE);
861 }
862
863
864
865
866
867
868
869
870
871 void
872 group_select_widget_by_id (const WGroup * g, unsigned long id)
873 {
874 Widget *w;
875
876 w = widget_find_by_id (CONST_WIDGET (g), id);
877 if (w != NULL)
878 widget_select (w);
879 }
880
881
882
883
884
885
886
887
888
889 void
890 group_send_broadcast_msg (WGroup * g, widget_msg_t msg)
891 {
892 group_send_broadcast_msg_custom (g, msg, FALSE, WOP_DEFAULT);
893 }
894
895