ui/motif/container.c

changeset 100
d2bd73d28ff1
parent 29
3fc287f06305
equal deleted inserted replaced
99:b9767cb5b06b 100:d2bd73d28ff1
1 /* 1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 * 3 *
4 * Copyright 2014 Olaf Wintermann. All rights reserved. 4 * Copyright 2024 Olaf Wintermann. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met: 7 * modification, are permitted provided that the following conditions are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
32 32
33 #include "container.h" 33 #include "container.h"
34 #include "../common/context.h" 34 #include "../common/context.h"
35 #include "../common/object.h" 35 #include "../common/object.h"
36 36
37 #include <cx/array_list.h> 37 #include "Grid.h"
38 #include <cx/linked_list.h> 38
39 #include <cx/compare.h> 39 /* ---------------------------- Box Container ---------------------------- */
40 40
41 #define UI_GRID_MAX_COLUMNS 512 41 static UIWIDGET box_create(UiObject *obj, UiContainerArgs args, UiBoxOrientation orientation) {
42 42 UiContainerPrivate *ctn = ui_obj_container(obj);
43 static UiBool ui_lb2bool(UiLayoutBool b) { 43 UI_APPLY_LAYOUT(ctn->layout, args);
44 return b == UI_LAYOUT_TRUE ? TRUE : FALSE; 44
45 } 45 Arg xargs[16];
46 46 int n = 0;
47 static UiLayoutBool ui_bool2lb(UiBool b) { 47
48 return b ? UI_LAYOUT_TRUE : UI_LAYOUT_FALSE; 48 if(orientation == UI_BOX_VERTICAL) {
49 } 49 //XtSetArg(xargs[n], gridRowSpacing, args.spacing); n++;
50
51
52 UiContainer* ui_frame_container(UiObject *obj, Widget frame) {
53 UiContainer *ct = cxCalloc(
54 obj->ctx->allocator,
55 1,
56 sizeof(UiContainer));
57 ct->widget = frame;
58 ct->prepare = ui_frame_container_prepare;
59 ct->add = ui_frame_container_add;
60 return ct;
61 }
62
63 Widget ui_frame_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
64 return ct->widget;
65 }
66
67 void ui_frame_container_add(UiContainer *ct, Widget widget) {
68 ui_reset_layout(ct->layout);
69 ct->current = widget;
70 }
71
72
73 UiContainer* ui_box_container(UiObject *obj, Widget box, int margin, int spacing, UiBoxOrientation orientation) {
74 UiBoxContainer *ct = cxCalloc(
75 obj->ctx->allocator,
76 1,
77 sizeof(UiBoxContainer));
78 ct->container.widget = box;
79 ct->container.prepare = ui_box_container_prepare;
80 ct->container.add = ui_box_container_add;
81 ct->orientation = orientation;
82 ct->margin = margin;
83 ct->spacing = spacing;
84 return (UiContainer*)ct;
85 }
86
87 Widget ui_box_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
88 UiBoxContainer *bc = (UiBoxContainer*)ct;
89 if(ct->layout.fill != UI_LAYOUT_UNDEFINED) {
90 fill = ui_lb2bool(ct->layout.fill);
91 }
92
93 if(bc->has_fill && fill) {
94 fprintf(stderr, "UiError: container has 2 filled widgets");
95 fill = FALSE;
96 }
97 if(fill) {
98 bc->has_fill = TRUE;
99 }
100
101 int a = *n;
102 // determine fixed and dynamic attachments
103 void *f1;
104 void *f2;
105 void *d1;
106 void *d2;
107 void *w1;
108 void *w2;
109 if(bc->orientation == UI_BOX_VERTICAL) {
110 f1 = XmNleftAttachment;
111 f2 = XmNrightAttachment;
112 d1 = XmNtopAttachment;
113 d2 = XmNbottomAttachment;
114 w1 = XmNtopWidget;
115 w2 = XmNbottomWidget;
116
117 // margin/spacing
118 XtSetArg(args[a], XmNleftOffset, bc->margin); a++;
119 XtSetArg(args[a], XmNrightOffset, bc->margin); a++;
120
121 XtSetArg(args[a], XmNtopOffset, bc->prev_widget ? bc->spacing : bc->margin); a++;
122 } else { 50 } else {
123 f1 = XmNtopAttachment; 51 //XtSetArg(xargs[n], gridColumnSpacing, args.spacing); n++;
124 f2 = XmNbottomAttachment; 52 }
125 d1 = XmNleftAttachment; 53
126 d2 = XmNrightAttachment; 54 Widget parent = ctn->prepare(ctn, xargs, &n);
127 w1 = XmNleftWidget; 55 Widget grid = XtCreateManagedWidget(args.name ? args.name : "boxcontainer", gridClass, parent, xargs, n);
128 w2 = XmNrightWidget; 56 ctn->add(ctn, grid);
129 57
130 // margin/spacing 58 UiContainerX *container = ui_box_container(obj, grid, orientation);
131 XtSetArg(args[a], XmNtopOffset, bc->margin); a++; 59 uic_object_push_container(obj, container);
132 XtSetArg(args[a], XmNbottomOffset, bc->margin); a++; 60
133 61 return grid;
134 XtSetArg(args[a], XmNleftOffset, bc->prev_widget ? bc->spacing : bc->margin); a++; 62 }
135 } 63
136 XtSetArg(args[a], f1, XmATTACH_FORM); a++; 64 // public
137 XtSetArg(args[a], f2, XmATTACH_FORM); a++; 65 UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) {
138 66 return box_create(obj, args, UI_BOX_VERTICAL);
139 if(fill) { 67 }
140 XtSetArg(args[a], d2, XmATTACH_FORM); a++; 68
141 } 69 // public
142 if(bc->prev_widget) { 70 UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) {
143 XtSetArg(args[a], d1, XmATTACH_WIDGET); a++; 71 return box_create(obj, args, UI_BOX_HORIZONTAL);
144 XtSetArg(args[a], w1, bc->prev_widget); a++; 72 }
145 } else { 73
146 XtSetArg(args[a], d1, XmATTACH_FORM); a++; 74 UiContainerX* ui_box_container(UiObject *obj, Widget grid, UiBoxOrientation orientation) {
147 } 75 UiBoxContainer *ctn = ui_malloc(obj->ctx, sizeof(UiBoxContainer));
148 76 memset(ctn, 0, sizeof(UiBoxContainer));
77 ctn->container.prepare = orientation == UI_BOX_VERTICAL ? ui_vbox_prepare : ui_hbox_prepare;
78 ctn->container.add = ui_box_container_add;
79 ctn->container.widget = grid;
80 ctn->n = 0;
81 return (UiContainerX*)ctn;
82 }
83
84 static Widget ui_box_container_prepare(UiBoxContainer *box, Arg *args, int *n) {
85 int a = *n;
86 box->n++;
87 return box->container.widget;
88 }
89
90 Widget ui_vbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n) {
91 UiBoxContainer *box = (UiBoxContainer*)ctn;
92 int a = *n;
93 XtSetArg(args[a], gridRow, box->n); a++;
94 if(box->container.layout.fill == UI_ON) {
95 XtSetArg(args[a], gridVExpand, TRUE); a++;
96 XtSetArg(args[a], gridVFill, TRUE); a++;
97 }
98 XtSetArg(args[a], gridHExpand, TRUE); a++;
99 XtSetArg(args[a], gridHFill, TRUE); a++;
149 *n = a; 100 *n = a;
150 return ct->widget; 101 return ui_box_container_prepare(box, args, n);
151 } 102 }
152 103
153 void ui_box_container_add(UiContainer *ct, Widget widget) { 104 Widget ui_hbox_prepare(UiContainerPrivate *ctn, Arg *args, int *n) {
154 UiBoxContainer *bc = (UiBoxContainer*)ct; 105 UiBoxContainer *box = (UiBoxContainer*)ctn;
155 // determine dynamic attachments 106 int a = *n;
156 void *d1; 107 XtSetArg(args[a], gridColumn, box->n); a++;
157 void *d2; 108 if(box->container.layout.fill == UI_ON) {
158 void *w1; 109 XtSetArg(args[a], gridHExpand, TRUE); a++;
159 void *w2; 110 XtSetArg(args[a], gridHFill, TRUE); a++;
160 if(bc->orientation == UI_BOX_VERTICAL) { 111 }
161 d1 = XmNtopAttachment; 112 XtSetArg(args[a], gridVExpand, TRUE); a++;
162 d2 = XmNbottomAttachment; 113 XtSetArg(args[a], gridVFill, TRUE); a++;
163 w1 = XmNtopWidget;
164 w2 = XmNbottomWidget;
165
166 } else {
167 d1 = XmNleftAttachment;
168 d2 = XmNrightAttachment;
169 w1 = XmNleftWidget;
170 w2 = XmNrightWidget;
171 }
172
173 if(bc->prev_widget) {
174 int v = 0;
175 XtVaGetValues(bc->prev_widget, d2, &v, NULL);
176 if(v == XmATTACH_FORM) {
177 XtVaSetValues(
178 bc->prev_widget,
179 d2,
180 XmATTACH_WIDGET,
181 w2,
182 widget,
183 NULL);
184 XtVaSetValues(
185 widget,
186 d1,
187 XmATTACH_NONE,
188 d2,
189 XmATTACH_FORM,
190 NULL);
191 }
192 }
193 bc->prev_widget = widget;
194
195 ui_reset_layout(ct->layout);
196 ct->current = widget;
197 }
198
199 UiContainer* ui_grid_container(UiObject *obj, Widget form, int columnspacing, int rowspacing) {
200 UiGridContainer *ct = cxCalloc(
201 obj->ctx->allocator,
202 1,
203 sizeof(UiGridContainer));
204 ct->container.widget = form;
205 ct->container.prepare = ui_grid_container_prepare;
206 ct->container.add = ui_grid_container_add;
207 ct->columnspacing = columnspacing;
208 ct->rowspacing = rowspacing;
209 ct->lines = cxLinkedListCreateSimple(CX_STORE_POINTERS);
210 return (UiContainer*)ct;
211 }
212
213 void ui_grid_newline(UiGridContainer *grid) {
214 if(grid->current) {
215 grid->current = NULL;
216 }
217 grid->container.layout.newline = FALSE;
218 }
219
220 Widget ui_grid_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
221 UiGridContainer *grid = (UiGridContainer*)ct;
222 if(ct->layout.newline) {
223 ui_grid_newline(grid);
224 }
225 return ct->widget;
226 }
227
228 void ui_grid_container_add(UiContainer *ct, Widget widget) {
229 UiGridContainer *grid = (UiGridContainer*)ct;
230
231 if(grid->current) {
232 cxListAdd(grid->current, widget);
233 } else {
234 grid->current = cxLinkedListCreateSimple(CX_STORE_POINTERS);
235 cxListAdd(grid->current, widget);
236 cxListAdd(grid->lines, grid->current);
237 }
238
239 ui_reset_layout(ct->layout);
240 ct->current = widget;
241 }
242
243 static void ui_grid_resize(Widget widget, XtPointer udata, XtPointer cdata) {
244 UiGridContainer *grid = udata;
245
246 CxList *rowdim = cxArrayListCreateSimple(sizeof(int), grid->lines->size);
247 int coldim[UI_GRID_MAX_COLUMNS];
248 memset(coldim, 0, UI_GRID_MAX_COLUMNS*sizeof(int));
249 int numcol = 0;
250
251 // get the minimum size of the columns and rows
252 int sumw = 0;
253 int sumh = 0;
254 CxIterator lineIterator = cxListIterator(grid->lines);
255 cx_foreach(CxList *, row, lineIterator) {
256 int rheight = 0;
257 int i=0;
258 int sum_width = 0;
259 CxIterator colIterator = cxListIterator(row);
260 cx_foreach(Widget, w, colIterator) {
261 int widget_width = 0;
262 int widget_height = 0;
263 XtVaGetValues(
264 w,
265 XmNwidth,
266 &widget_width,
267 XmNheight,
268 &widget_height,
269 NULL);
270
271 // get the maximum height in this row
272 if(widget_height > rheight) {
273 rheight = widget_height;
274 }
275
276 // get the maximum width in this column
277 if(widget_width > coldim[i]) {
278 coldim[i] = widget_width;
279 }
280 sum_width += widget_width;
281 if(sum_width > sumw) {
282 sumw = sum_width;
283 }
284
285 i++;
286 if(i > numcol) {
287 numcol = i;
288 }
289 }
290 cxListAdd(rowdim, &rheight);
291 sumh += rheight;
292 }
293
294 // check container size
295 int gwidth = 0;
296 int gheight = 0;
297 XtVaGetValues(widget, XmNwidth, &gwidth, XmNheight, &gheight, NULL);
298 if(gwidth < sumw || gheight < sumh) {
299 XtVaSetValues(widget, XmNwidth, sumw, XmNheight, sumh, NULL);
300 cxListDestroy(rowdim);
301 return;
302 }
303
304
305 // adjust the positions of all children
306 int y = 0;
307 lineIterator = cxListIterator(grid->lines);
308 cx_foreach(CxList *, row, lineIterator) {
309 int x = 0;
310 int i=0;
311 int *rowheight = cxListAt(rowdim, lineIterator.index);
312 CxIterator colIterator = cxListIterator(row);
313 cx_foreach(Widget, w, colIterator) {
314 XtVaSetValues(
315 w,
316 XmNx, x,
317 XmNy, y,
318 XmNwidth, coldim[i],
319 XmNheight, *rowheight,
320 NULL);
321
322 x += coldim[i];
323 i++;
324 }
325 y += *rowheight;
326 }
327
328 cxListDestroy(rowdim);
329 }
330
331 UiContainer* ui_scrolledwindow_container(UiObject *obj, Widget scrolledwindow) {
332 UiContainer *ct = cxCalloc(
333 obj->ctx->allocator,
334 1,
335 sizeof(UiContainer));
336 ct->widget = scrolledwindow;
337 ct->prepare = ui_scrolledwindow_container_prepare;
338 ct->add = ui_scrolledwindow_container_add;
339 return ct;
340 }
341
342 Widget ui_scrolledwindow_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
343 return ct->widget;
344 }
345
346 void ui_scrolledwindow_container_add(UiContainer *ct, Widget widget) {
347 ui_reset_layout(ct->layout);
348 ct->current = widget;
349 }
350
351
352 UiContainer* ui_tabview_container(UiObject *obj, Widget frame) {
353 UiTabViewContainer *ct = cxCalloc(
354 obj->ctx->allocator,
355 1,
356 sizeof(UiTabViewContainer));
357 ct->context = obj->ctx;
358 ct->container.widget = frame;
359 ct->container.prepare = ui_tabview_container_prepare;
360 ct->container.add = ui_tabview_container_add;
361 ct->tabs = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 16);
362 return (UiContainer*)ct;
363 }
364
365 Widget ui_tabview_container_prepare(UiContainer *ct, Arg *args, int *n, UiBool fill) {
366 int a = *n;
367 XtSetArg(args[a], XmNleftAttachment, XmATTACH_FORM); a++;
368 XtSetArg(args[a], XmNrightAttachment, XmATTACH_FORM); a++;
369 XtSetArg(args[a], XmNtopAttachment, XmATTACH_FORM); a++;
370 XtSetArg(args[a], XmNbottomAttachment, XmATTACH_FORM); a++;
371 *n = a; 114 *n = a;
372 return ct->widget; 115 return ui_box_container_prepare(box, args, n);
373 } 116 }
374 117
375 void ui_tabview_container_add(UiContainer *ct, Widget widget) { 118 void ui_box_container_add(UiContainerPrivate *ctn, Widget widget) {
376 UiTabViewContainer *tabview = (UiTabViewContainer*)ct; 119 ui_reset_layout(ctn->layout);
377 120
378 if(tabview->current) { 121 }
379 XtUnmanageChild(tabview->current); 122
380 } 123
381 124 /* ---------------------------- Grid Container ---------------------------- */
382 tabview->current = widget; 125
383 cxListAdd(tabview->tabs, widget); 126 // public
384 127 UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) {
385 ui_select_tab(ct->widget, 0); 128 Arg xargs[16];
386 ui_reset_layout(ct->layout);
387 ct->current = widget;
388 }
389
390 UIWIDGET ui_box(UiObject *obj, int margin, int spacing, UiBoxOrientation orientation) {
391 UiContainer *ct = uic_get_current_container(obj);
392
393 Arg args[16];
394 int n = 0; 129 int n = 0;
395 Widget parent = ct->prepare(ct, args, &n, TRUE); 130
396 Widget form = XmCreateForm(parent, "vbox", args, n); 131 XtSetArg(xargs[n], XmNbackground, 0); n++;
397 ct->add(ct, form); 132
398 XtManageChild(form); 133 UiContainerPrivate *ctn = ui_obj_container(obj);
399 134 UI_APPLY_LAYOUT(ctn->layout, args);
400 UiObject *newobj = uic_object_new(obj, form); 135
401 newobj->container = ui_box_container(obj, form, margin, spacing, orientation); 136 Widget parent = ctn->prepare(ctn, xargs, &n);
402 uic_obj_add(obj, newobj); 137 Widget grid = XtCreateManagedWidget(args.name ? args.name : "gridcontainer", gridClass, parent, xargs, n);
403 138 ctn->add(ctn, grid);
404 return form; 139
405 } 140 UiContainerX *container = ui_grid_container(obj, grid);
406 141 uic_object_push_container(obj, container);
407 UIWIDGET ui_vbox(UiObject *obj) {
408 return ui_box(obj, 0, 0, UI_BOX_VERTICAL);
409 }
410
411 UIWIDGET ui_hbox(UiObject *obj) {
412 return ui_box(obj, 0, 0, UI_BOX_HORIZONTAL);
413 }
414
415 UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) {
416 return ui_box(obj, margin, spacing, UI_BOX_VERTICAL);
417 }
418
419 UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) {
420 return ui_box(obj, margin, spacing, UI_BOX_HORIZONTAL);
421 }
422
423 UIWIDGET ui_grid(UiObject *obj) {
424 return ui_grid_sp(obj, 0, 0, 0);
425 }
426
427 UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) {
428 UiContainer *ct = uic_get_current_container(obj);
429
430 Arg args[16];
431 int n = 0;
432 Widget parent = ct->prepare(ct, args, &n, TRUE);
433 Widget grid = XmCreateDrawingArea(parent, "grid", args, n);
434 ct->add(ct, grid);
435 XtManageChild(grid);
436
437 UiObject *newobj = uic_object_new(obj, grid);
438 newobj->container = ui_grid_container(obj, grid, columnspacing, rowspacing);
439 uic_obj_add(obj, newobj);
440
441 XtAddCallback (grid, XmNresizeCallback , ui_grid_resize, newobj->container);
442 142
443 return grid; 143 return grid;
444 } 144 }
445 145
446 UIWIDGET ui_scrolledwindow(UiObject *obj) { 146 UiContainerX* ui_grid_container(UiObject *obj, Widget grid) {
447 UiContainer *ct = uic_get_current_container(obj); 147 UiGridContainer *ctn = ui_malloc(obj->ctx, sizeof(UiGridContainer));
448 148 memset(ctn, 0, sizeof(UiBoxContainer));
449 Arg args[16]; 149 ctn->container.prepare = ui_grid_container_prepare;
450 int n = 0; 150 ctn->container.add = ui_grid_container_add;
451 XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); // TODO: dosn't work, use XmAPPLICATION_DEFINED 151 ctn->container.widget = grid;
452 n++; 152 ctn->x = 0;
453 Widget parent = ct->prepare(ct, args, &n, TRUE); 153 ctn->y = 0;
454 Widget scrolledwindow = XmCreateScrolledWindow(parent, "scrolledwindow", args, n); 154 return (UiContainerX*)ctn;
455 ct->add(ct, scrolledwindow); 155 }
456 XtManageChild(scrolledwindow); 156
457 157 Widget ui_grid_container_prepare(UiContainerPrivate *ctn, Arg *args, int *n) {
458 UiObject *newobj = uic_object_new(obj, scrolledwindow); 158 UiGridContainer *grid = (UiGridContainer*)ctn;
459 newobj->container = ui_scrolledwindow_container(obj, scrolledwindow); 159 if(ctn->layout.newline) {
460 uic_obj_add(obj, newobj); 160 grid->y++;
461 161 grid->x = 0;
462 return scrolledwindow; 162 }
463 } 163
464 164 int a = *n;
465 UIWIDGET ui_sidebar(UiObject *obj) { 165 XtSetArg(args[a], gridColumn, grid->x); a++;
466 UiContainer *ct = uic_get_current_container(obj); 166 XtSetArg(args[a], gridRow, grid->y); a++;
467 167 if(ctn->layout.colspan > 0) {
468 Arg args[16]; 168 XtSetArg(args[a], gridColspan, ctn->layout.colspan); a++;
469 int n = 0; 169 }
470 170 if(ctn->layout.rowspan > 0) {
471 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); 171 XtSetArg(args[a], gridRowspan, ctn->layout.rowspan); a++;
472 n++; 172 }
473 173
474 Widget parent = ct->prepare(ct, args, &n, TRUE); 174 if(grid->container.layout.fill == UI_ON) {
475 Widget pane = XmCreatePanedWindow(parent, "pane", args, n); 175 grid->container.layout.hfill = TRUE;
476 ct->add(ct, pane); 176 grid->container.layout.vfill = TRUE;
477 XtManageChild(pane); 177 grid->container.layout.hexpand = TRUE;
478 178 grid->container.layout.vexpand = TRUE;
479 // add sidebar widget 179 }
480 Widget sidebar = XmCreateForm(pane, "sidebar", args, 0); 180
481 XtManageChild(sidebar); 181 if(grid->container.layout.hfill) {
482 182 XtSetArg(args[a], gridHFill, TRUE); a++;
483 UiObject *left = uic_object_new(obj, sidebar); 183 }
484 left->container = ui_box_container(left, sidebar, 0, 0, UI_BOX_VERTICAL); 184 if(grid->container.layout.vfill) {
485 185 XtSetArg(args[a], gridVFill, TRUE); a++;
486 // add content widget 186 }
487 XtSetArg (args[0], XmNpaneMaximum, 8000); 187 if(grid->container.layout.hexpand) {
488 Widget content = XmCreateForm(pane, "content_area", args, 1); 188 XtSetArg(args[a], gridHExpand, TRUE); a++;
489 XtManageChild(content); 189 }
490 190 if(grid->container.layout.vexpand) {
491 UiObject *right = uic_object_new(obj, content); 191 XtSetArg(args[a], gridVExpand, TRUE); a++;
492 right->container = ui_box_container(right, content, 0, 0, UI_BOX_VERTICAL); 192 }
493 193
494 uic_obj_add(obj, right); 194 *n = a;
495 uic_obj_add(obj, left); 195 return ctn->widget;
496 196 }
497 return sidebar; 197
498 } 198 void ui_grid_container_add(UiContainerPrivate *ctn, Widget widget) {
499 199 UiGridContainer *grid = (UiGridContainer*)ctn;
500 UIWIDGET ui_tabview(UiObject *obj) { 200 grid->x++;
501 UiContainer *ct = uic_get_current_container(obj); 201 ui_reset_layout(ctn->layout);
502 202 }
503 // create a simple frame as container widget 203
504 // when tabs are selected, the current child will be replaced by the 204
505 // the new tab widget 205 /* -------------------- Container Helper Functions -------------------- */
506 Arg args[16]; 206
507 int n = 0; 207 void ui_container_begin_close(UiObject *obj) {
508 XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); 208 UiContainerPrivate *ct = ui_obj_container(obj);
509 n++; 209 ct->container.close = 1;
510 XtSetArg(args[n], XmNshadowThickness, 0); 210 }
511 n++; 211
512 Widget parent = ct->prepare(ct, args, &n, TRUE); 212 int ui_container_finish(UiObject *obj) {
513 Widget form = XmCreateForm(parent, "tabview", args, n); 213 UiContainerPrivate *ct = ui_obj_container(obj);
514 ct->add(ct, form); 214 if(ct->container.close) {
515 XtManageChild(form); 215 ui_end_new(obj);
516 216 return 0;
517 UiObject *tabviewobj = uic_object_new(obj, form); 217 }
518 tabviewobj->container = ui_tabview_container(obj, form); 218 return 1;
519 uic_obj_add(obj, tabviewobj); 219 }
520
521 XtVaSetValues(form, XmNuserData, tabviewobj->container, NULL);
522
523 return form;
524 }
525
526 void ui_tab(UiObject *obj, char *title) {
527 UiContainer *ct = uic_get_current_container(obj);
528 ct->layout.label = title;
529
530 ui_vbox(obj);
531 }
532
533 void ui_select_tab(UIWIDGET tabview, int tab) {
534 UiTabViewContainer *ct = NULL;
535 XtVaGetValues(tabview, XmNuserData, &ct, NULL);
536 if(ct) {
537 XtUnmanageChild(ct->current);
538 Widget w = cxListAt(ct->tabs, tab);
539 if(w) {
540 XtManageChild(w);
541 ct->current = w;
542 } else {
543 fprintf(stderr, "UiError: front tab index: %d\n", tab);
544 }
545 } else {
546 fprintf(stderr, "UiError: widget is not a tabview\n");
547 }
548 }
549
550
551 /* document tabview */
552
553 static void ui_tabbar_resize(Widget widget, XtPointer udata, XtPointer cdata) {
554 MotifTabbedPane *v = (MotifTabbedPane*)udata;
555
556 int width = 0;
557 int height = 0;
558 XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL);
559 int button_width = width / 4;
560 int x = 0;
561 CxIterator tabIterator = cxListIterator(v->tabs);
562 cx_foreach(UiTab*, tab, tabIterator) {
563 XtVaSetValues(
564 tab->tab_button,
565 XmNx, x,
566 XmNy, 0,
567 XmNwidth,
568 button_width,
569
570 NULL);
571 x += button_width;
572 }
573
574 if(height <= v->height) {
575 XtVaSetValues(widget, XmNheight, v->height + 4, NULL);
576 }
577 }
578
579 static void ui_tabbar_expose(Widget widget, XtPointer udata, XtPointer cdata) {
580 MotifTabbedPane *v = (MotifTabbedPane*)udata;
581 XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *)cdata;
582 XEvent *event = cbs->event;
583 Display *dpy = XtDisplay(widget);
584
585 XGCValues gcvals;
586 GC gc;
587 Pixel fgpix;
588
589 int tab_x;
590 int tab_width;
591 XtVaGetValues(v->current->tab_button, XmNx, &tab_x, XmNwidth, &tab_width, XmNhighlightColor, &fgpix, NULL);
592
593 gcvals.foreground = v->bg1;
594 gc = XCreateGC( dpy, XtWindow(widget), (GCForeground), &gcvals);
595
596 int width = 0;
597 int height = 0;
598 XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL);
599 XFillRectangle(dpy, XtWindow(widget), gc, 0, 0, width, height);
600
601 gcvals.foreground = fgpix;
602 gc = XCreateGC( dpy, XtWindow(widget), (GCForeground), &gcvals);
603
604 XFillRectangle(dpy, XtWindow(widget), gc, tab_x, 0, tab_width, height);
605
606 }
607
608 UiTabbedPane* ui_tabbed_document_view(UiObject *obj) {
609 int n = 0;
610 Arg args[16];
611
612 UiContainer *ct = uic_get_current_container(obj);
613 Widget parent = ct->prepare(ct, args, &n, TRUE);
614
615 Widget tabview = XmCreateForm(parent, "tabview_form", args, n);
616 XtManageChild(tabview);
617
618 XtSetArg(args[0], XmNorientation, XmHORIZONTAL);
619 XtSetArg(args[1], XmNpacking, XmPACK_TIGHT);
620 XtSetArg(args[2], XmNspacing, 1);
621 XtSetArg(args[3], XmNleftAttachment, XmATTACH_FORM);
622 XtSetArg(args[4], XmNrightAttachment, XmATTACH_FORM);
623 XtSetArg(args[5], XmNtopAttachment, XmATTACH_FORM);
624 XtSetArg(args[6], XmNmarginWidth, 0);
625 XtSetArg(args[7], XmNmarginHeight, 0);
626 Widget tabbar = XmCreateDrawingArea(tabview, "tabbar", args, 8);
627 XtManageChild(tabbar);
628
629 XtSetArg(args[0], XmNleftAttachment, XmATTACH_FORM);
630 XtSetArg(args[1], XmNrightAttachment, XmATTACH_FORM);
631 XtSetArg(args[2], XmNtopAttachment, XmATTACH_WIDGET);
632 XtSetArg(args[3], XmNtopWidget, tabbar);
633 XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM);
634 XtSetArg(args[5], XmNshadowThickness, 0);
635 Widget tabct = XmCreateForm(tabview, "tabview", args, 6);
636 XtManageChild(tabct);
637
638 MotifTabbedPane *tabbedpane = ui_malloc(obj->ctx, sizeof(MotifTabbedPane));
639 tabbedpane->view.ctx = uic_current_obj(obj)->ctx;
640 tabbedpane->view.widget = tabct;
641 tabbedpane->view.document = NULL;
642 tabbedpane->tabbar = tabbar;
643 tabbedpane->tabs = cxArrayListCreate(obj->ctx->allocator, cx_cmp_uintptr, CX_STORE_POINTERS, 16);
644 tabbedpane->current = NULL;
645 tabbedpane->height = 0;
646
647 XtAddCallback(tabbar, XmNresizeCallback , ui_tabbar_resize, tabbedpane);
648 XtAddCallback(tabbar, XmNexposeCallback, ui_tabbar_expose, tabbedpane);
649
650 return &tabbedpane->view;
651 }
652
653 UiObject* ui_document_tab(UiTabbedPane *view) {
654 MotifTabbedPane *v = (MotifTabbedPane*)view;
655 int n = 0;
656 Arg args[16];
657
658 // hide the current tab content
659 if(v->current) {
660 XtUnmanageChild(v->current->content->widget);
661 }
662
663 UiTab *tab = ui_malloc(view->ctx, sizeof(UiTab));
664
665 // create the new tab content
666 XtSetArg(args[0], XmNshadowThickness, 0);
667 XtSetArg(args[1], XmNleftAttachment, XmATTACH_FORM);
668 XtSetArg(args[2], XmNrightAttachment, XmATTACH_FORM);
669 XtSetArg(args[3], XmNtopAttachment, XmATTACH_FORM);
670 XtSetArg(args[4], XmNbottomAttachment, XmATTACH_FORM);
671 XtSetArg(args[5], XmNuserData, tab);
672 Widget frame = XmCreateFrame(view->widget, "tab", args, 6);
673 XtManageChild(frame);
674
675 UiObject *content = ui_malloc(view->ctx, sizeof(UiObject));
676 content->widget = NULL; // initialization for uic_context()
677 content->ctx = uic_context(content, view->ctx->mp);
678 content->ctx->parent = view->ctx;
679 content->ctx->attach_document = uic_context_attach_document;
680 content->ctx->detach_document2 = uic_context_detach_document2;
681 content->widget = frame;
682 content->window = view->ctx->obj->window;
683 content->container = ui_frame_container(content, frame);
684 content->next = NULL;
685
686 // add tab button
687 cxListAdd(v->tabs, tab);
688
689 XmString label = XmStringCreateLocalized("tab");
690 XtSetArg(args[0], XmNlabelString, label);
691 XtSetArg(args[1], XmNshadowThickness, 0);
692 XtSetArg(args[2], XmNhighlightThickness, 0);
693
694 Widget button = XmCreatePushButton(v->tabbar, "tab_button", args, 3);
695 tab->tabbedpane = v;
696 tab->content = content;
697 tab->tab_button = button;
698 XtManageChild(button);
699 XtAddCallback(
700 button,
701 XmNactivateCallback,
702 (XtCallbackProc)ui_tab_button_callback,
703 tab);
704
705 if(v->height == 0) {
706 XtVaGetValues(
707 button,
708 XmNarmColor,
709 &v->bg1,
710 XmNbackground,
711 &v->bg2,
712 XmNheight,
713 &v->height,
714 NULL);
715 v->height += 2; // border
716 }
717
718 ui_change_tab(v, tab);
719 ui_tabbar_resize(v->tabbar, v, NULL);
720
721 return content;
722 }
723
724 void ui_tab_button_callback(Widget widget, UiTab *tab, XtPointer d) {
725 MotifTabbedPane *t = tab->tabbedpane;
726 if(t->current) {
727 XtUnmanageChild(t->current->content->widget);
728 XtVaSetValues(t->current->tab_button, XmNset, 0, NULL);
729 }
730 XtManageChild(tab->content->widget);
731
732 ui_change_tab(t, tab);
733
734 }
735
736 void ui_change_tab(MotifTabbedPane *pane, UiTab *tab) {
737 UiContext *ctx = tab->content->ctx;
738 ctx->parent->detach_document2(ctx->parent, pane->current->content->ctx->document);
739 ctx->parent->attach_document(ctx->parent, ctx->document);
740
741 if(pane->current) {
742 XtVaSetValues(pane->current->tab_button, XmNshadowThickness, 0, XmNbackground, pane->bg1, NULL);
743 }
744 XtVaSetValues(tab->tab_button, XmNshadowThickness, 1, XmNbackground, pane->bg2, NULL);
745
746 pane->current = tab;
747 pane->index = cxListFind(pane->tabs, tab);
748 printf("index: %d\n", pane->index);
749
750 // redraw tabbar
751 Display *dpy = XtDisplay(pane->tabbar);
752 Window window = XtWindow(pane->tabbar);
753 if(dpy && window) {
754 XClearArea(dpy, XtWindow(pane->tabbar), 0, 0, 0, 0, TRUE);
755 XFlush(dpy);
756 }
757 }
758
759 void ui_tab_set_document(UiContext *ctx, void *document) {
760 if(ctx->parent->document) {
761 //ctx->parent->detach_document(ctx->parent, ctx->parent->document);
762 }
763 uic_context_attach_document(ctx, document);
764 //uic_context_set_document(ctx->parent, document);
765 //ctx->parent->document = document;
766
767 UiTab *tab = NULL;
768 XtVaGetValues(
769 ctx->obj->widget,
770 XmNuserData,
771 &tab,
772 NULL);
773 if(tab) {
774 if(tab->tabbedpane->current == tab) {
775 ctx->parent->attach_document(ctx->parent, ctx->document);
776 }
777 } else {
778 fprintf(stderr, "UiError: ui_bar_set_document: Cannot set document");
779 }
780 }
781
782 220
783 221
784 /* 222 /*
785 * -------------------- Layout Functions -------------------- 223 * -------------------- Layout Functions --------------------
786 * 224 *
787 * functions for setting layout attributes for the current container 225 * functions for setting layout attributes for the current container
788 * 226 *
789 */ 227 */
790 228
791 void ui_layout_fill(UiObject *obj, UiBool fill) {
792 UiContainer *ct = uic_get_current_container(obj);
793 ct->layout.fill = ui_bool2lb(fill);
794 }
795
796 void ui_layout_hexpand(UiObject *obj, UiBool expand) {
797 UiContainer *ct = uic_get_current_container(obj);
798 ct->layout.hexpand = expand;
799 }
800
801 void ui_layout_vexpand(UiObject *obj, UiBool expand) {
802 UiContainer *ct = uic_get_current_container(obj);
803 ct->layout.vexpand = expand;
804 }
805
806 void ui_layout_gridwidth(UiObject *obj, int width) {
807 UiContainer *ct = uic_get_current_container(obj);
808 ct->layout.gridwidth = width;
809 }
810
811 void ui_newline(UiObject *obj) { 229 void ui_newline(UiObject *obj) {
812 UiContainer *ct = uic_get_current_container(obj); 230 UiContainerPrivate *ct = ui_obj_container(obj);
813 ct->layout.newline = TRUE; 231 ct->layout.newline = TRUE;
814 } 232 }

mercurial