finch/libgnt/gntbox.c

changeset 39360
e7bed293aad5
parent 39302
64aabebb476b
child 39361
a1068caa3600
equal deleted inserted replaced
39302:64aabebb476b 39360:e7bed293aad5
1 /*
2 * GNT - The GLib Ncurses Toolkit
3 *
4 * GNT is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
7 *
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 */
22
23 #include "gntinternal.h"
24 #include "gntbox.h"
25 #include "gntstyle.h"
26 #include "gntutils.h"
27
28 #include <string.h>
29
30 #define PROP_LAST_RESIZE_S "last-resize"
31 #define PROP_SIZE_QUEUED_S "size-queued"
32
33 enum
34 {
35 PROP_0,
36 PROP_VERTICAL,
37 PROP_HOMO /* ... */
38 };
39
40 enum
41 {
42 SIGS = 1,
43 };
44
45 static GntWidgetClass *parent_class = NULL;
46
47 static GntWidget * find_focusable_widget(GntBox *box);
48
49 static void
50 add_to_focus(gpointer value, gpointer data)
51 {
52 GntBox *box = GNT_BOX(data);
53 GntWidget *w = GNT_WIDGET(value);
54
55 if (GNT_IS_BOX(w))
56 g_list_foreach(GNT_BOX(w)->list, add_to_focus, box);
57 else if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_CAN_TAKE_FOCUS))
58 box->focus = g_list_append(box->focus, w);
59 }
60
61 static void
62 get_title_thingies(GntBox *box, char *title, int *p, int *r)
63 {
64 GntWidget *widget = GNT_WIDGET(box);
65 int len;
66 char *end = (char*)gnt_util_onscreen_width_to_pointer(title, widget->priv.width - 4, &len);
67
68 if (p)
69 *p = (widget->priv.width - len) / 2;
70 if (r)
71 *r = (widget->priv.width + len) / 2;
72 *end = '\0';
73 }
74
75 static void
76 gnt_box_draw(GntWidget *widget)
77 {
78 GntBox *box = GNT_BOX(widget);
79
80 if (box->focus == NULL && widget->parent == NULL)
81 g_list_foreach(box->list, add_to_focus, box);
82
83 g_list_foreach(box->list, (GFunc)gnt_widget_draw, NULL);
84
85 if (box->title && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER))
86 {
87 int pos, right;
88 char *title = g_strdup(box->title);
89
90 get_title_thingies(box, title, &pos, &right);
91
92 if (gnt_widget_has_focus(widget))
93 wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_TITLE));
94 else
95 wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_TITLE_D));
96 mvwaddch(widget->window, 0, pos-1, ACS_RTEE | gnt_color_pair(GNT_COLOR_NORMAL));
97 mvwaddstr(widget->window, 0, pos, C_(title));
98 mvwaddch(widget->window, 0, right, ACS_LTEE | gnt_color_pair(GNT_COLOR_NORMAL));
99 g_free(title);
100 }
101
102 gnt_box_sync_children(box);
103 }
104
105 static void
106 reposition_children(GntWidget *widget)
107 {
108 GList *iter;
109 GntBox *box = GNT_BOX(widget);
110 int w, h, curx, cury, max;
111 gboolean has_border = FALSE;
112
113 w = h = 0;
114 max = 0;
115 curx = widget->priv.x;
116 cury = widget->priv.y;
117 if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER))
118 {
119 has_border = TRUE;
120 curx += 1;
121 cury += 1;
122 }
123
124 for (iter = box->list; iter; iter = iter->next)
125 {
126 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(iter->data), GNT_WIDGET_INVISIBLE))
127 continue;
128 gnt_widget_set_position(GNT_WIDGET(iter->data), curx, cury);
129 gnt_widget_get_size(GNT_WIDGET(iter->data), &w, &h);
130 if (box->vertical)
131 {
132 if (h)
133 {
134 cury += h + box->pad;
135 if (max < w)
136 max = w;
137 }
138 }
139 else
140 {
141 if (w)
142 {
143 curx += w + box->pad;
144 if (max < h)
145 max = h;
146 }
147 }
148 }
149
150 if (has_border)
151 {
152 curx += 1;
153 cury += 1;
154 max += 2;
155 }
156
157 if (box->list)
158 {
159 if (box->vertical)
160 cury -= box->pad;
161 else
162 curx -= box->pad;
163 }
164
165 if (box->vertical)
166 {
167 widget->priv.width = max;
168 widget->priv.height = cury - widget->priv.y;
169 }
170 else
171 {
172 widget->priv.width = curx - widget->priv.x;
173 widget->priv.height = max;
174 }
175 }
176
177 static void
178 gnt_box_set_position(GntWidget *widget, int x, int y)
179 {
180 GList *iter;
181 int changex, changey;
182
183 changex = widget->priv.x - x;
184 changey = widget->priv.y - y;
185
186 for (iter = GNT_BOX(widget)->list; iter; iter = iter->next)
187 {
188 GntWidget *w = GNT_WIDGET(iter->data);
189 gnt_widget_set_position(w, w->priv.x - changex,
190 w->priv.y - changey);
191 }
192 }
193
194 static void
195 gnt_box_size_request(GntWidget *widget)
196 {
197 GntBox *box = GNT_BOX(widget);
198 GList *iter;
199 int maxw = 0, maxh = 0;
200
201 g_list_foreach(box->list, (GFunc)gnt_widget_size_request, NULL);
202
203 for (iter = box->list; iter; iter = iter->next)
204 {
205 int w, h;
206 gnt_widget_get_size(GNT_WIDGET(iter->data), &w, &h);
207 if (maxh < h)
208 maxh = h;
209 if (maxw < w)
210 maxw = w;
211 }
212
213 for (iter = box->list; iter; iter = iter->next)
214 {
215 int w, h;
216 GntWidget *wid = GNT_WIDGET(iter->data);
217
218 gnt_widget_get_size(wid, &w, &h);
219
220 if (box->homogeneous)
221 {
222 if (box->vertical)
223 h = maxh;
224 else
225 w = maxw;
226 }
227 if (box->fill)
228 {
229 if (box->vertical)
230 w = maxw;
231 else
232 h = maxh;
233 }
234
235 if (gnt_widget_confirm_size(wid, w, h))
236 gnt_widget_set_size(wid, w, h);
237 }
238
239 reposition_children(widget);
240 }
241
242 static void
243 gnt_box_map(GntWidget *widget)
244 {
245 if (widget->priv.width == 0 || widget->priv.height == 0)
246 {
247 gnt_widget_size_request(widget);
248 find_focusable_widget(GNT_BOX(widget));
249 }
250 GNTDEBUG;
251 }
252
253 /* Ensures that the current widget can take focus */
254 static GntWidget *
255 find_focusable_widget(GntBox *box)
256 {
257 /* XXX: Make sure the widget is visible? */
258 if (box->focus == NULL && GNT_WIDGET(box)->parent == NULL)
259 g_list_foreach(box->list, add_to_focus, box);
260
261 if (box->active == NULL && box->focus)
262 box->active = box->focus->data;
263
264 return box->active;
265 }
266
267 static void
268 find_next_focus(GntBox *box)
269 {
270 gpointer last = box->active;
271 do
272 {
273 GList *iter = g_list_find(box->focus, box->active);
274 if (iter && iter->next)
275 box->active = iter->next->data;
276 else if (box->focus)
277 box->active = box->focus->data;
278 if (!GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_INVISIBLE) &&
279 GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_CAN_TAKE_FOCUS))
280 break;
281 } while (box->active != last);
282 }
283
284 static void
285 find_prev_focus(GntBox *box)
286 {
287 gpointer last = box->active;
288
289 if (!box->focus)
290 return;
291
292 do
293 {
294 GList *iter = g_list_find(box->focus, box->active);
295 if (!iter)
296 box->active = box->focus->data;
297 else if (!iter->prev)
298 box->active = g_list_last(box->focus)->data;
299 else
300 box->active = iter->prev->data;
301 if (!GNT_WIDGET_IS_FLAG_SET(box->active, GNT_WIDGET_INVISIBLE))
302 break;
303 } while (box->active != last);
304 }
305
306 static gboolean
307 gnt_box_key_pressed(GntWidget *widget, const char *text)
308 {
309 GntBox *box = GNT_BOX(widget);
310 gboolean ret;
311
312 if (!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_DISABLE_ACTIONS))
313 return FALSE;
314
315 if (box->active == NULL && !find_focusable_widget(box))
316 return FALSE;
317
318 if (gnt_widget_key_pressed(box->active, text))
319 return TRUE;
320
321 /* This dance is necessary to make sure that the child widgets get a chance
322 to trigger their bindings first */
323 GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_DISABLE_ACTIONS);
324 ret = gnt_widget_key_pressed(widget, text);
325 GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_DISABLE_ACTIONS);
326 return ret;
327 }
328
329 static gboolean
330 box_focus_change(GntBox *box, gboolean next)
331 {
332 GntWidget *now;
333 now = box->active;
334
335 if (next) {
336 find_next_focus(box);
337 } else {
338 find_prev_focus(box);
339 }
340
341 if (now && now != box->active) {
342 gnt_widget_set_focus(now, FALSE);
343 gnt_widget_set_focus(box->active, TRUE);
344 return TRUE;
345 }
346
347 return FALSE;
348 }
349
350 static gboolean
351 action_focus_next(GntBindable *bindable, GList *null)
352 {
353 return box_focus_change(GNT_BOX(bindable), TRUE);
354 }
355
356 static gboolean
357 action_focus_prev(GntBindable *bindable, GList *null)
358 {
359 return box_focus_change(GNT_BOX(bindable), FALSE);
360 }
361
362 static void
363 gnt_box_lost_focus(GntWidget *widget)
364 {
365 GntWidget *w = GNT_BOX(widget)->active;
366 if (w)
367 gnt_widget_set_focus(w, FALSE);
368 gnt_widget_draw(widget);
369 }
370
371 static void
372 gnt_box_gained_focus(GntWidget *widget)
373 {
374 GntWidget *w = GNT_BOX(widget)->active;
375 if (w)
376 gnt_widget_set_focus(w, TRUE);
377 gnt_widget_draw(widget);
378 }
379
380 static void
381 gnt_box_destroy(GntWidget *w)
382 {
383 GntBox *box = GNT_BOX(w);
384
385 gnt_box_remove_all(box);
386 gnt_screen_release(w);
387 }
388
389 static void
390 gnt_box_expose(GntWidget *widget, int x, int y, int width, int height)
391 {
392 WINDOW *win = newwin(height, width, widget->priv.y + y, widget->priv.x + x);
393 copywin(widget->window, win, y, x, 0, 0, height - 1, width - 1, FALSE);
394 wrefresh(win);
395 delwin(win);
396 }
397
398 static gboolean
399 gnt_box_confirm_size(GntWidget *widget, int width, int height)
400 {
401 GList *iter;
402 GntBox *box = GNT_BOX(widget);
403 int wchange, hchange;
404 GntWidget *child, *last;
405
406 if (!box->list)
407 return TRUE;
408
409 wchange = widget->priv.width - width;
410 hchange = widget->priv.height - height;
411
412 if (wchange == 0 && hchange == 0)
413 return TRUE; /* Quit playing games with my size */
414
415 child = NULL;
416 last = g_object_get_data(G_OBJECT(box), PROP_LAST_RESIZE_S);
417
418 /* First, make sure all the widgets will fit into the box after resizing. */
419 for (iter = box->list; iter; iter = iter->next) {
420 GntWidget *wid = iter->data;
421 int w, h;
422
423 gnt_widget_get_size(wid, &w, &h);
424
425 if (wid != last && !child && w > 0 && h > 0 &&
426 !GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_INVISIBLE) &&
427 gnt_widget_confirm_size(wid, w - wchange, h - hchange)) {
428 child = wid;
429 break;
430 }
431 }
432
433 if (!child && (child = last)) {
434 int w, h;
435 gnt_widget_get_size(child, &w, &h);
436 if (!gnt_widget_confirm_size(child, w - wchange, h - hchange))
437 child = NULL;
438 }
439
440 g_object_set_data(G_OBJECT(box), PROP_SIZE_QUEUED_S, child);
441
442 if (child) {
443 for (iter = box->list; iter; iter = iter->next) {
444 GntWidget *wid = iter->data;
445 int w, h;
446
447 if (wid == child)
448 continue;
449
450 gnt_widget_get_size(wid, &w, &h);
451 if (box->vertical) {
452 /* For a vertical box, if we are changing the width, make sure the widgets
453 * in the box will fit after resizing the width. */
454 if (wchange > 0 &&
455 w >= child->priv.width &&
456 !gnt_widget_confirm_size(wid, w - wchange, h))
457 return FALSE;
458 } else {
459 /* If we are changing the height, make sure the widgets in the box fit after
460 * the resize. */
461 if (hchange > 0 &&
462 h >= child->priv.height &&
463 !gnt_widget_confirm_size(wid, w, h - hchange))
464 return FALSE;
465 }
466
467 }
468 }
469
470 return (child != NULL);
471 }
472
473 static void
474 gnt_box_size_changed(GntWidget *widget, int oldw, int oldh)
475 {
476 int wchange, hchange;
477 GList *i;
478 GntBox *box = GNT_BOX(widget);
479 GntWidget *wid;
480 int tw, th;
481
482 wchange = widget->priv.width - oldw;
483 hchange = widget->priv.height - oldh;
484
485 wid = g_object_get_data(G_OBJECT(box), PROP_SIZE_QUEUED_S);
486 if (wid) {
487 gnt_widget_get_size(wid, &tw, &th);
488 gnt_widget_set_size(wid, tw + wchange, th + hchange);
489 g_object_set_data(G_OBJECT(box), PROP_SIZE_QUEUED_S, NULL);
490 g_object_set_data(G_OBJECT(box), PROP_LAST_RESIZE_S, wid);
491 }
492
493 if (box->vertical)
494 hchange = 0;
495 else
496 wchange = 0;
497
498 for (i = box->list; i; i = i->next)
499 {
500 if (wid != i->data)
501 {
502 gnt_widget_get_size(GNT_WIDGET(i->data), &tw, &th);
503 gnt_widget_set_size(i->data, tw + wchange, th + hchange);
504 }
505 }
506
507 reposition_children(widget);
508 }
509
510 static gboolean
511 gnt_box_clicked(GntWidget *widget, GntMouseEvent event, int cx, int cy)
512 {
513 GList *iter;
514 for (iter = GNT_BOX(widget)->list; iter; iter = iter->next) {
515 int x, y, w, h;
516 GntWidget *wid = iter->data;
517
518 gnt_widget_get_position(wid, &x, &y);
519 gnt_widget_get_size(wid, &w, &h);
520
521 if (cx >= x && cx < x + w && cy >= y && cy < y + h) {
522 if (event <= GNT_MIDDLE_MOUSE_DOWN &&
523 GNT_WIDGET_IS_FLAG_SET(wid, GNT_WIDGET_CAN_TAKE_FOCUS)) {
524 while (widget->parent)
525 widget = widget->parent;
526 gnt_box_give_focus_to_child(GNT_BOX(widget), wid);
527 }
528 return gnt_widget_clicked(wid, event, cx, cy);
529 }
530 }
531 return FALSE;
532 }
533
534 static void
535 gnt_box_set_property(GObject *obj, guint prop_id, const GValue *value,
536 GParamSpec *spec)
537 {
538 GntBox *box = GNT_BOX(obj);
539 switch (prop_id) {
540 case PROP_VERTICAL:
541 box->vertical = g_value_get_boolean(value);
542 break;
543 case PROP_HOMO:
544 box->homogeneous = g_value_get_boolean(value);
545 break;
546 default:
547 g_return_if_reached();
548 break;
549 }
550 }
551
552 static void
553 gnt_box_get_property(GObject *obj, guint prop_id, GValue *value,
554 GParamSpec *spec)
555 {
556 GntBox *box = GNT_BOX(obj);
557 switch (prop_id) {
558 case PROP_VERTICAL:
559 g_value_set_boolean(value, box->vertical);
560 break;
561 case PROP_HOMO:
562 g_value_set_boolean(value, box->homogeneous);
563 break;
564 default:
565 break;
566 }
567 }
568
569 static void
570 gnt_box_class_init(GntBoxClass *klass)
571 {
572 GntBindableClass *bindable = GNT_BINDABLE_CLASS(klass);
573 GObjectClass *gclass = G_OBJECT_CLASS(klass);
574 parent_class = GNT_WIDGET_CLASS(klass);
575 parent_class->destroy = gnt_box_destroy;
576 parent_class->draw = gnt_box_draw;
577 parent_class->expose = gnt_box_expose;
578 parent_class->map = gnt_box_map;
579 parent_class->size_request = gnt_box_size_request;
580 parent_class->set_position = gnt_box_set_position;
581 parent_class->key_pressed = gnt_box_key_pressed;
582 parent_class->clicked = gnt_box_clicked;
583 parent_class->lost_focus = gnt_box_lost_focus;
584 parent_class->gained_focus = gnt_box_gained_focus;
585 parent_class->confirm_size = gnt_box_confirm_size;
586 parent_class->size_changed = gnt_box_size_changed;
587
588 gclass->set_property = gnt_box_set_property;
589 gclass->get_property = gnt_box_get_property;
590 g_object_class_install_property(gclass,
591 PROP_VERTICAL,
592 g_param_spec_boolean("vertical", "Vertical",
593 "Whether the child widgets in the box should be stacked vertically.",
594 TRUE,
595 G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS
596 )
597 );
598 g_object_class_install_property(gclass,
599 PROP_HOMO,
600 g_param_spec_boolean("homogeneous", "Homogeneous",
601 "Whether the child widgets in the box should have the same size.",
602 TRUE,
603 G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS
604 )
605 );
606
607 gnt_bindable_class_register_action(bindable, "focus-next", action_focus_next,
608 "\t", NULL);
609 gnt_bindable_register_binding(bindable, "focus-next", GNT_KEY_RIGHT, NULL);
610 gnt_bindable_class_register_action(bindable, "focus-prev", action_focus_prev,
611 GNT_KEY_BACK_TAB, NULL);
612 gnt_bindable_register_binding(bindable, "focus-prev", GNT_KEY_LEFT, NULL);
613
614 gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), bindable);
615 }
616
617 static void
618 gnt_box_init(GTypeInstance *instance, gpointer class)
619 {
620 GntWidget *widget = GNT_WIDGET(instance);
621 GntBox *box = GNT_BOX(widget);
622 /* Initially make both the height and width resizable.
623 * Update the flags as necessary when widgets are added to it. */
624 GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_GROW_X | GNT_WIDGET_GROW_Y);
625 GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS | GNT_WIDGET_DISABLE_ACTIONS);
626 GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW);
627 box->pad = 1;
628 box->fill = TRUE;
629 GNTDEBUG;
630 }
631
632 /******************************************************************************
633 * GntBox API
634 *****************************************************************************/
635 GType
636 gnt_box_get_type(void)
637 {
638 static GType type = 0;
639
640 if(type == 0)
641 {
642 static const GTypeInfo info = {
643 sizeof(GntBoxClass),
644 NULL, /* base_init */
645 NULL, /* base_finalize */
646 (GClassInitFunc)gnt_box_class_init,
647 NULL, /* class_finalize */
648 NULL, /* class_data */
649 sizeof(GntBox),
650 0, /* n_preallocs */
651 gnt_box_init, /* instance_init */
652 NULL /* value_table */
653 };
654
655 type = g_type_register_static(GNT_TYPE_WIDGET,
656 "GntBox",
657 &info, 0);
658 }
659
660 return type;
661 }
662
663 GntWidget *gnt_box_new(gboolean homo, gboolean vert)
664 {
665 GntWidget *widget = g_object_new(GNT_TYPE_BOX, "homogeneous", homo,
666 "vertical", vert, NULL);
667 GntBox *box = GNT_BOX(widget);
668
669 box->alignment = vert ? GNT_ALIGN_LEFT : GNT_ALIGN_MID;
670
671 return widget;
672 }
673
674 void gnt_box_add_widget(GntBox *b, GntWidget *widget)
675 {
676 b->list = g_list_append(b->list, widget);
677 widget->parent = GNT_WIDGET(b);
678 }
679
680 void gnt_box_add_widget_in_front(GntBox *b, GntWidget *widget)
681 {
682 b->list = g_list_prepend(b->list, widget);
683 widget->parent = GNT_WIDGET(b);
684 }
685
686 void gnt_box_set_title(GntBox *b, const char *title)
687 {
688 char *prev = b->title;
689 GntWidget *w = GNT_WIDGET(b);
690 b->title = g_strdup(title);
691 if (w->window && !GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_NO_BORDER)) {
692 /* Erase the old title */
693 int pos, right;
694 get_title_thingies(b, prev, &pos, &right);
695 mvwhline(w->window, 0, pos - 1, ACS_HLINE | gnt_color_pair(GNT_COLOR_NORMAL),
696 right - pos + 2);
697 }
698 g_free(prev);
699 }
700
701 void gnt_box_set_pad(GntBox *box, int pad)
702 {
703 box->pad = pad;
704 /* XXX: Perhaps redraw if already showing? */
705 }
706
707 void gnt_box_set_toplevel(GntBox *box, gboolean set)
708 {
709 GntWidget *widget = GNT_WIDGET(box);
710 if (set)
711 {
712 GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW);
713 GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS);
714 }
715 else
716 {
717 GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW);
718 GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS);
719 }
720 }
721
722 void gnt_box_sync_children(GntBox *box)
723 {
724 GList *iter;
725 GntWidget *widget = GNT_WIDGET(box);
726 int pos = 1;
727
728 if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER))
729 pos = 0;
730
731 if (!box->active)
732 find_focusable_widget(box);
733
734 for (iter = box->list; iter; iter = iter->next)
735 {
736 GntWidget *w = GNT_WIDGET(iter->data);
737 int height, width;
738 int x, y;
739
740 if (G_UNLIKELY(w == NULL)) {
741 g_warn_if_reached();
742 continue;
743 }
744
745 if (GNT_WIDGET_IS_FLAG_SET(w, GNT_WIDGET_INVISIBLE))
746 continue;
747
748 if (GNT_IS_BOX(w))
749 gnt_box_sync_children(GNT_BOX(w));
750
751 gnt_widget_get_size(w, &width, &height);
752
753 x = w->priv.x - widget->priv.x;
754 y = w->priv.y - widget->priv.y;
755
756 if (box->vertical)
757 {
758 x = pos;
759 if (box->alignment == GNT_ALIGN_RIGHT)
760 x += widget->priv.width - width;
761 else if (box->alignment == GNT_ALIGN_MID)
762 x += (widget->priv.width - width)/2;
763 if (x + width > widget->priv.width - pos)
764 x -= x + width - (widget->priv.width - pos);
765 }
766 else
767 {
768 y = pos;
769 if (box->alignment == GNT_ALIGN_BOTTOM)
770 y += widget->priv.height - height;
771 else if (box->alignment == GNT_ALIGN_MID)
772 y += (widget->priv.height - height)/2;
773 if (y + height >= widget->priv.height - pos)
774 y = widget->priv.height - height - pos;
775 }
776
777 copywin(w->window, widget->window, 0, 0,
778 y, x, y + height - 1, x + width - 1, FALSE);
779 gnt_widget_set_position(w, x + widget->priv.x, y + widget->priv.y);
780 if (w == box->active) {
781 wmove(widget->window, y + getcury(w->window), x + getcurx(w->window));
782 }
783 }
784 }
785
786 void gnt_box_set_alignment(GntBox *box, GntAlignment alignment)
787 {
788 box->alignment = alignment;
789 }
790
791 void gnt_box_remove(GntBox *box, GntWidget *widget)
792 {
793 box->list = g_list_remove(box->list, widget);
794 if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_CAN_TAKE_FOCUS)
795 && GNT_WIDGET(box)->parent == NULL && box->focus)
796 {
797 if (widget == box->active)
798 {
799 find_next_focus(box);
800 if (box->active == widget) /* There's only one widget */
801 box->active = NULL;
802 }
803 box->focus = g_list_remove(box->focus, widget);
804 }
805
806 if (GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(box), GNT_WIDGET_MAPPED))
807 gnt_widget_draw(GNT_WIDGET(box));
808 }
809
810 void gnt_box_remove_all(GntBox *box)
811 {
812 g_list_foreach(box->list, (GFunc)gnt_widget_destroy, NULL);
813 g_list_free(box->list);
814 g_list_free(box->focus);
815 box->list = NULL;
816 box->focus = NULL;
817 GNT_WIDGET(box)->priv.width = 0;
818 GNT_WIDGET(box)->priv.height = 0;
819 }
820
821 void gnt_box_readjust(GntBox *box)
822 {
823 GList *iter;
824 GntWidget *wid;
825 int width, height;
826
827 if (GNT_WIDGET(box)->parent != NULL)
828 return;
829
830 for (iter = box->list; iter; iter = iter->next)
831 {
832 GntWidget *w = iter->data;
833
834 if (G_UNLIKELY(w == NULL)) {
835 g_warn_if_reached();
836 continue;
837 }
838
839 if (GNT_IS_BOX(w))
840 gnt_box_readjust(GNT_BOX(w));
841 else
842 {
843 GNT_WIDGET_UNSET_FLAGS(w, GNT_WIDGET_MAPPED);
844 w->priv.width = 0;
845 w->priv.height = 0;
846 }
847 }
848
849 wid = GNT_WIDGET(box);
850 GNT_WIDGET_UNSET_FLAGS(wid, GNT_WIDGET_MAPPED);
851 wid->priv.width = 0;
852 wid->priv.height = 0;
853
854 if (wid->parent == NULL)
855 {
856 g_list_free(box->focus);
857 box->focus = NULL;
858 box->active = NULL;
859 gnt_widget_size_request(wid);
860 gnt_widget_get_size(wid, &width, &height);
861 gnt_screen_resize_widget(wid, width, height);
862 find_focusable_widget(box);
863 }
864 }
865
866 void gnt_box_set_fill(GntBox *box, gboolean fill)
867 {
868 box->fill = fill;
869 }
870
871 void gnt_box_move_focus(GntBox *box, int dir)
872 {
873 GntWidget *now;
874
875 if (box->active == NULL)
876 {
877 find_focusable_widget(box);
878 return;
879 }
880
881 now = box->active;
882
883 if (dir == 1)
884 find_next_focus(box);
885 else if (dir == -1)
886 find_prev_focus(box);
887
888 if (now && now != box->active)
889 {
890 gnt_widget_set_focus(now, FALSE);
891 gnt_widget_set_focus(box->active, TRUE);
892 }
893
894 if (GNT_WIDGET(box)->window)
895 gnt_widget_draw(GNT_WIDGET(box));
896 }
897
898 void gnt_box_give_focus_to_child(GntBox *box, GntWidget *widget)
899 {
900 GList *find;
901 gpointer now;
902
903 while (GNT_WIDGET(box)->parent)
904 box = GNT_BOX(GNT_WIDGET(box)->parent);
905
906 find = g_list_find(box->focus, widget);
907 now = box->active;
908 if (find)
909 box->active = widget;
910 if (now && now != box->active)
911 {
912 gnt_widget_set_focus(now, FALSE);
913 gnt_widget_set_focus(box->active, TRUE);
914 }
915
916 if (GNT_WIDGET(box)->window)
917 gnt_widget_draw(GNT_WIDGET(box));
918 }
919

mercurial