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 || g->current == 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 return (strcmp (hotkey1.start, hotkey2.start) == 0)
256 && hotkey_cmp (hotkey1.hotkey, hotkey2.hotkey) && hotkey_cmp (hotkey1.end, hotkey2.end);
257 }
258
259
260
261 void
262 hotkey_draw (const Widget *w, const hotkey_t hotkey, gboolean focused)
263 {
264 if (hotkey.start[0] != '\0')
265 {
266 widget_selectcolor (w, focused, FALSE);
267 tty_print_string (hotkey.start);
268 }
269
270 if (hotkey.hotkey != NULL)
271 {
272 widget_selectcolor (w, focused, TRUE);
273 tty_print_string (hotkey.hotkey);
274 }
275
276 if (hotkey.end != NULL)
277 {
278 widget_selectcolor (w, focused, FALSE);
279 tty_print_string (hotkey.end);
280 }
281 }
282
283
284
285 char *
286 hotkey_get_text (const hotkey_t hotkey)
287 {
288 GString *text;
289
290 text = g_string_new (hotkey.start);
291
292 if (hotkey.hotkey != NULL)
293 {
294 g_string_append_c (text, '&');
295 g_string_append (text, hotkey.hotkey);
296 }
297
298 if (hotkey.end != NULL)
299 g_string_append (text, hotkey.end);
300
301 return g_string_free (text, FALSE);
302 }
303
304
305
306 void
307 widget_init (Widget *w, const WRect *r, widget_cb_fn callback, widget_mouse_cb_fn mouse_callback)
308 {
309 w->id = widget_set_id ();
310 w->rect = *r;
311 w->pos_flags = WPOS_KEEP_DEFAULT;
312 w->callback = callback;
313
314 w->keymap = NULL;
315 w->ext_keymap = NULL;
316 w->ext_mode = FALSE;
317
318 w->mouse_callback = mouse_callback != NULL ? mouse_callback : widget_default_mouse_callback;
319 w->owner = NULL;
320 w->mouse_handler = mouse_handle_event;
321 w->mouse.forced_capture = FALSE;
322 w->mouse.capture = FALSE;
323 w->mouse.last_msg = MSG_MOUSE_NONE;
324 w->mouse.last_buttons_down = 0;
325
326 w->options = WOP_DEFAULT;
327 w->state = WST_CONSTRUCT | WST_VISIBLE;
328
329 w->make_global = widget_default_make_global;
330 w->make_local = widget_default_make_local;
331
332 w->find = widget_default_find;
333 w->find_by_type = widget_default_find_by_type;
334 w->find_by_id = widget_default_find_by_id;
335
336 w->set_state = widget_default_set_state;
337 w->destroy = widget_default_destroy;
338 w->get_colors = widget_default_get_colors;
339 }
340
341
342
343
344 cb_ret_t
345 widget_default_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
346 {
347 (void) sender;
348 (void) parm;
349
350 switch (msg)
351 {
352 case MSG_INIT:
353 case MSG_FOCUS:
354 case MSG_UNFOCUS:
355 case MSG_ENABLE:
356 case MSG_DISABLE:
357 case MSG_DRAW:
358 case MSG_DESTROY:
359 case MSG_CURSOR:
360 case MSG_IDLE:
361 return MSG_HANDLED;
362
363 case MSG_RESIZE:
364 return widget_default_resize (w, CONST_RECT (data));
365
366 default:
367 return MSG_NOT_HANDLED;
368 }
369 }
370
371
372
373
374
375
376
377
378
379
380 void
381 widget_set_options (Widget *w, widget_options_t options, gboolean enable)
382 {
383 if (enable)
384 w->options |= options;
385 else
386 w->options &= ~options;
387 }
388
389
390
391 void
392 widget_adjust_position (widget_pos_flags_t pos_flags, WRect *r)
393 {
394 if ((pos_flags & WPOS_FULLSCREEN) != 0)
395 {
396 r->y = 0;
397 r->x = 0;
398 r->lines = LINES;
399 r->cols = COLS;
400 }
401 else
402 {
403 if ((pos_flags & WPOS_CENTER_HORZ) != 0)
404 r->x = (COLS - r->cols) / 2;
405
406 if ((pos_flags & WPOS_CENTER_VERT) != 0)
407 r->y = (LINES - r->lines) / 2;
408
409 if ((pos_flags & WPOS_TRYUP) != 0)
410 {
411 if (r->y > 3)
412 r->y -= 2;
413 else if (r->y == 3)
414 r->y = 2;
415 }
416 }
417 }
418
419
420
421
422
423
424
425
426
427
428
429
430 void
431 widget_set_size (Widget *w, int y, int x, int lines, int cols)
432 {
433 WRect r = { y, x, lines, cols };
434
435 send_message (w, NULL, MSG_RESIZE, 0, &r);
436 widget_draw (w);
437 }
438
439
440
441
442
443
444
445
446
447 void
448 widget_set_size_rect (Widget *w, WRect *r)
449 {
450 send_message (w, NULL, MSG_RESIZE, 0, r);
451 widget_draw (w);
452 }
453
454
455
456 void
457 widget_selectcolor (const Widget *w, gboolean focused, gboolean hotkey)
458 {
459 int color;
460 const int *colors;
461
462 colors = widget_get_colors (w);
463
464 if (widget_get_state (w, WST_DISABLED))
465 color = DISABLED_COLOR;
466 else if (hotkey)
467 color = colors[focused ? DLG_COLOR_HOT_FOCUS : DLG_COLOR_HOT_NORMAL];
468 else
469 color = colors[focused ? DLG_COLOR_FOCUS : DLG_COLOR_NORMAL];
470
471 tty_setcolor (color);
472 }
473
474
475
476 void
477 widget_erase (Widget *w)
478 {
479 if (w != NULL)
480 tty_fill_region (w->rect.y, w->rect.x, w->rect.lines, w->rect.cols, ' ');
481 }
482
483
484
485 void
486 widget_set_visibility (Widget *w, gboolean make_visible)
487 {
488 if (widget_get_state (w, WST_VISIBLE) != make_visible)
489 widget_set_state (w, WST_VISIBLE, make_visible);
490 }
491
492
493
494
495
496
497
498
499
500
501
502 gboolean
503 widget_is_active (const void *w)
504 {
505 const WGroup *owner;
506
507
508 if (w == top_dlg->data)
509 return TRUE;
510
511 owner = CONST_WIDGET (w)->owner;
512
513
514 if (owner == NULL)
515 return FALSE;
516
517 if (w != owner->current->data)
518 return FALSE;
519
520 return widget_is_active (owner);
521 }
522
523
524
525 cb_ret_t
526 widget_draw (Widget *w)
527 {
528 cb_ret_t ret = MSG_NOT_HANDLED;
529
530 if (w != NULL && widget_get_state (w, WST_VISIBLE))
531 {
532 WGroup *g = w->owner;
533
534 if (g != NULL && widget_get_state (WIDGET (g), WST_ACTIVE))
535 ret = w->callback (w, NULL, MSG_DRAW, 0, NULL);
536 }
537
538 return ret;
539 }
540
541
542
543
544
545
546
547
548
549 void
550 widget_replace (Widget *old_w, Widget *new_w)
551 {
552 WGroup *g = old_w->owner;
553 gboolean should_focus = FALSE;
554 GList *holder;
555
556 if (g->widgets == NULL)
557 return;
558
559 if (g->current == NULL)
560 g->current = g->widgets;
561
562
563 if (old_w == g->current->data)
564 holder = g->current;
565 else
566 holder = g_list_find (g->widgets, old_w);
567
568
569 if (widget_get_state (old_w, WST_FOCUSED))
570 should_focus = TRUE;
571
572 if (!widget_get_options (new_w, WOP_SELECTABLE))
573 should_focus = FALSE;
574
575
576 if (!should_focus)
577 {
578 GList *l;
579
580 for (l = group_get_widget_next_of (holder);
581 !widget_is_focusable (WIDGET (l->data)) && l != holder;
582 l = group_get_widget_next_of (l))
583 ;
584
585 widget_select (WIDGET (l->data));
586 }
587
588
589 new_w->owner = g;
590 new_w->id = old_w->id;
591 holder->data = new_w;
592
593 send_message (old_w, NULL, MSG_DESTROY, 0, NULL);
594 send_message (new_w, NULL, MSG_INIT, 0, NULL);
595
596 if (should_focus)
597 widget_select (new_w);
598 else
599 widget_draw (new_w);
600 }
601
602
603
604 gboolean
605 widget_is_focusable (const Widget *w)
606 {
607 return (widget_get_options (w, WOP_SELECTABLE) && widget_get_state (w, WST_VISIBLE)
608 && !widget_get_state (w, WST_DISABLED));
609 }
610
611
612
613
614
615
616
617
618
619
620
621 void
622 widget_select (Widget *w)
623 {
624 WGroup *g;
625
626 if (!widget_get_options (w, WOP_SELECTABLE))
627 return;
628
629 g = GROUP (w->owner);
630 if (g != NULL)
631 {
632 if (widget_get_options (w, WOP_TOP_SELECT))
633 {
634 GList *l;
635
636 l = widget_find (WIDGET (g), w);
637 widget_reorder (l, TRUE);
638 }
639
640 widget_focus (w);
641 }
642 }
643
644
645
646
647
648
649 void
650 widget_set_bottom (Widget *w)
651 {
652 widget_reorder (widget_find (WIDGET (w->owner), w), FALSE);
653 }
654
655
656
657
658
659
660
661
662
663
664 long
665 widget_lookup_key (Widget *w, int key)
666 {
667 if (w->ext_mode)
668 {
669 w->ext_mode = FALSE;
670 return keybind_lookup_keymap_command (w->ext_keymap, key);
671 }
672
673 return keybind_lookup_keymap_command (w->keymap, key);
674 }
675
676
677
678
679
680
681
682
683
684
685
686 void
687 widget_default_make_global (Widget *w, const WRect *delta)
688 {
689 if (delta != NULL)
690 rect_move (&w->rect, delta->y, delta->x);
691 else if (w->owner != NULL)
692 rect_move (&w->rect, WIDGET (w->owner)->rect.y, WIDGET (w->owner)->rect.x);
693 }
694
695
696
697
698
699
700
701
702
703
704
705 void
706 widget_default_make_local (Widget *w, const WRect *delta)
707 {
708 if (delta != NULL)
709 rect_move (&w->rect, -delta->y, -delta->x);
710 else if (w->owner != NULL)
711 rect_move (&w->rect, -WIDGET (w->owner)->rect.y, -WIDGET (w->owner)->rect.x);
712 }
713
714
715
716
717
718
719
720
721
722
723
724 GList *
725 widget_default_find (const Widget *w, const Widget *what)
726 {
727 return (w != what || w->owner == NULL) ? NULL
728 : g_list_find (CONST_GROUP (w->owner)->widgets, what);
729 }
730
731
732
733
734
735
736
737
738
739
740
741
742 Widget *
743 widget_default_find_by_type (const Widget *w, widget_cb_fn cb)
744 {
745 return (w->callback == cb ? WIDGET (w) : NULL);
746 }
747
748
749
750
751
752
753
754
755
756
757
758 Widget *
759 widget_default_find_by_id (const Widget *w, unsigned long id)
760 {
761 return (w->id == id ? WIDGET (w) : NULL);
762 }
763
764
765
766
767
768
769
770
771
772
773
774
775
776 cb_ret_t
777 widget_default_set_state (Widget *w, widget_state_t state, gboolean enable)
778 {
779 gboolean ret = MSG_HANDLED;
780 Widget *owner = WIDGET (GROUP (w->owner));
781
782 if (enable)
783 w->state |= state;
784 else
785 w->state &= ~state;
786
787 if (enable)
788 {
789
790 switch (state)
791 {
792 case WST_CONSTRUCT:
793 w->state &= ~(WST_ACTIVE | WST_SUSPENDED | WST_CLOSED);
794 break;
795 case WST_ACTIVE:
796 w->state &= ~(WST_CONSTRUCT | WST_SUSPENDED | WST_CLOSED);
797 break;
798 case WST_SUSPENDED:
799 w->state &= ~(WST_CONSTRUCT | WST_ACTIVE | WST_CLOSED);
800 break;
801 case WST_CLOSED:
802 w->state &= ~(WST_CONSTRUCT | WST_ACTIVE | WST_SUSPENDED);
803 break;
804 default:
805 break;
806 }
807 }
808
809 if (owner == NULL)
810 return MSG_NOT_HANDLED;
811
812 switch (state)
813 {
814 case WST_VISIBLE:
815 if (widget_get_state (owner, WST_ACTIVE))
816 {
817 widget_draw (owner);
818
819 if (!enable)
820 {
821
822 if (w == GROUP (owner)->current->data)
823 group_select_next_widget (GROUP (owner));
824
825 widget_update_cursor (owner);
826 }
827 }
828 break;
829
830 case WST_DISABLED:
831 ret = send_message (w, NULL, enable ? MSG_DISABLE : MSG_ENABLE, 0, NULL);
832 if (ret == MSG_HANDLED && widget_get_state (owner, WST_ACTIVE))
833 ret = widget_draw (w);
834 break;
835
836 case WST_FOCUSED:
837 {
838 widget_msg_t msg;
839
840 msg = enable ? MSG_FOCUS : MSG_UNFOCUS;
841 ret = send_message (w, NULL, msg, 0, NULL);
842 if (ret == MSG_HANDLED && widget_get_state (owner, WST_ACTIVE))
843 {
844 widget_draw (w);
845
846 send_message (owner, w, MSG_CHANGED_FOCUS, 0, NULL);
847 }
848 }
849 break;
850
851 default:
852 break;
853 }
854
855 return ret;
856 }
857
858
859
860
861
862
863
864
865 void
866 widget_default_destroy (Widget *w)
867 {
868 send_message (w, NULL, MSG_DESTROY, 0, NULL);
869 g_free (w);
870 }
871
872
873
874
875 Gpm_Event
876 mouse_get_local (const Gpm_Event *global, const Widget *w)
877 {
878 Gpm_Event local;
879
880 memset (&local, 0, sizeof (local));
881
882 local.buttons = global->buttons;
883 local.x = global->x - w->rect.x;
884 local.y = global->y - w->rect.y;
885 local.type = global->type;
886
887 return local;
888 }
889
890
891
892 gboolean
893 mouse_global_in_widget (const Gpm_Event *event, const Widget *w)
894 {
895 const WRect *r = &w->rect;
896
897 return (event->x > r->x) && (event->y > r->y) && (event->x <= r->x + r->cols)
898 && (event->y <= r->y + r->lines);
899 }
900
901