Sun, 19 Oct 2025 21:20:08 +0200
update toolkit
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2014 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include "container.h" #include "../common/object.h" #include "../common/container.h" #include <cx/mempool.h> #include <QSpacerItem> #include <QStackedWidget> #include <QLabel> #include <QDockWidget> static void delete_container(UiContainerPrivate *ct) { delete ct; } void ui_obj_add_container(UiObject *obj, UiContainerPrivate *ct) { UiContainerX *container = (UiContainerX*)ui_malloc(obj->ctx, sizeof(UiContainerX)); container->close = 0; container->container = ct; container->prev = NULL; container->next = NULL; ct->container = container; cxMempoolRegister(obj->ctx->mp, ct, (cx_destructor_func)delete_container); uic_object_push_container(obj, container); } /* ------------------------ margin helper ------------------------ */ QWidget* ui_widget_set_margin(QWidget *w, int left, int right, int top, int bottom) { if((left | right | top | bottom) == 0) { return w; } QWidget* wrapper = new QWidget; QVBoxLayout* inner = new QVBoxLayout(wrapper); inner->setContentsMargins(left, top, right, bottom); inner->addWidget(w); // TODO: handle widget visibility changes return wrapper; } /* -------------------- UiBoxContainer -------------------- */ UiBoxContainer::UiBoxContainer(QBoxLayout* box) { this->box = box; this->direction = box->direction(); box->setContentsMargins(QMargins(0,0,0,0)); box->setSpacing(0); } void UiBoxContainer::add(QWidget* widget, UiLayout& layout) { bool fill = layout.fill; if(hasStretchedWidget && fill) { fill = false; fprintf(stderr, "UiError: container has 2 filled widgets"); } uic_layout_setup_margin(&layout); widget = ui_widget_set_margin(widget, layout.margin_left, layout.margin_right, layout.margin_top, layout.margin_bottom); box->addWidget(widget); if(direction == Qt::LeftToRight) { box->setAlignment(widget, Qt::AlignTop); } if(!hasStretchedWidget) { QSpacerItem *newspace = new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); box->removeItem(space); box->addSpacerItem(newspace); space = newspace; } if(fill) { hasStretchedWidget = true; } current = widget; } UIWIDGET ui_box(UiObject *obj, UiContainerArgs *args, QBoxLayout::Direction dir) { UiContainerPrivate *ctn = (UiContainerPrivate*)ui_obj_container(obj); UiLayout layout = UI_ARGS2LAYOUT(args); QWidget *widget = new QWidget(); QBoxLayout *box = new QBoxLayout(dir); widget->setLayout(box); ctn->add(widget, layout); ui_obj_add_container(obj, new UiBoxContainer(box)); return widget; } UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) { return ui_box(obj, args, QBoxLayout::TopToBottom); } UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) { return ui_box(obj, args, QBoxLayout::LeftToRight); } /* -------------------- UiGridContainer -------------------- */ UiGridContainer::UiGridContainer( QGridLayout *grid, int margin, int columnspacing, int rowspacing, bool def_hexpand, bool def_vexpand, bool def_hfill, bool def_vfill) { this->current = NULL; this->grid = grid; this->def_hexpand = def_hexpand; this->def_vexpand = def_vexpand; this->def_hfill = def_hfill; this->def_vfill = def_vfill; grid->setContentsMargins(QMargins(margin, margin, margin, margin)); grid->setHorizontalSpacing(columnspacing); grid->setVerticalSpacing(rowspacing); } void UiGridContainer::add(QWidget* widget, UiLayout& layout) { if(container->newline) { x = 0; y++; container->newline = false; } uic_layout_setup_expand_fill(&layout, def_hexpand, def_vexpand, def_hfill, def_vfill); uic_layout_setup_margin(&layout); if(layout.hexpand) { col_expanding = true; } if(layout.vexpand) { row_expanding = true; } if(layout.hexpand) { grid->setColumnStretch(x, 1); } if(layout.vexpand) { grid->setRowStretch(y, 1); } Qt::Alignment alignment = 0; if(!layout.hfill) { alignment = Qt::AlignLeft; } if(!layout.vfill) { alignment = Qt::AlignTop; } int colspan = layout.colspan > 0 ? layout.colspan : 1; int rowspan = layout.rowspan > 0 ? layout.rowspan : 1; widget = ui_widget_set_margin(widget, layout.margin_left, layout.margin_right, layout.margin_top, layout.margin_bottom); grid->addWidget(widget, y, x, rowspan, colspan, alignment); if(x > max_x) { max_x = x; } if(y > max_y) { max_y = y; } x += colspan; current = widget; } void UiGridContainer::end() { if(!col_expanding) { QSpacerItem *filler = new QSpacerItem(0, 0); x = max_x + 1; grid->setColumnStretch(x, 1); grid->addItem(filler, 0, x, 1, 1, 0); } if(!row_expanding) { QSpacerItem *filler = new QSpacerItem(0, 0); y++; grid->setRowStretch(y, 1); grid->addItem(filler, y, 0, 1, 1, 0); } } UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { UiContainerPrivate *ctn = (UiContainerPrivate*)ui_obj_container(obj); UiLayout layout = UI_ARGS2LAYOUT(args); QWidget *widget = new QWidget(); QGridLayout *grid = new QGridLayout(); widget->setLayout(grid); ctn->add(widget, layout); ui_obj_add_container(obj, new UiGridContainer( grid, args->margin, args->columnspacing, args->rowspacing, args->def_hexpand, args->def_vexpand, args->def_hfill, args->def_vfill)); return widget; } /* ---------------------------- UiSidebar ---------------------------- */ UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs *args) { QVariant v = obj->widget->property("ui_sidebar"); QDockWidget *dock = (QDockWidget*)v.value<void*>(); if(!dock) { fprintf(stderr, "Error: window is not configured for sidebar\n"); return nullptr; } QWidget *widget = new QWidget(); QBoxLayout *box = new QBoxLayout(QBoxLayout::TopToBottom); widget->setLayout(box); dock->setWidget(widget); ui_obj_add_container(obj, new UiBoxContainer(box)); return dock; } /* -------------------- Container Helper Functions -------------------- */ void ui_container_begin_close(UiObject *obj) { obj->container_end->close = true; } int ui_container_finish(UiObject *obj) { if(obj->container_end->close) { UiContainerPrivate *ctn = (UiContainerPrivate*)obj->container_end->container; ctn->end(); ui_end_new(obj); return 0; } return 1; }