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