UNIXworkcode

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 628