|
1 /* |
|
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2017 Olaf Wintermann. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
26 * POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #include <stdio.h> |
|
30 #include <stdlib.h> |
|
31 #include <limits.h> |
|
32 |
|
33 #include "container.h" |
|
34 #include "toolkit.h" |
|
35 |
|
36 #include "../common/context.h" |
|
37 #include "../common/object.h" |
|
38 |
|
39 |
|
40 void ui_container_begin_close(UiObject *obj) { |
|
41 UiContainer *ct = uic_get_current_container(obj); |
|
42 ct->close = 1; |
|
43 } |
|
44 |
|
45 int ui_container_finish(UiObject *obj) { |
|
46 UiContainer *ct = uic_get_current_container(obj); |
|
47 if(ct->close) { |
|
48 ui_end(obj); |
|
49 return 0; |
|
50 } |
|
51 return 1; |
|
52 } |
|
53 |
|
54 GtkWidget* ui_gtk_vbox_new(int spacing) { |
|
55 #ifdef UI_GTK3 |
|
56 return gtk_box_new(GTK_ORIENTATION_VERTICAL, spacing); |
|
57 #else |
|
58 return gtk_vbox_new(FALSE, spacing); |
|
59 #endif |
|
60 } |
|
61 |
|
62 GtkWidget* ui_gtk_hbox_new(int spacing) { |
|
63 #ifdef UI_GTK3 |
|
64 return gtk_box_new(GTK_ORIENTATION_HORIZONTAL, spacing); |
|
65 #else |
|
66 return gtk_hbox_new(FALSE, spacing); |
|
67 #endif |
|
68 } |
|
69 |
|
70 /* -------------------- Frame Container (deprecated) -------------------- */ |
|
71 UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) { |
|
72 UiContainer *ct = ucx_mempool_calloc( |
|
73 obj->ctx->mempool, |
|
74 1, |
|
75 sizeof(UiContainer)); |
|
76 ct->widget = frame; |
|
77 ct->add = ui_frame_container_add; |
|
78 return ct; |
|
79 } |
|
80 |
|
81 void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
82 gtk_container_add(GTK_CONTAINER(ct->widget), widget); |
|
83 ui_reset_layout(ct->layout); |
|
84 ct->current = widget; |
|
85 } |
|
86 |
|
87 |
|
88 /* -------------------- Box Container -------------------- */ |
|
89 UiContainer* ui_box_container(UiObject *obj, GtkWidget *box) { |
|
90 UiBoxContainer *ct = ucx_mempool_calloc( |
|
91 obj->ctx->mempool, |
|
92 1, |
|
93 sizeof(UiBoxContainer)); |
|
94 ct->container.widget = box; |
|
95 ct->container.add = ui_box_container_add; |
|
96 return (UiContainer*)ct; |
|
97 } |
|
98 |
|
99 void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
100 UiBoxContainer *bc = (UiBoxContainer*)ct; |
|
101 if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { |
|
102 fill = ui_lb2bool(ct->layout.fill); |
|
103 } |
|
104 |
|
105 if(bc->has_fill && fill) { |
|
106 fprintf(stderr, "UiError: container has 2 filled widgets"); |
|
107 fill = FALSE; |
|
108 } |
|
109 if(fill) { |
|
110 bc->has_fill = TRUE; |
|
111 } |
|
112 |
|
113 UiBool expand = fill; |
|
114 gtk_box_pack_start(GTK_BOX(ct->widget), widget, expand, fill, 0); |
|
115 |
|
116 ui_reset_layout(ct->layout); |
|
117 ct->current = widget; |
|
118 } |
|
119 |
|
120 UiContainer* ui_grid_container(UiObject *obj, GtkWidget *grid) { |
|
121 UiGridContainer *ct = ucx_mempool_calloc( |
|
122 obj->ctx->mempool, |
|
123 1, |
|
124 sizeof(UiGridContainer)); |
|
125 ct->container.widget = grid; |
|
126 ct->container.add = ui_grid_container_add; |
|
127 #ifdef UI_GTK2 |
|
128 ct->width = 0; |
|
129 ct->height = 1; |
|
130 #endif |
|
131 return (UiContainer*)ct; |
|
132 } |
|
133 |
|
134 #ifdef UI_GTK3 |
|
135 void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
136 UiGridContainer *grid = (UiGridContainer*)ct; |
|
137 |
|
138 if(ct->layout.newline) { |
|
139 grid->x = 0; |
|
140 grid->y++; |
|
141 ct->layout.newline = FALSE; |
|
142 } |
|
143 |
|
144 int hexpand = FALSE; |
|
145 int vexpand = FALSE; |
|
146 if(ct->layout.hexpand != UI_LAYOUT_UNDEFINED) { |
|
147 hexpand = ct->layout.hexpand; |
|
148 } |
|
149 if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) { |
|
150 vexpand = ct->layout.vexpand; |
|
151 } |
|
152 |
|
153 if(hexpand) { |
|
154 gtk_widget_set_hexpand(widget, TRUE); |
|
155 } |
|
156 if(vexpand) { |
|
157 gtk_widget_set_vexpand(widget, TRUE); |
|
158 } |
|
159 |
|
160 int gwidth = ct->layout.gridwidth > 0 ? ct->layout.gridwidth : 1; |
|
161 |
|
162 gtk_grid_attach(GTK_GRID(ct->widget), widget, grid->x, grid->y, gwidth, 1); |
|
163 grid->x += gwidth; |
|
164 |
|
165 ui_reset_layout(ct->layout); |
|
166 ct->current = widget; |
|
167 } |
|
168 #endif |
|
169 #ifdef UI_GTK2 |
|
170 void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
171 UiGridContainer *grid = (UiGridContainer*)ct; |
|
172 |
|
173 if(ct->layout.newline) { |
|
174 grid->x = 0; |
|
175 grid->y++; |
|
176 ct->layout.newline = FALSE; |
|
177 } |
|
178 |
|
179 int hexpand = FALSE; |
|
180 int vexpand = FALSE; |
|
181 if(ct->layout.hexpand != UI_LAYOUT_UNDEFINED) { |
|
182 hexpand = ct->layout.hexpand; |
|
183 } |
|
184 if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) { |
|
185 vexpand = ct->layout.vexpand; |
|
186 } |
|
187 GtkAttachOptions xoptions = hexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; |
|
188 GtkAttachOptions yoptions = vexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; |
|
189 |
|
190 gtk_table_attach(GTK_TABLE(ct->widget), widget, grid->x, grid->x+1, grid->y, grid->y+1, xoptions, yoptions, 0, 0); |
|
191 grid->x++; |
|
192 int nw = grid->x > grid->width ? grid->x : grid->width; |
|
193 if(grid->x > grid->width || grid->y > grid->height) { |
|
194 grid->width = nw; |
|
195 grid->height = grid->y + 1; |
|
196 gtk_table_resize(GTK_TABLE(ct->widget), grid->width, grid->height); |
|
197 } |
|
198 |
|
199 ui_reset_layout(ct->layout); |
|
200 ct->current = widget; |
|
201 } |
|
202 #endif |
|
203 |
|
204 UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) { |
|
205 UiContainer *ct = ucx_mempool_calloc( |
|
206 obj->ctx->mempool, |
|
207 1, |
|
208 sizeof(UiContainer)); |
|
209 ct->widget = scrolledwindow; |
|
210 ct->add = ui_scrolledwindow_container_add; |
|
211 return ct; |
|
212 } |
|
213 |
|
214 void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
215 // TODO: check if the widget implements GtkScrollable |
|
216 #ifdef UI_GTK3 |
|
217 gtk_container_add(GTK_CONTAINER(ct->widget), widget); |
|
218 #else |
|
219 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ct->widget), widget); |
|
220 #endif |
|
221 ui_reset_layout(ct->layout); |
|
222 ct->current = widget; |
|
223 } |
|
224 |
|
225 UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) { |
|
226 UiTabViewContainer *ct = ucx_mempool_calloc( |
|
227 obj->ctx->mempool, |
|
228 1, |
|
229 sizeof(UiTabViewContainer)); |
|
230 ct->container.widget = tabview; |
|
231 ct->container.add = ui_tabview_container_add; |
|
232 return (UiContainer*)ct; |
|
233 } |
|
234 |
|
235 void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
236 gtk_notebook_append_page( |
|
237 GTK_NOTEBOOK(ct->widget), |
|
238 widget, |
|
239 gtk_label_new(ct->layout.label)); |
|
240 |
|
241 ui_reset_layout(ct->layout); |
|
242 ct->current = widget; |
|
243 } |
|
244 |
|
245 |
|
246 UIWIDGET ui_vbox(UiObject *obj) { |
|
247 return ui_vbox_sp(obj, 0, 0); |
|
248 } |
|
249 |
|
250 UIWIDGET ui_hbox(UiObject *obj) { |
|
251 return ui_hbox_sp(obj, 0, 0); |
|
252 } |
|
253 |
|
254 static GtkWidget* box_set_margin(GtkWidget *box, int margin) { |
|
255 GtkWidget *ret = box; |
|
256 #ifdef UI_GTK3 |
|
257 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 12 |
|
258 gtk_widget_set_margin_start(box, margin); |
|
259 gtk_widget_set_margin_end(box, margin); |
|
260 #else |
|
261 gtk_widget_set_margin_left(box, margin); |
|
262 gtk_widget_set_margin_right(box, margin); |
|
263 #endif |
|
264 gtk_widget_set_margin_top(box, margin); |
|
265 gtk_widget_set_margin_bottom(box, margin); |
|
266 #elif defined(UI_GTK2) |
|
267 GtkWidget *a = gtk_alignment_new(0.5, 0.5, 1, 1); |
|
268 gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin, margin, margin, margin); |
|
269 gtk_container_add(GTK_CONTAINER(a), box); |
|
270 ret = a; |
|
271 #endif |
|
272 return ret; |
|
273 } |
|
274 |
|
275 UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) { |
|
276 UiContainer *ct = uic_get_current_container(obj); |
|
277 |
|
278 GtkWidget *vbox = ui_gtk_vbox_new(spacing); |
|
279 GtkWidget *widget = margin > 0 ? box_set_margin(vbox, margin) : vbox; |
|
280 ct->add(ct, widget, TRUE); |
|
281 |
|
282 UiObject *newobj = uic_object_new(obj, vbox); |
|
283 newobj->container = ui_box_container(obj, vbox); |
|
284 uic_obj_add(obj, newobj); |
|
285 |
|
286 return widget; |
|
287 } |
|
288 |
|
289 UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) { |
|
290 UiContainer *ct = uic_get_current_container(obj); |
|
291 |
|
292 GtkWidget *hbox = ui_gtk_hbox_new(spacing); |
|
293 GtkWidget *widget = margin > 0 ? box_set_margin(hbox, margin) : hbox; |
|
294 ct->add(ct, widget, TRUE); |
|
295 |
|
296 UiObject *newobj = uic_object_new(obj, hbox); |
|
297 newobj->container = ui_box_container(obj, hbox); |
|
298 uic_obj_add(obj, newobj); |
|
299 |
|
300 return widget; |
|
301 } |
|
302 |
|
303 UIWIDGET ui_grid(UiObject *obj) { |
|
304 return ui_grid_sp(obj, 0, 0, 0); |
|
305 } |
|
306 |
|
307 UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) { |
|
308 UiContainer *ct = uic_get_current_container(obj); |
|
309 GtkWidget *widget; |
|
310 |
|
311 #ifdef UI_GTK3 |
|
312 GtkWidget *grid = gtk_grid_new(); |
|
313 gtk_grid_set_column_spacing(GTK_GRID(grid), columnspacing); |
|
314 gtk_grid_set_row_spacing(GTK_GRID(grid), rowspacing); |
|
315 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 12 |
|
316 gtk_widget_set_margin_start(grid, margin); |
|
317 gtk_widget_set_margin_end(grid, margin); |
|
318 #else |
|
319 gtk_widget_set_margin_left(grid, margin); |
|
320 gtk_widget_set_margin_right(grid, margin); |
|
321 #endif |
|
322 gtk_widget_set_margin_top(grid, margin); |
|
323 gtk_widget_set_margin_bottom(grid, margin); |
|
324 |
|
325 widget = grid; |
|
326 #elif defined(UI_GTK2) |
|
327 GtkWidget *grid = gtk_table_new(1, 1, FALSE); |
|
328 |
|
329 gtk_table_set_col_spacings(GTK_TABLE(grid), columnspacing); |
|
330 gtk_table_set_row_spacings(GTK_TABLE(grid), rowspacing); |
|
331 |
|
332 if(margin > 0) { |
|
333 GtkWidget *a = gtk_alignment_new(0.5, 0.5, 1, 1); |
|
334 gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin, margin, margin, margin); |
|
335 gtk_container_add(GTK_CONTAINER(a), grid); |
|
336 widget = a; |
|
337 } else { |
|
338 widget = grid; |
|
339 } |
|
340 #endif |
|
341 ct->add(ct, widget, TRUE); |
|
342 |
|
343 UiObject *newobj = uic_object_new(obj, grid); |
|
344 newobj->container = ui_grid_container(obj, grid); |
|
345 uic_obj_add(obj, newobj); |
|
346 |
|
347 return widget; |
|
348 } |
|
349 |
|
350 UIWIDGET ui_scrolledwindow(UiObject *obj) { |
|
351 UiContainer *ct = uic_get_current_container(obj); |
|
352 GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); |
|
353 ct->add(ct, sw, TRUE); |
|
354 |
|
355 UiObject *newobj = uic_object_new(obj, sw); |
|
356 newobj->container = ui_scrolledwindow_container(obj, sw); |
|
357 uic_obj_add(obj, newobj); |
|
358 |
|
359 return sw; |
|
360 } |
|
361 |
|
362 UIWIDGET ui_tabview(UiObject *obj) { |
|
363 GtkWidget *tabview = gtk_notebook_new(); |
|
364 gtk_notebook_set_show_border(GTK_NOTEBOOK(tabview), FALSE); |
|
365 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(tabview), FALSE); |
|
366 |
|
367 UiContainer *ct = uic_get_current_container(obj); |
|
368 ct->add(ct, tabview, TRUE); |
|
369 |
|
370 UiObject *tabviewobj = uic_object_new(obj, tabview); |
|
371 tabviewobj->container = ui_tabview_container(obj, tabview); |
|
372 uic_obj_add(obj, tabviewobj); |
|
373 |
|
374 return tabview; |
|
375 } |
|
376 |
|
377 void ui_tab(UiObject *obj, char *title) { |
|
378 UiContainer *ct = uic_get_current_container(obj); |
|
379 ct->layout.label = title; |
|
380 ui_vbox(obj); |
|
381 } |
|
382 |
|
383 void ui_select_tab(UIWIDGET tabview, int tab) { |
|
384 gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab); |
|
385 } |
|
386 |
|
387 /* -------------------- Splitpane -------------------- */ |
|
388 |
|
389 static GtkWidget* create_paned(UiOrientation orientation) { |
|
390 #ifdef UI_GTK3 |
|
391 switch(orientation) { |
|
392 case UI_HORIZONTAL: return gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); |
|
393 case UI_VERTICAL: return gtk_paned_new(GTK_ORIENTATION_VERTICAL); |
|
394 } |
|
395 #else |
|
396 switch(orientation) { |
|
397 case UI_HORIZONTAL: return gtk_hpaned_new(); |
|
398 case UI_VERTICAL: return gtk_vpaned_new(); |
|
399 } |
|
400 #endif |
|
401 return NULL; |
|
402 } |
|
403 |
|
404 UIWIDGET ui_splitpane(UiObject *obj, int max, UiOrientation orientation) { |
|
405 GtkWidget *paned = create_paned(orientation); |
|
406 UiContainer *ct = uic_get_current_container(obj); |
|
407 ct->add(ct, paned, TRUE); |
|
408 |
|
409 if(max <= 0) max = INT_MAX; |
|
410 |
|
411 UiPanedContainer *pctn = ucx_mempool_calloc( |
|
412 obj->ctx->mempool, |
|
413 1, |
|
414 sizeof(UiPanedContainer)); |
|
415 pctn->container.widget = paned; |
|
416 pctn->container.add = ui_paned_container_add; |
|
417 pctn->current_pane = paned; |
|
418 pctn->orientation = orientation; |
|
419 pctn->max = max; |
|
420 pctn->cur = 0; |
|
421 |
|
422 UiObject *pobj = uic_object_new(obj, paned); |
|
423 pobj->container = (UiContainer*)pctn; |
|
424 |
|
425 uic_obj_add(obj, pobj); |
|
426 |
|
427 return paned; |
|
428 } |
|
429 |
|
430 UIWIDGET ui_hsplitpane(UiObject *obj, int max) { |
|
431 return ui_splitpane(obj, max, UI_HORIZONTAL); |
|
432 } |
|
433 |
|
434 UIWIDGET ui_vsplitpane(UiObject *obj, int max) { |
|
435 return ui_splitpane(obj, max, UI_VERTICAL); |
|
436 } |
|
437 |
|
438 void ui_paned_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
439 UiPanedContainer *pctn = (UiPanedContainer*)ct; |
|
440 |
|
441 gboolean resize = (ct->layout.hexpand || ct->layout.vexpand) ? TRUE : FALSE; |
|
442 int width = ct->layout.width; |
|
443 ui_reset_layout(ct->layout); |
|
444 |
|
445 if(pctn->cur == 0) { |
|
446 gtk_paned_pack1(GTK_PANED(pctn->current_pane), widget, resize, resize); |
|
447 } else if(pctn->cur < pctn->max-1) { |
|
448 GtkWidget *nextPane = create_paned(pctn->orientation); |
|
449 gtk_paned_pack2(GTK_PANED(pctn->current_pane), nextPane, TRUE, TRUE); |
|
450 gtk_paned_pack1(GTK_PANED(nextPane), widget, resize, resize); |
|
451 pctn->current_pane = nextPane; |
|
452 } else if(pctn->cur == pctn->max-1) { |
|
453 gtk_paned_pack2(GTK_PANED(pctn->current_pane), widget, resize, resize); |
|
454 width = 0; // disable potential call of gtk_paned_set_position |
|
455 } else { |
|
456 fprintf(stderr, "Splitpane max reached: %d\n", pctn->max); |
|
457 return; |
|
458 } |
|
459 |
|
460 if(width > 0) { |
|
461 gtk_paned_set_position(GTK_PANED(pctn->current_pane), width); |
|
462 } |
|
463 |
|
464 pctn->cur++; |
|
465 } |
|
466 |
|
467 |
|
468 /* -------------------- Sidebar (deprecated) -------------------- */ |
|
469 UIWIDGET ui_sidebar(UiObject *obj) { |
|
470 #ifdef UI_GTK3 |
|
471 GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); |
|
472 #else |
|
473 GtkWidget *paned = gtk_hpaned_new(); |
|
474 #endif |
|
475 gtk_paned_set_position(GTK_PANED(paned), 200); |
|
476 |
|
477 GtkWidget *sidebar = ui_gtk_vbox_new(0); |
|
478 gtk_paned_pack1(GTK_PANED(paned), sidebar, TRUE, FALSE); |
|
479 |
|
480 UiObject *left = uic_object_new(obj, sidebar); |
|
481 UiContainer *ct1 = ui_box_container(obj, sidebar); |
|
482 left->container = ct1; |
|
483 |
|
484 UiObject *right = uic_object_new(obj, sidebar); |
|
485 UiContainer *ct2 = ucx_mempool_malloc( |
|
486 obj->ctx->mempool, |
|
487 sizeof(UiContainer)); |
|
488 ct2->widget = paned; |
|
489 ct2->add = ui_split_container_add2; |
|
490 right->container = ct2; |
|
491 |
|
492 UiContainer *ct = uic_get_current_container(obj); |
|
493 ct->add(ct, paned, TRUE); |
|
494 |
|
495 uic_obj_add(obj, right); |
|
496 uic_obj_add(obj, left); |
|
497 |
|
498 return sidebar; |
|
499 } |
|
500 |
|
501 void ui_split_container_add1(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
502 // TODO: remove |
|
503 gtk_paned_pack1(GTK_PANED(ct->widget), widget, TRUE, FALSE); |
|
504 |
|
505 ui_reset_layout(ct->layout); |
|
506 ct->current = widget; |
|
507 } |
|
508 |
|
509 void ui_split_container_add2(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
510 gtk_paned_pack2(GTK_PANED(ct->widget), widget, TRUE, FALSE); |
|
511 |
|
512 ui_reset_layout(ct->layout); |
|
513 ct->current = widget; |
|
514 } |
|
515 |
|
516 |
|
517 /* -------------------- Document Tabview -------------------- */ |
|
518 static void page_change(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data) { |
|
519 GQuark q = g_quark_from_static_string("ui.tab.object"); |
|
520 UiObject *tab = g_object_get_qdata(G_OBJECT(page), q); |
|
521 if(!tab) { |
|
522 return; |
|
523 } |
|
524 |
|
525 //printf("page_change: %d\n", page_num); |
|
526 UiContext *ctx = tab->ctx; |
|
527 uic_context_detach_all(ctx->parent); // TODO: fix? |
|
528 ctx->parent->attach_document(ctx->parent, ctx->document); |
|
529 } |
|
530 |
|
531 UiTabbedPane* ui_tabbed_document_view(UiObject *obj) { |
|
532 GtkWidget *tabview = gtk_notebook_new(); |
|
533 gtk_notebook_set_show_border(GTK_NOTEBOOK(tabview), FALSE); |
|
534 |
|
535 g_signal_connect( |
|
536 tabview, |
|
537 "switch-page", |
|
538 G_CALLBACK(page_change), |
|
539 NULL); |
|
540 |
|
541 UiContainer *ct = uic_get_current_container(obj); |
|
542 ct->add(ct, tabview, TRUE); |
|
543 |
|
544 UiTabbedPane *tabbedpane = ui_malloc(obj->ctx, sizeof(UiTabbedPane)); |
|
545 tabbedpane->ctx = uic_current_obj(obj)->ctx; |
|
546 tabbedpane->widget = tabview; |
|
547 tabbedpane->document = NULL; |
|
548 |
|
549 return tabbedpane; |
|
550 } |
|
551 |
|
552 UiObject* ui_document_tab(UiTabbedPane *view) { |
|
553 GtkWidget *frame = gtk_frame_new(NULL); |
|
554 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE); |
|
555 // TODO: label |
|
556 gtk_notebook_append_page(GTK_NOTEBOOK(view->widget), frame, NULL); |
|
557 |
|
558 UiObject *tab = ui_malloc(view->ctx, sizeof(UiObject)); |
|
559 tab->widget = NULL; // initialization for uic_context() |
|
560 tab->ctx = uic_context(tab, view->ctx->mempool); |
|
561 tab->ctx->parent = view->ctx; |
|
562 tab->ctx->attach_document = uic_context_attach_document; |
|
563 tab->ctx->detach_document2 = uic_context_detach_document2; |
|
564 tab->widget = frame; |
|
565 tab->window = view->ctx->obj->window; |
|
566 tab->container = ui_frame_container(tab, frame); |
|
567 tab->next = NULL; |
|
568 |
|
569 GQuark q = g_quark_from_static_string("ui.tab.object"); |
|
570 g_object_set_qdata(G_OBJECT(frame), q, tab); |
|
571 |
|
572 return tab; |
|
573 } |
|
574 |
|
575 void ui_tab_set_document(UiContext *ctx, void *document) { |
|
576 // TODO: remove? |
|
577 if(ctx->parent->document) { |
|
578 //ctx->parent->detach_document(ctx->parent, ctx->parent->document); |
|
579 } |
|
580 //uic_context_set_document(ctx, document); |
|
581 //uic_context_set_document(ctx->parent, document); |
|
582 //ctx->parent->document = document; |
|
583 } |
|
584 |
|
585 void ui_tab_detach_document(UiContext *ctx) { |
|
586 // TODO: remove? |
|
587 //uic_context_detach_document(ctx->parent); |
|
588 } |
|
589 |
|
590 |
|
591 /* |
|
592 * -------------------- Layout Functions -------------------- |
|
593 * |
|
594 * functions for setting layout attributes for the current container |
|
595 * |
|
596 */ |
|
597 |
|
598 void ui_layout_fill(UiObject *obj, UiBool fill) { |
|
599 UiContainer *ct = uic_get_current_container(obj); |
|
600 ct->layout.fill = ui_bool2lb(fill); |
|
601 } |
|
602 |
|
603 void ui_layout_hexpand(UiObject *obj, UiBool expand) { |
|
604 UiContainer *ct = uic_get_current_container(obj); |
|
605 ct->layout.hexpand = expand; |
|
606 } |
|
607 |
|
608 void ui_layout_vexpand(UiObject *obj, UiBool expand) { |
|
609 UiContainer *ct = uic_get_current_container(obj); |
|
610 ct->layout.vexpand = expand; |
|
611 } |
|
612 |
|
613 void ui_layout_width(UiObject *obj, int width) { |
|
614 UiContainer *ct = uic_get_current_container(obj); |
|
615 ct->layout.width = width; |
|
616 } |
|
617 |
|
618 void ui_layout_gridwidth(UiObject *obj, int width) { |
|
619 UiContainer *ct = uic_get_current_container(obj); |
|
620 ct->layout.gridwidth = width; |
|
621 } |
|
622 |
|
623 void ui_newline(UiObject *obj) { |
|
624 UiContainer *ct = uic_get_current_container(obj); |
|
625 ct->layout.newline = TRUE; |
|
626 } |
|
627 |