ui/gtk/container.c

changeset 431
bb7da585debc
parent 422
c1354a29a7e9
child 440
7c4b9cba09ca
equal deleted inserted replaced
169:fe49cff3c571 431:bb7da585debc
30 #include <stdlib.h> 30 #include <stdlib.h>
31 #include <limits.h> 31 #include <limits.h>
32 32
33 #include "container.h" 33 #include "container.h"
34 #include "toolkit.h" 34 #include "toolkit.h"
35 #include "headerbar.h"
35 36
36 #include "../common/context.h" 37 #include "../common/context.h"
37 #include "../common/object.h" 38 #include "../common/object.h"
38 39
39 40
50 } 51 }
51 return 1; 52 return 1;
52 } 53 }
53 54
54 GtkWidget* ui_gtk_vbox_new(int spacing) { 55 GtkWidget* ui_gtk_vbox_new(int spacing) {
55 #ifdef UI_GTK3 56 #if GTK_MAJOR_VERSION >= 3
56 return gtk_box_new(GTK_ORIENTATION_VERTICAL, spacing); 57 return gtk_box_new(GTK_ORIENTATION_VERTICAL, spacing);
57 #else 58 #else
58 return gtk_vbox_new(FALSE, spacing); 59 return gtk_vbox_new(FALSE, spacing);
59 #endif 60 #endif
60 } 61 }
61 62
62 GtkWidget* ui_gtk_hbox_new(int spacing) { 63 GtkWidget* ui_gtk_hbox_new(int spacing) {
63 #ifdef UI_GTK3 64 #if GTK_MAJOR_VERSION >= 3
64 return gtk_box_new(GTK_ORIENTATION_HORIZONTAL, spacing); 65 return gtk_box_new(GTK_ORIENTATION_HORIZONTAL, spacing);
65 #else 66 #else
66 return gtk_hbox_new(FALSE, spacing); 67 return gtk_hbox_new(FALSE, spacing);
67 #endif 68 #endif
68 } 69 }
69 70
70 /* -------------------- Frame Container (deprecated) -------------------- */ 71 GtkWidget* ui_subcontainer_create(
71 UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) { 72 UiSubContainerType type,
72 UiContainer *ct = ucx_mempool_calloc( 73 UiObject *newobj,
73 obj->ctx->mempool, 74 int spacing,
74 1, 75 int columnspacing,
75 sizeof(UiContainer)); 76 int rowspacing,
76 ct->widget = frame; 77 int margin)
77 ct->add = ui_frame_container_add; 78 {
78 return ct; 79 GtkWidget *sub = NULL;
79 } 80 GtkWidget *add = NULL;
80 81 switch(type) {
81 void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { 82 default: {
82 gtk_container_add(GTK_CONTAINER(ct->widget), widget); 83 sub = ui_gtk_vbox_new(spacing);
83 ui_reset_layout(ct->layout); 84 add = ui_box_set_margin(sub, margin);
84 ct->current = widget; 85 newobj->container = ui_box_container(newobj, sub, type);
86 newobj->widget = sub;
87 break;
88 }
89 case UI_CONTAINER_HBOX: {
90 sub = ui_gtk_hbox_new(spacing);
91 add = ui_box_set_margin(sub, margin);
92 newobj->container = ui_box_container(newobj, sub, type);
93 newobj->widget = sub;
94 break;
95 }
96 case UI_CONTAINER_GRID: {
97 sub = ui_create_grid_widget(columnspacing, rowspacing);
98 add = ui_box_set_margin(sub, margin);
99 newobj->container = ui_grid_container(newobj, sub);
100 newobj->widget = sub;
101 break;
102 }
103 case UI_CONTAINER_NO_SUB: {
104 break;
105 }
106 }
107 return add;
85 } 108 }
86 109
87 110
88 /* -------------------- Box Container -------------------- */ 111 /* -------------------- Box Container -------------------- */
89 UiContainer* ui_box_container(UiObject *obj, GtkWidget *box) { 112 UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) {
90 UiBoxContainer *ct = ucx_mempool_calloc( 113 UiBoxContainer *ct = cxCalloc(
91 obj->ctx->mempool, 114 obj->ctx->allocator,
92 1, 115 1,
93 sizeof(UiBoxContainer)); 116 sizeof(UiBoxContainer));
94 ct->container.widget = box; 117 ct->container.widget = box;
95 ct->container.add = ui_box_container_add; 118 ct->container.add = ui_box_container_add;
119 ct->type = type;
96 return (UiContainer*)ct; 120 return (UiContainer*)ct;
97 } 121 }
98 122
99 void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { 123 void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
100 UiBoxContainer *bc = (UiBoxContainer*)ct; 124 UiBoxContainer *bc = (UiBoxContainer*)ct;
109 if(fill) { 133 if(fill) {
110 bc->has_fill = TRUE; 134 bc->has_fill = TRUE;
111 } 135 }
112 136
113 UiBool expand = fill; 137 UiBool expand = fill;
138 #if GTK_MAJOR_VERSION >= 4
139 gtk_box_append(GTK_BOX(ct->widget), widget);
140 GtkAlign align = expand ? GTK_ALIGN_FILL : GTK_ALIGN_START;
141 if(bc->type == UI_CONTAINER_VBOX) {
142 gtk_widget_set_valign(widget, align);
143 gtk_widget_set_vexpand(widget, expand);
144 gtk_widget_set_hexpand(widget, TRUE);
145 } else if(bc->type == UI_CONTAINER_HBOX) {
146 gtk_widget_set_halign(widget, align);
147 gtk_widget_set_hexpand(widget, expand);
148 gtk_widget_set_vexpand(widget, TRUE);
149 }
150
151 #else
114 gtk_box_pack_start(GTK_BOX(ct->widget), widget, expand, fill, 0); 152 gtk_box_pack_start(GTK_BOX(ct->widget), widget, expand, fill, 0);
153 #endif
115 154
116 ui_reset_layout(ct->layout); 155 ui_reset_layout(ct->layout);
117 ct->current = widget; 156 ct->current = widget;
118 } 157 }
119 158
120 UiContainer* ui_grid_container(UiObject *obj, GtkWidget *grid) { 159 UiContainer* ui_grid_container(UiObject *obj, GtkWidget *grid) {
121 UiGridContainer *ct = ucx_mempool_calloc( 160 UiGridContainer *ct = cxCalloc(
122 obj->ctx->mempool, 161 obj->ctx->allocator,
123 1, 162 1,
124 sizeof(UiGridContainer)); 163 sizeof(UiGridContainer));
125 ct->container.widget = grid; 164 ct->container.widget = grid;
126 ct->container.add = ui_grid_container_add; 165 ct->container.add = ui_grid_container_add;
127 #ifdef UI_GTK2 166 UI_GTK_V2(ct->width = 0);
128 ct->width = 0; 167 UI_GTK_V2(ct->height = 1);
129 ct->height = 1;
130 #endif
131 return (UiContainer*)ct; 168 return (UiContainer*)ct;
132 } 169 }
133 170
134 #ifdef UI_GTK3 171 #if GTK_MAJOR_VERSION >= 3
135 void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { 172 void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
136 UiGridContainer *grid = (UiGridContainer*)ct; 173 UiGridContainer *grid = (UiGridContainer*)ct;
137 174
138 if(ct->layout.newline) { 175 if(ct->layout.newline) {
139 grid->x = 0; 176 grid->x = 0;
141 ct->layout.newline = FALSE; 178 ct->layout.newline = FALSE;
142 } 179 }
143 180
144 int hexpand = FALSE; 181 int hexpand = FALSE;
145 int vexpand = FALSE; 182 int vexpand = FALSE;
183 int hfill = FALSE;
184 int vfill = FALSE;
185 if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
186 fill = ui_lb2bool(ct->layout.fill);
187 }
146 if(ct->layout.hexpand != UI_LAYOUT_UNDEFINED) { 188 if(ct->layout.hexpand != UI_LAYOUT_UNDEFINED) {
147 hexpand = ct->layout.hexpand; 189 hexpand = ct->layout.hexpand;
190 hfill = TRUE;
148 } 191 }
149 if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) { 192 if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) {
150 vexpand = ct->layout.vexpand; 193 vexpand = ct->layout.vexpand;
151 } 194 vfill = TRUE;
152 195 }
153 if(hexpand) { 196 if(fill) {
154 gtk_widget_set_hexpand(widget, TRUE); 197 hfill = TRUE;
155 } 198 vfill = TRUE;
156 if(vexpand) { 199 }
157 gtk_widget_set_vexpand(widget, TRUE); 200
158 } 201 if(!hfill) {
159 202 gtk_widget_set_halign(widget, GTK_ALIGN_START);
160 int gwidth = ct->layout.gridwidth > 0 ? ct->layout.gridwidth : 1; 203 }
161 204 if(!vfill) {
162 gtk_grid_attach(GTK_GRID(ct->widget), widget, grid->x, grid->y, gwidth, 1); 205 gtk_widget_set_valign(widget, GTK_ALIGN_START);
163 grid->x += gwidth; 206 }
207
208 gtk_widget_set_hexpand(widget, hexpand);
209 gtk_widget_set_vexpand(widget, vexpand);
210
211 int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1;
212 int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1;
213
214 gtk_grid_attach(GTK_GRID(ct->widget), widget, grid->x, grid->y, colspan, rowspan);
215 grid->x += colspan;
164 216
165 ui_reset_layout(ct->layout); 217 ui_reset_layout(ct->layout);
166 ct->current = widget; 218 ct->current = widget;
167 } 219 }
168 #endif 220 #endif
184 if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) { 236 if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) {
185 vexpand = ct->layout.vexpand; 237 vexpand = ct->layout.vexpand;
186 } 238 }
187 GtkAttachOptions xoptions = hexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; 239 GtkAttachOptions xoptions = hexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL;
188 GtkAttachOptions yoptions = vexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; 240 GtkAttachOptions yoptions = vexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL;
241
242 int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1;
243 int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1;
244 // TODO: use colspan/rowspan
189 245
190 gtk_table_attach(GTK_TABLE(ct->widget), widget, grid->x, grid->x+1, grid->y, grid->y+1, xoptions, yoptions, 0, 0); 246 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++; 247 grid->x++;
192 int nw = grid->x > grid->width ? grid->x : grid->width; 248 int nw = grid->x > grid->width ? grid->x : grid->width;
193 if(grid->x > grid->width || grid->y > grid->height) { 249 if(grid->x > grid->width || grid->y > grid->height) {
199 ui_reset_layout(ct->layout); 255 ui_reset_layout(ct->layout);
200 ct->current = widget; 256 ct->current = widget;
201 } 257 }
202 #endif 258 #endif
203 259
260 UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame) {
261 UiContainer *ct = cxCalloc(
262 obj->ctx->allocator,
263 1,
264 sizeof(UiContainer));
265 ct->widget = frame;
266 ct->add = ui_frame_container_add;
267 return ct;
268 }
269
270 void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
271 FRAME_SET_CHILD(ct->widget, widget);
272 }
273
274 UiContainer* ui_expander_container(UiObject *obj, GtkWidget *expander) {
275 UiContainer *ct = cxCalloc(
276 obj->ctx->allocator,
277 1,
278 sizeof(UiContainer));
279 ct->widget = expander;
280 ct->add = ui_expander_container_add;
281 return ct;
282 }
283
284 void ui_expander_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
285 EXPANDER_SET_CHILD(ct->widget, widget);
286 }
287
288 void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
289 // TODO: check if the widget implements GtkScrollable
290 SCROLLEDWINDOW_SET_CHILD(ct->widget, widget);
291 ui_reset_layout(ct->layout);
292 ct->current = widget;
293 }
294
204 UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) { 295 UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) {
205 UiContainer *ct = ucx_mempool_calloc( 296 UiContainer *ct = cxCalloc(
206 obj->ctx->mempool, 297 obj->ctx->allocator,
207 1, 298 1,
208 sizeof(UiContainer)); 299 sizeof(UiContainer));
209 ct->widget = scrolledwindow; 300 ct->widget = scrolledwindow;
210 ct->add = ui_scrolledwindow_container_add; 301 ct->add = ui_scrolledwindow_container_add;
211 return ct; 302 return ct;
212 } 303 }
213 304
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) { 305 UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) {
226 UiTabViewContainer *ct = ucx_mempool_calloc( 306 UiTabViewContainer *ct = cxCalloc(
227 obj->ctx->mempool, 307 obj->ctx->allocator,
228 1, 308 1,
229 sizeof(UiTabViewContainer)); 309 sizeof(UiTabViewContainer));
230 ct->container.widget = tabview; 310 ct->container.widget = tabview;
231 ct->container.add = ui_tabview_container_add; 311 ct->container.add = ui_tabview_container_add;
232 return (UiContainer*)ct; 312 return (UiContainer*)ct;
233 } 313 }
234 314
235 void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { 315 void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
236 gtk_notebook_append_page( 316 UiGtkTabView *data = ui_widget_get_tabview_data(ct->widget);
237 GTK_NOTEBOOK(ct->widget), 317 if(!data) {
238 widget, 318 fprintf(stderr, "UI Error: widget is not a tabview");
239 gtk_label_new(ct->layout.label)); 319 return;
320 }
321 data->add_tab(ct->widget, -1, ct->layout.label, widget);
240 322
241 ui_reset_layout(ct->layout); 323 ui_reset_layout(ct->layout);
242 ct->current = widget; 324 ct->current = widget;
243 } 325 }
244 326
245 327
246 UIWIDGET ui_vbox(UiObject *obj) { 328
247 return ui_vbox_sp(obj, 0, 0); 329 GtkWidget* ui_box_set_margin(GtkWidget *box, int margin) {
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; 330 GtkWidget *ret = box;
256 #ifdef UI_GTK3 331 #if GTK_MAJOR_VERSION >= 3
257 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 12 332 #if GTK_MAJOR_VERSION * 1000 + GTK_MINOR_VERSION >= 3012
258 gtk_widget_set_margin_start(box, margin); 333 gtk_widget_set_margin_start(box, margin);
259 gtk_widget_set_margin_end(box, margin); 334 gtk_widget_set_margin_end(box, margin);
260 #else 335 #else
261 gtk_widget_set_margin_left(box, margin); 336 gtk_widget_set_margin_left(box, margin);
262 gtk_widget_set_margin_right(box, margin); 337 gtk_widget_set_margin_right(box, margin);
270 ret = a; 345 ret = a;
271 #endif 346 #endif
272 return ret; 347 return ret;
273 } 348 }
274 349
275 UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) { 350 UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type) {
276 UiContainer *ct = uic_get_current_container(obj); 351 UiObject *current = uic_current_obj(obj);
277 352 UiContainer *ct = current->container;
278 GtkWidget *vbox = ui_gtk_vbox_new(spacing); 353 UI_APPLY_LAYOUT1(current, args);
279 GtkWidget *widget = margin > 0 ? box_set_margin(vbox, margin) : vbox; 354
355 GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing);
356 ui_set_name_and_style(box, args.name, args.style_class);
357 GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box;
280 ct->add(ct, widget, TRUE); 358 ct->add(ct, widget, TRUE);
281 359
282 UiObject *newobj = uic_object_new(obj, vbox); 360 UiObject *newobj = uic_object_new(obj, box);
283 newobj->container = ui_box_container(obj, vbox); 361 newobj->container = ui_box_container(obj, box, type);
284 uic_obj_add(obj, newobj); 362 uic_obj_add(obj, newobj);
285 363
286 return widget; 364 return widget;
287 } 365 }
288 366
289 UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) { 367 UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
290 UiContainer *ct = uic_get_current_container(obj); 368 return ui_box_create(obj, args, UI_CONTAINER_VBOX);
291 369 }
292 GtkWidget *hbox = ui_gtk_hbox_new(spacing); 370
293 GtkWidget *widget = margin > 0 ? box_set_margin(hbox, margin) : hbox; 371 UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
294 ct->add(ct, widget, TRUE); 372 return ui_box_create(obj, args, UI_CONTAINER_HBOX);
295 373 }
296 UiObject *newobj = uic_object_new(obj, hbox); 374
297 newobj->container = ui_box_container(obj, hbox); 375 GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing) {
298 uic_obj_add(obj, newobj); 376 #if GTK_MAJOR_VERSION >= 3
299 377 GtkWidget *grid = gtk_grid_new();
300 return widget; 378 gtk_grid_set_column_spacing(GTK_GRID(grid), colspacing);
301 } 379 gtk_grid_set_row_spacing(GTK_GRID(grid), rowspacing);
302 380 #else
303 UIWIDGET ui_grid(UiObject *obj) { 381 GtkWidget *grid = gtk_table_new(1, 1, FALSE);
304 return ui_grid_sp(obj, 0, 0, 0); 382 gtk_table_set_col_spacings(GTK_TABLE(grid), colspacing);
305 } 383 gtk_table_set_row_spacings(GTK_TABLE(grid), rowspacing);
306 384 #endif
307 UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) { 385 return grid;
308 UiContainer *ct = uic_get_current_container(obj); 386 }
387
388 UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
389 UiObject* current = uic_current_obj(obj);
390 UI_APPLY_LAYOUT1(current, args);
309 GtkWidget *widget; 391 GtkWidget *widget;
310 392
311 #ifdef UI_GTK3 393 GtkWidget *grid = ui_create_grid_widget(args.columnspacing, args.rowspacing);
312 GtkWidget *grid = gtk_grid_new(); 394 ui_set_name_and_style(grid, args.name, args.style_class);
313 gtk_grid_set_column_spacing(GTK_GRID(grid), columnspacing); 395 widget = ui_box_set_margin(grid, args.margin);
314 gtk_grid_set_row_spacing(GTK_GRID(grid), rowspacing); 396 current->container->add(current->container, widget, TRUE);
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 397
343 UiObject *newobj = uic_object_new(obj, grid); 398 UiObject *newobj = uic_object_new(obj, grid);
344 newobj->container = ui_grid_container(obj, grid); 399 newobj->container = ui_grid_container(obj, grid);
345 uic_obj_add(obj, newobj); 400 uic_obj_add(obj, newobj);
346 401
347 return widget; 402 return widget;
348 } 403 }
349 404
350 UIWIDGET ui_scrolledwindow(UiObject *obj) { 405 UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs args) {
351 UiContainer *ct = uic_get_current_container(obj); 406 UiObject* current = uic_current_obj(obj);
352 GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); 407 UI_APPLY_LAYOUT1(current, args);
353 ct->add(ct, sw, TRUE); 408
409 GtkWidget *frame = gtk_frame_new(args.label);
410 UiObject *newobj = uic_object_new(obj, frame);
411 GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
412 if(sub) {
413 FRAME_SET_CHILD(frame, sub);
414 } else {
415 newobj->widget = frame;
416 newobj->container = ui_frame_container(obj, frame);
417 }
418 current->container->add(current->container, frame, FALSE);
419 uic_obj_add(obj, newobj);
420
421 return frame;
422 }
423
424 UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs args) {
425 UiObject* current = uic_current_obj(obj);
426 UI_APPLY_LAYOUT1(current, args);
427
428 GtkWidget *expander = gtk_expander_new(args.label);
429 gtk_expander_set_expanded(GTK_EXPANDER(expander), args.isexpanded);
430 UiObject *newobj = uic_object_new(obj, expander);
431 GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
432 if(sub) {
433 EXPANDER_SET_CHILD(expander, sub);
434 } else {
435 newobj->widget = expander;
436 newobj->container = ui_expander_container(obj, expander);
437 }
438 current->container->add(current->container, expander, FALSE);
439 uic_obj_add(obj, newobj);
440
441 return expander;
442 }
443
444
445 UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) {
446 UiObject* current = uic_current_obj(obj);
447 UI_APPLY_LAYOUT1(current, args);
448
449 GtkWidget *sw = SCROLLEDWINDOW_NEW();
450 ui_set_name_and_style(sw, args.name, args.style_class);
451 GtkWidget *widget = ui_box_set_margin(sw, args.margin);
452 current->container->add(current->container, widget, TRUE);
354 453
355 UiObject *newobj = uic_object_new(obj, sw); 454 UiObject *newobj = uic_object_new(obj, sw);
356 newobj->container = ui_scrolledwindow_container(obj, sw); 455 GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin);
456 if(sub) {
457 SCROLLEDWINDOW_SET_CHILD(sw, sub);
458 } else {
459 newobj->widget = sw;
460 newobj->container = ui_scrolledwindow_container(obj, sw);
461 }
462
357 uic_obj_add(obj, newobj); 463 uic_obj_add(obj, newobj);
358 464
359 return sw; 465 return sw;
360 } 466 }
361 467
362 UIWIDGET ui_tabview(UiObject *obj) { 468
363 GtkWidget *tabview = gtk_notebook_new(); 469 void ui_notebook_tab_select(UIWIDGET tabview, int tab) {
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); 470 gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab);
385 } 471 }
386 472
473 void ui_notebook_tab_remove(UIWIDGET tabview, int tab) {
474 gtk_notebook_remove_page(GTK_NOTEBOOK(tabview), tab);
475 }
476
477 void ui_notebook_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) {
478 gtk_notebook_insert_page(
479 GTK_NOTEBOOK(widget),
480 child,
481 gtk_label_new(name),
482 index);
483 }
484
485 int64_t ui_notebook_get(UiInteger *i) {
486 GtkNotebook *nb = i->obj;
487 i->value = gtk_notebook_get_current_page(nb);
488 return i->value;
489 }
490
491 void ui_notebook_set(UiInteger *i, int64_t value) {
492 GtkNotebook *nb = i->obj;
493 gtk_notebook_set_current_page(nb, value);
494 i->value = gtk_notebook_get_current_page(nb);
495 }
496
497
498 #if GTK_MAJOR_VERSION >= 4
499 static int stack_set_page(GtkWidget *stack, int index) {
500 GtkSelectionModel *pages = gtk_stack_get_pages(GTK_STACK(stack));
501 GListModel *list = G_LIST_MODEL(pages);
502 GtkStackPage *page = g_list_model_get_item(list, index);
503 if(page) {
504 gtk_stack_set_visible_child(GTK_STACK(stack), gtk_stack_page_get_child(page));
505 } else {
506 fprintf(stderr, "UI Error: ui_stack_set value out of bounds\n");
507 return -1;
508 }
509 return index;
510 }
511
512 void ui_stack_tab_select(UIWIDGET tabview, int tab) {
513 stack_set_page(tabview, tab);
514 }
515
516 void ui_stack_tab_remove(UIWIDGET tabview, int tab) {
517 GtkStack *stack = GTK_STACK(tabview);
518 GtkWidget *current = gtk_stack_get_visible_child(stack);
519 GtkSelectionModel *pages = gtk_stack_get_pages(stack);
520 GListModel *list = G_LIST_MODEL(pages);
521 GtkStackPage *page = g_list_model_get_item(list, tab);
522 if(page) {
523 gtk_stack_remove(stack, gtk_stack_page_get_child(page));
524 }
525 }
526
527 void ui_stack_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) {
528 (void)gtk_stack_add_titled(GTK_STACK(widget), child, name, name);
529 }
530
531 int64_t ui_stack_get(UiInteger *i) {
532 GtkStack *stack = GTK_STACK(i->obj);
533 GtkWidget *current = gtk_stack_get_visible_child(stack);
534 GtkSelectionModel *pages = gtk_stack_get_pages(stack);
535 GListModel *list = G_LIST_MODEL(pages);
536 int nitems = g_list_model_get_n_items(list);
537 for(int p=0;p<nitems;p++) {
538 GtkStackPage *page = g_list_model_get_item(list, p);
539 GtkWidget *child = gtk_stack_page_get_child(page);
540 if(child == current) {
541 i->value = p;
542 break;
543 }
544 }
545 return i->value;
546 }
547
548 void ui_stack_set(UiInteger *i, int64_t value) {
549 GtkWidget *widget = i->obj;
550 if(stack_set_page(widget, value) >= 0) {
551 i->value = value;
552 }
553 }
554 #elif GTK_MAJOR_VERSION >= 3
555 static GtkWidget* stack_get_child(GtkWidget *stack, int index) {
556 GList *children = gtk_container_get_children(GTK_CONTAINER(stack));
557 if(children) {
558 return g_list_nth_data(children, index);
559 }
560 return NULL;
561 }
562
563 void ui_stack_tab_select(UIWIDGET tabview, int tab) {
564 GtkWidget *child = stack_get_child(tabview, tab);
565 if(child) {
566 gtk_stack_set_visible_child(GTK_STACK(tabview), child);
567 }
568 }
569
570 void ui_stack_tab_remove(UIWIDGET tabview, int tab) {
571 GtkWidget *child = stack_get_child(tabview, tab);
572 if(child) {
573 gtk_container_remove(GTK_CONTAINER(tabview), child);
574 }
575 }
576
577 void ui_stack_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) {
578 gtk_stack_add_titled(GTK_STACK(widget), child, name, name);
579 }
580
581 int64_t ui_stack_get(UiInteger *i) {
582 GtkWidget *visible = gtk_stack_get_visible_child(GTK_STACK(i->obj));
583 GList *children = gtk_container_get_children(GTK_CONTAINER(i->obj));
584 GList *elm = children;
585 int n = 0;
586 int64_t v = -1;
587 while(elm) {
588 GtkWidget *child = elm->data;
589 if(child == visible) {
590 v = n;
591 break;
592 }
593
594 elm = elm->next;
595 n++;
596 }
597 g_list_free(children);
598 i->value = v;
599 return v;
600 }
601
602 void ui_stack_set(UiInteger *i, int64_t value) {
603 GtkWidget *child = stack_get_child(i->obj, value);
604 if(child) {
605 gtk_stack_set_visible_child(GTK_STACK(i->obj), child);
606 i->value = value;
607 }
608 }
609
610 #endif
611
612
613
614
615 UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview) {
616 return g_object_get_data(G_OBJECT(tabview), "ui_tabview");
617 }
618
619 typedef int64_t(*ui_tabview_get_func)(UiInteger*);
620 typedef void (*ui_tabview_set_func)(UiInteger*, int64_t);
621
622 UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) {
623 UiGtkTabView *data = malloc(sizeof(UiGtkTabView));
624 data->margin = args.margin;
625 data->spacing = args.spacing;
626 data->columnspacing = args.columnspacing;
627 data->rowspacing = args.rowspacing;
628
629 ui_tabview_get_func getfunc = NULL;
630 ui_tabview_set_func setfunc = NULL;
631
632 GtkWidget *widget = NULL;
633 GtkWidget *data_widget = NULL;
634 switch(args.tabview) {
635 case UI_TABVIEW_DOC: {
636 // TODO
637 break;
638 }
639 case UI_TABVIEW_NAVIGATION_SIDE: {
640 #if GTK_CHECK_VERSION(3, 10, 0)
641 widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
642 GtkWidget *sidebar = gtk_stack_sidebar_new();
643 BOX_ADD(widget, sidebar);
644 GtkWidget *stack = gtk_stack_new();
645 gtk_stack_set_transition_type (GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN);
646 gtk_stack_sidebar_set_stack(GTK_STACK_SIDEBAR(sidebar), GTK_STACK(stack));
647 BOX_ADD_EXPAND(widget, stack);
648 data->select_tab = ui_stack_tab_select;
649 data->remove_tab = ui_stack_tab_remove;
650 data->add_tab = ui_stack_tab_add;
651 getfunc = ui_stack_get;
652 setfunc = ui_stack_set;
653 data_widget = stack;
654 #else
655 // TODO
656 #endif
657 break;
658 }
659 case UI_TABVIEW_DEFAULT: /* fall through */
660 case UI_TABVIEW_NAVIGATION_TOP: /* fall through */
661 case UI_TABVIEW_INVISIBLE: /* fall through */
662 case UI_TABVIEW_NAVIGATION_TOP2: {
663 widget = gtk_notebook_new();
664 data_widget = widget;
665 data->select_tab = ui_notebook_tab_select;
666 data->remove_tab = ui_notebook_tab_remove;
667 data->add_tab = ui_notebook_tab_add;
668 getfunc = ui_notebook_get;
669 setfunc = ui_notebook_set;
670 if(args.tabview == UI_TABVIEW_INVISIBLE) {
671 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(widget), FALSE);
672 gtk_notebook_set_show_border(GTK_NOTEBOOK(widget), FALSE);
673 }
674 break;
675 }
676 }
677
678 UiObject* current = uic_current_obj(obj);
679 if(args.value || args.varname) {
680 UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER);
681 UiInteger *i = var->value;
682 i->get = getfunc;
683 i->set = setfunc;
684 i->obj = data_widget;
685 }
686
687 g_object_set_data(G_OBJECT(widget), "ui_tabview", data);
688 data->widget = data_widget;
689 data->subcontainer = args.subcontainer;
690
691 UI_APPLY_LAYOUT1(current, args);
692 current->container->add(current->container, widget, TRUE);
693
694 UiObject *newobj = uic_object_new(obj, widget);
695 newobj->container = ui_tabview_container(obj, widget);
696 uic_obj_add(obj, newobj);
697 data->obj = newobj;
698
699 return widget;
700 }
701
702 void ui_tab_create(UiObject* obj, const char* title) {
703 UiObject* current = uic_current_obj(obj);
704 UiGtkTabView *data = ui_widget_get_tabview_data(current->widget);
705 if(!data) {
706 fprintf(stderr, "UI Error: widget is not a tabview\n");
707 return;
708 }
709
710 UiObject *newobj = ui_tabview_add(current->widget, title, -1);
711 current->next = newobj;
712 }
713
714
715
716 void ui_tabview_select(UIWIDGET tabview, int tab) {
717 UiGtkTabView *data = ui_widget_get_tabview_data(tabview);
718 if(!data) {
719 fprintf(stderr, "UI Error: widget is not a tabview\n");
720 return;
721 }
722 data->select_tab(tabview, tab);
723 }
724
725 void ui_tabview_remove(UIWIDGET tabview, int tab) {
726 UiGtkTabView *data = ui_widget_get_tabview_data(tabview);
727 if(!data) {
728 fprintf(stderr, "UI Error: widget is not a tabview\n");
729 return;
730 }
731 data->remove_tab(tabview, tab);
732 }
733
734 UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) {
735 UiGtkTabView *data = ui_widget_get_tabview_data(tabview);
736 if(!data) {
737 fprintf(stderr, "UI Error: widget is not a tabview\n");
738 return NULL;
739 }
740
741 UiObject *newobj = cxCalloc(data->obj->ctx->allocator, 1, sizeof(UiObject));
742 newobj->ctx = data->obj->ctx;
743
744 GtkWidget *sub;
745 switch(data->subcontainer) {
746 default: {
747 sub = ui_gtk_vbox_new(data->spacing);
748 newobj->container = ui_box_container(newobj, sub, data->subcontainer);
749 break;
750 }
751 case UI_CONTAINER_HBOX: {
752 sub = ui_gtk_hbox_new(data->spacing);
753 newobj->container = ui_box_container(newobj, sub, data->subcontainer);
754 break;
755 }
756 case UI_CONTAINER_GRID: {
757 sub = ui_create_grid_widget(data->columnspacing, data->rowspacing);
758 newobj->container = ui_grid_container(newobj, sub);
759 break;
760 }
761 }
762 newobj->widget = sub;
763 GtkWidget *widget = ui_box_set_margin(sub, data->margin);
764
765 data->add_tab(data->widget, tab_index, name, widget);
766
767 return newobj;
768 }
769
770
771 /* -------------------- Headerbar -------------------- */
772
773 static void hb_set_part(UiObject *obj, int part) {
774 UiObject* current = uic_current_obj(obj);
775 GtkWidget *headerbar = current->widget;
776
777 UiHeaderbarContainer *hb = cxCalloc(
778 obj->ctx->allocator,
779 1,
780 sizeof(UiHeaderbarContainer));
781 memcpy(hb, current->container, sizeof(UiHeaderbarContainer));
782
783 UiObject *newobj = uic_object_new(obj, headerbar);
784 newobj->container = (UiContainer*)hb;
785 uic_obj_add(obj, newobj);
786
787 hb->part = part;
788 }
789
790 void ui_headerbar_start_create(UiObject *obj) {
791 hb_set_part(obj, 0);
792 }
793
794 void ui_headerbar_center_create(UiObject *obj) {
795 hb_set_part(obj, 2);
796 }
797
798 void ui_headerbar_end_create(UiObject *obj) {
799 hb_set_part(obj, 1);
800 }
801
802 UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs args) {
803 UiObject *current = uic_current_obj(obj);
804 UiContainer *ct = current->container;
805 UI_APPLY_LAYOUT1(current, args);
806
807 GtkWidget *box = ui_gtk_hbox_new(args.alt_spacing);
808 ui_set_name_and_style(box, args.name, args.style_class);
809 ct->add(ct, box, FALSE);
810
811 UiObject *newobj = uic_object_new(obj, box);
812 newobj->container = ui_headerbar_fallback_container(obj, box);
813 uic_obj_add(obj, newobj);
814
815 return box;
816 }
817
818 static void hb_fallback_set_part(UiObject *obj, int part) {
819 UiObject* current = uic_current_obj(obj);
820 GtkWidget *headerbar = current->widget;
821
822 UiObject *newobj = uic_object_new(obj, headerbar);
823 newobj->container = ui_headerbar_container(obj, headerbar);
824 uic_obj_add(obj, newobj);
825
826 UiHeaderbarContainer *hb = (UiHeaderbarContainer*)newobj->container;
827 hb->part = part;
828 }
829
830 UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) {
831 UiHeaderbarContainer *ct = cxCalloc(
832 obj->ctx->allocator,
833 1,
834 sizeof(UiHeaderbarContainer));
835 ct->container.widget = headerbar;
836 ct->container.add = ui_headerbar_fallback_container_add;
837 return (UiContainer*)ct;
838 }
839
840 void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
841 UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
842 BOX_ADD(ct->widget, widget);
843 }
844
845 #if GTK_CHECK_VERSION(3, 10, 0)
846
847 UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
848 GtkWidget *headerbar = g_object_get_data(G_OBJECT(obj->widget), "ui_headerbar");
849 if(!headerbar) {
850 return ui_headerbar_fallback_create(obj, args);
851 }
852
853 UiObject *newobj = uic_object_new(obj, headerbar);
854 newobj->container = ui_headerbar_container(obj, headerbar);
855 uic_obj_add(obj, newobj);
856
857 return headerbar;
858 }
859
860 UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) {
861 UiHeaderbarContainer *ct = cxCalloc(
862 obj->ctx->allocator,
863 1,
864 sizeof(UiHeaderbarContainer));
865 ct->container.widget = headerbar;
866 ct->container.add = ui_headerbar_container_add;
867 return (UiContainer*)ct;
868 }
869
870 void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) {
871 UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct;
872 if(hb->part == 0) {
873 UI_HEADERBAR_PACK_START(ct->widget, widget);
874 } else if(hb->part == 1) {
875 UI_HEADERBAR_PACK_END(ct->widget, widget);
876 } else if(hb->part == 2) {
877 if(!hb->centerbox) {
878 GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
879 hb->centerbox = box;
880 UI_HEADERBAR_SET_TITLE_WIDGET(ct->widget, box);
881 }
882 BOX_ADD(hb->centerbox, widget);
883 }
884 }
885
886 #else
887
888 UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) {
889 return ui_headerbar_fallback_create(obj, args);
890 }
891
892 #endif
893
894 /* -------------------- Sidebar -------------------- */
895
896 #ifdef UI_LIBADWAITA
897 UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) {
898 GtkWidget *sidebar_toolbar_view = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar");
899 if(!sidebar_toolbar_view) {
900 fprintf(stderr, "Error: window is not configured for sidebar\n");
901 return NULL;
902 }
903
904 GtkWidget *box = ui_gtk_vbox_new(args.spacing);
905 ui_box_set_margin(box, args.margin);
906 adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box);
907
908 UiObject *newobj = uic_object_new(obj, box);
909 newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
910 uic_obj_add(obj, newobj);
911
912 return box;
913 }
914 #else
915 UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) {
916 GtkWidget *sidebar_vbox = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar");
917
918 GtkWidget *box = ui_gtk_vbox_new(args.spacing);
919 ui_box_set_margin(box, args.margin);
920 BOX_ADD_EXPAND(sidebar_vbox, box);
921
922 UiObject *newobj = uic_object_new(obj, box);
923 newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX);
924 uic_obj_add(obj, newobj);
925
926 return box;
927 }
928 #endif
929
387 /* -------------------- Splitpane -------------------- */ 930 /* -------------------- Splitpane -------------------- */
388 931
389 static GtkWidget* create_paned(UiOrientation orientation) { 932 static GtkWidget* create_paned(UiOrientation orientation) {
390 #ifdef UI_GTK3 933 #if GTK_MAJOR_VERSION >= 3
391 switch(orientation) { 934 switch(orientation) {
392 case UI_HORIZONTAL: return gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); 935 case UI_HORIZONTAL: return gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
393 case UI_VERTICAL: return gtk_paned_new(GTK_ORIENTATION_VERTICAL); 936 case UI_VERTICAL: return gtk_paned_new(GTK_ORIENTATION_VERTICAL);
394 } 937 }
395 #else 938 #else
399 } 942 }
400 #endif 943 #endif
401 return NULL; 944 return NULL;
402 } 945 }
403 946
404 UIWIDGET ui_splitpane(UiObject *obj, int max, UiOrientation orientation) { 947
405 GtkWidget *paned = create_paned(orientation); 948
406 UiContainer *ct = uic_get_current_container(obj); 949 /* -------------------- ItemList Container -------------------- */
407 ct->add(ct, paned, TRUE); 950
408 951 static void remove_item(void *data, void *item) {
409 if(max <= 0) max = INT_MAX; 952 UiGtkItemListContainer *ct = data;
410 953 UiObject *obj = item;
411 UiPanedContainer *pctn = ucx_mempool_calloc( 954 if(ct->remove_items) {
412 obj->ctx->mempool, 955 BOX_REMOVE(ct->widget, obj->widget);
413 1, 956 }
414 sizeof(UiPanedContainer)); 957 uic_object_destroy(obj);
415 pctn->container.widget = paned; 958 }
416 pctn->container.add = ui_paned_container_add; 959
417 pctn->current_pane = paned; 960 static void update_itemlist(UiList *list, int c) {
418 pctn->orientation = orientation; 961 UiGtkItemListContainer *ct = list->obj;
419 pctn->max = max; 962
420 pctn->cur = 0; 963 CxMap *new_items = cxHashMapCreateSimple(CX_STORE_POINTERS);
421 964 new_items->collection.advanced_destructor = remove_item;
422 UiObject *pobj = uic_object_new(obj, paned); 965 new_items->collection.destructor_data = ct;
423 pobj->container = (UiContainer*)pctn; 966
424 967 // only create new widgets for new elements, so at first we have
425 uic_obj_add(obj, pobj); 968 // to find which elements are new
426 969 // check which elements in the list are already in the container
427 return paned; 970 void *elm = list->first(list);
428 } 971 int j = 0;
429 972 while(elm) {
430 UIWIDGET ui_hsplitpane(UiObject *obj, int max) { 973 CxHashKey key = cx_hash_key(&elm, sizeof(void*));
431 return ui_splitpane(obj, max, UI_HORIZONTAL); 974 UiObject *item_obj = cxMapRemoveAndGet(ct->current_items, key);
432 } 975 if(item_obj) {
433 976 g_object_ref(G_OBJECT(item_obj->widget));
434 UIWIDGET ui_vsplitpane(UiObject *obj, int max) { 977 BOX_REMOVE(ct->widget, item_obj->widget);
435 return ui_splitpane(obj, max, UI_VERTICAL); 978 cxMapPut(new_items, key, item_obj);
436 } 979 }
437 980 elm = list->next(list);
438 void ui_paned_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { 981 j++;
439 UiPanedContainer *pctn = (UiPanedContainer*)ct; 982 }
440 983
441 gboolean resize = (ct->layout.hexpand || ct->layout.vexpand) ? TRUE : FALSE; 984 // ct->current_items only contains elements, that are not in the list
442 int width = ct->layout.width; 985 cxMapDestroy(ct->current_items); // calls destructor remove_item
443 ui_reset_layout(ct->layout); 986 ct->current_items = new_items;
444 987
445 if(pctn->cur == 0) { 988 // add all items
446 gtk_paned_pack1(GTK_PANED(pctn->current_pane), widget, resize, resize); 989 int index = 0;
447 } else if(pctn->cur < pctn->max-1) { 990 elm = list->first(list);
448 GtkWidget *nextPane = create_paned(pctn->orientation); 991 while(elm) {
449 gtk_paned_pack2(GTK_PANED(pctn->current_pane), nextPane, TRUE, TRUE); 992 CxHashKey key = cx_hash_key(&elm, sizeof(void*));
450 gtk_paned_pack1(GTK_PANED(nextPane), widget, resize, resize); 993 UiObject *item_obj = cxMapGet(ct->current_items, key);
451 pctn->current_pane = nextPane; 994 if(item_obj) {
452 } else if(pctn->cur == pctn->max-1) { 995 // re-add previously created widget
453 gtk_paned_pack2(GTK_PANED(pctn->current_pane), widget, resize, resize); 996 ui_box_container_add(ct->container, item_obj->widget, FALSE);
454 width = 0; // disable potential call of gtk_paned_set_position 997 } else {
455 } else { 998 // create new widget and object for this list element
456 fprintf(stderr, "Splitpane max reached: %d\n", pctn->max); 999 CxMempool *mp = cxBasicMempoolCreate(256);
457 return; 1000 const CxAllocator *a = mp->allocator;
458 } 1001 UiObject *obj = cxCalloc(a, 1, sizeof(UiObject));
459 1002 obj->ctx = uic_context(obj, mp);
460 if(width > 0) { 1003 obj->window = NULL;
461 gtk_paned_set_position(GTK_PANED(pctn->current_pane), width); 1004 obj->widget = ui_subcontainer_create(
462 } 1005 ct->subcontainer,
463 1006 obj,
464 pctn->cur++; 1007 ct->spacing,
465 } 1008 ct->columnspacing,
466 1009 ct->rowspacing,
467 1010 ct->margin);
468 /* -------------------- Sidebar (deprecated) -------------------- */ 1011 ui_box_container_add(ct->container, obj->widget, FALSE);
469 UIWIDGET ui_sidebar(UiObject *obj) { 1012 if(ct->create_ui) {
470 #ifdef UI_GTK3 1013 ct->create_ui(obj, index, elm, ct->userdata);
471 GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); 1014 }
472 #else 1015 cxMapPut(new_items, key, obj);
473 GtkWidget *paned = gtk_hpaned_new(); 1016 }
474 #endif 1017 elm = list->next(list);
475 gtk_paned_set_position(GTK_PANED(paned), 200); 1018 index++;
476 1019 }
477 GtkWidget *sidebar = ui_gtk_vbox_new(0); 1020 }
478 gtk_paned_pack1(GTK_PANED(paned), sidebar, TRUE, FALSE); 1021
479 1022 static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *container) {
480 UiObject *left = uic_object_new(obj, sidebar); 1023 container->remove_items = FALSE;
481 UiContainer *ct1 = ui_box_container(obj, sidebar); 1024 cxMapDestroy(container->current_items);
482 left->container = ct1; 1025 free(container);
483 1026 }
484 UiObject *right = uic_object_new(obj, sidebar); 1027
485 UiContainer *ct2 = ucx_mempool_malloc( 1028 UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) {
486 obj->ctx->mempool, 1029 UiObject *current = uic_current_obj(obj);
487 sizeof(UiContainer)); 1030 UiContainer *ct = current->container;
488 ct2->widget = paned; 1031 UI_APPLY_LAYOUT1(current, args);
489 ct2->add = ui_split_container_add2; 1032
490 right->container = ct2; 1033 GtkWidget *box = args.container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing);
491 1034 ui_set_name_and_style(box, args.name, args.style_class);
492 UiContainer *ct = uic_get_current_container(obj); 1035 GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box;
493 ct->add(ct, paned, TRUE); 1036 ct->add(ct, widget, TRUE);
494 1037
495 uic_obj_add(obj, right); 1038 UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer));
496 uic_obj_add(obj, left); 1039 container->parent = obj;
497 1040 container->widget = box;
498 return sidebar; 1041 container->container = ui_box_container(current, box, args.container);
499 } 1042 container->create_ui = args.create_ui;
500 1043 container->userdata = args.userdata;
501 void ui_split_container_add1(UiContainer *ct, GtkWidget *widget, UiBool fill) { 1044 container->subcontainer = args.subcontainer;
502 // TODO: remove 1045 container->current_items = cxHashMapCreateSimple(CX_STORE_POINTERS);
503 gtk_paned_pack1(GTK_PANED(ct->widget), widget, TRUE, FALSE); 1046 container->current_items->collection.advanced_destructor = remove_item;
504 1047 container->current_items->collection.destructor_data = container;
505 ui_reset_layout(ct->layout); 1048 container->margin = args.sub_margin;
506 ct->current = widget; 1049 container->spacing = args.sub_spacing;
507 } 1050 container->columnspacing = args.sub_columnspacing;
508 1051 container->rowspacing = args.sub_rowspacing;
509 void ui_split_container_add2(UiContainer *ct, GtkWidget *widget, UiBool fill) { 1052 container->remove_items = TRUE;
510 gtk_paned_pack2(GTK_PANED(ct->widget), widget, TRUE, FALSE); 1053
511 1054 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_LIST);
512 ui_reset_layout(ct->layout); 1055 if(var) {
513 ct->current = widget; 1056 UiList *list = var->value;
514 } 1057 list->obj = container;
515 1058 list->update = update_itemlist;
516 1059 update_itemlist(list, 0);
517 /* -------------------- Document Tabview -------------------- */ 1060 }
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( 1061 g_signal_connect(
536 tabview, 1062 box,
537 "switch-page", 1063 "destroy",
538 G_CALLBACK(page_change), 1064 G_CALLBACK(destroy_itemlist_container),
539 NULL); 1065 container);
540 1066
541 UiContainer *ct = uic_get_current_container(obj); 1067 return box;
542 ct->add(ct, tabview, TRUE); 1068 }
543 1069
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 1070
590 1071
591 /* 1072 /*
592 * -------------------- Layout Functions -------------------- 1073 * -------------------- Layout Functions --------------------
593 * 1074 *
608 void ui_layout_vexpand(UiObject *obj, UiBool expand) { 1089 void ui_layout_vexpand(UiObject *obj, UiBool expand) {
609 UiContainer *ct = uic_get_current_container(obj); 1090 UiContainer *ct = uic_get_current_container(obj);
610 ct->layout.vexpand = expand; 1091 ct->layout.vexpand = expand;
611 } 1092 }
612 1093
613 void ui_layout_width(UiObject *obj, int width) { 1094 void ui_layout_hfill(UiObject *obj, UiBool fill) {
614 UiContainer *ct = uic_get_current_container(obj); 1095 UiContainer *ct = uic_get_current_container(obj);
615 ct->layout.width = width; 1096 ct->layout.hfill = fill;
616 } 1097 }
617 1098
618 void ui_layout_gridwidth(UiObject *obj, int width) { 1099 void ui_layout_vfill(UiObject *obj, UiBool fill) {
619 UiContainer *ct = uic_get_current_container(obj); 1100 UiContainer *ct = uic_get_current_container(obj);
620 ct->layout.gridwidth = width; 1101 ct->layout.vfill = fill;
1102 }
1103
1104 void ui_layout_colspan(UiObject* obj, int cols) {
1105 UiContainer* ct = uic_get_current_container(obj);
1106 ct->layout.colspan = cols;
1107 }
1108
1109 void ui_layout_rowspan(UiObject* obj, int rows) {
1110 UiContainer* ct = uic_get_current_container(obj);
1111 ct->layout.rowspan = rows;
621 } 1112 }
622 1113
623 void ui_newline(UiObject *obj) { 1114 void ui_newline(UiObject *obj) {
624 UiContainer *ct = uic_get_current_container(obj); 1115 UiContainer *ct = uic_get_current_container(obj);
625 ct->layout.newline = TRUE; 1116 ct->layout.newline = TRUE;

mercurial