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