Sun, 22 Sep 2024 16:39:10 +0200
add libadwaita toolkit option
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2017 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 <stdlib.h> #include <limits.h> #include "container.h" #include "toolkit.h" #include "../common/context.h" #include "../common/object.h" void ui_container_begin_close(UiObject *obj) { UiContainer *ct = uic_get_current_container(obj); ct->close = 1; } int ui_container_finish(UiObject *obj) { UiContainer *ct = uic_get_current_container(obj); if(ct->close) { ui_end(obj); return 0; } return 1; } GtkWidget* ui_gtk_vbox_new(int spacing) { #if GTK_MAJOR_VERSION >= 3 return gtk_box_new(GTK_ORIENTATION_VERTICAL, spacing); #else return gtk_vbox_new(FALSE, spacing); #endif } GtkWidget* ui_gtk_hbox_new(int spacing) { #if GTK_MAJOR_VERSION >= 3 return gtk_box_new(GTK_ORIENTATION_HORIZONTAL, spacing); #else return gtk_hbox_new(FALSE, spacing); #endif } /* -------------------- Box Container -------------------- */ UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type) { UiBoxContainer *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiBoxContainer)); ct->container.widget = box; ct->container.add = ui_box_container_add; ct->type = type; return (UiContainer*)ct; } void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { UiBoxContainer *bc = (UiBoxContainer*)ct; if(ct->layout.fill != UI_LAYOUT_UNDEFINED) { fill = ui_lb2bool(ct->layout.fill); } if(bc->has_fill && fill) { fprintf(stderr, "UiError: container has 2 filled widgets"); fill = FALSE; } if(fill) { bc->has_fill = TRUE; } UiBool expand = fill; #if GTK_MAJOR_VERSION >= 4 gtk_box_append(GTK_BOX(ct->widget), widget); GtkAlign align = expand ? GTK_ALIGN_FILL : GTK_ALIGN_START; if(bc->type == UI_CONTAINER_VBOX) { gtk_widget_set_valign(widget, align); gtk_widget_set_vexpand(widget, expand); gtk_widget_set_hexpand(widget, TRUE); } else if(bc->type == UI_CONTAINER_HBOX) { gtk_widget_set_halign(widget, align); gtk_widget_set_hexpand(widget, expand); gtk_widget_set_vexpand(widget, TRUE); } #else gtk_box_pack_start(GTK_BOX(ct->widget), widget, expand, fill, 0); #endif ui_reset_layout(ct->layout); ct->current = widget; } UiContainer* ui_grid_container(UiObject *obj, GtkWidget *grid) { UiGridContainer *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiGridContainer)); ct->container.widget = grid; ct->container.add = ui_grid_container_add; #ifdef UI_GTK2 ct->width = 0; ct->height = 1; #endif return (UiContainer*)ct; } #if GTK_MAJOR_VERSION >= 3 void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { UiGridContainer *grid = (UiGridContainer*)ct; if(ct->layout.newline) { grid->x = 0; grid->y++; ct->layout.newline = FALSE; } int hexpand = FALSE; int vexpand = FALSE; if(ct->layout.hexpand != UI_LAYOUT_UNDEFINED) { hexpand = ct->layout.hexpand; } if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) { vexpand = ct->layout.vexpand; } if(hexpand) { gtk_widget_set_hexpand(widget, TRUE); } if(vexpand) { gtk_widget_set_vexpand(widget, TRUE); } int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1; int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1; gtk_grid_attach(GTK_GRID(ct->widget), widget, grid->x, grid->y, colspan, rowspan); grid->x += colspan; ui_reset_layout(ct->layout); ct->current = widget; } #endif #ifdef UI_GTK2 void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { UiGridContainer *grid = (UiGridContainer*)ct; if(ct->layout.newline) { grid->x = 0; grid->y++; ct->layout.newline = FALSE; } int hexpand = FALSE; int vexpand = FALSE; if(ct->layout.hexpand != UI_LAYOUT_UNDEFINED) { hexpand = ct->layout.hexpand; } if(ct->layout.vexpand != UI_LAYOUT_UNDEFINED) { vexpand = ct->layout.vexpand; } GtkAttachOptions xoptions = hexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; GtkAttachOptions yoptions = vexpand ? GTK_FILL | GTK_EXPAND : GTK_FILL; int colspan = ct->layout.colspan > 0 ? ct->layout.colspan : 1; int rowspan = ct->layout.rowspan > 0 ? ct->layout.rowspan : 1; // TODO: use colspan/rowspan gtk_table_attach(GTK_TABLE(ct->widget), widget, grid->x, grid->x+1, grid->y, grid->y+1, xoptions, yoptions, 0, 0); grid->x++; int nw = grid->x > grid->width ? grid->x : grid->width; if(grid->x > grid->width || grid->y > grid->height) { grid->width = nw; grid->height = grid->y + 1; gtk_table_resize(GTK_TABLE(ct->widget), grid->width, grid->height); } ui_reset_layout(ct->layout); ct->current = widget; } #endif UiContainer* ui_scrolledwindow_container(UiObject *obj, GtkWidget *scrolledwindow) { UiContainer *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiContainer)); ct->widget = scrolledwindow; ct->add = ui_scrolledwindow_container_add; return ct; } void ui_scrolledwindow_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { // TODO: check if the widget implements GtkScrollable #ifdef UI_GTK4 gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(ct->widget), widget); #elif defined(UI_GTK3) gtk_container_add(GTK_CONTAINER(ct->widget), widget); #else gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(ct->widget), widget); #endif ui_reset_layout(ct->layout); ct->current = widget; } UiContainer* ui_tabview_container(UiObject *obj, GtkWidget *tabview) { UiTabViewContainer *ct = cxCalloc( obj->ctx->allocator, 1, sizeof(UiTabViewContainer)); ct->container.widget = tabview; ct->container.add = ui_tabview_container_add; return (UiContainer*)ct; } void ui_tabview_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { gtk_notebook_append_page( GTK_NOTEBOOK(ct->widget), widget, gtk_label_new(ct->layout.label)); ui_reset_layout(ct->layout); ct->current = widget; } static GtkWidget* box_set_margin(GtkWidget *box, int margin) { GtkWidget *ret = box; #ifdef UI_GTK3 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 12 gtk_widget_set_margin_start(box, margin); gtk_widget_set_margin_end(box, margin); #else gtk_widget_set_margin_left(box, margin); gtk_widget_set_margin_right(box, margin); #endif gtk_widget_set_margin_top(box, margin); gtk_widget_set_margin_bottom(box, margin); #elif defined(UI_GTK2) GtkWidget *a = gtk_alignment_new(0.5, 0.5, 1, 1); gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin, margin, margin, margin); gtk_container_add(GTK_CONTAINER(a), box); ret = a; #endif return ret; } UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type) { UiObject *current = uic_current_obj(obj); UiContainer *ct = current->container; UI_APPLY_LAYOUT1(current, args); GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing); GtkWidget *widget = args.margin > 0 ? box_set_margin(box, args.margin) : box; ct->add(ct, widget, TRUE); UiObject *newobj = uic_object_new(obj, box); newobj->container = ui_box_container(obj, box, type); uic_obj_add(obj, newobj); return widget; } UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) { return ui_box_create(obj, args, UI_CONTAINER_VBOX); } UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) { return ui_box_create(obj, args, UI_CONTAINER_HBOX); } UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) { UiObject* current = uic_current_obj(obj); UI_APPLY_LAYOUT1(current, args); GtkWidget *widget; #if GTK_MAJOR_VERSION >= 3 GtkWidget *grid = gtk_grid_new(); gtk_grid_set_column_spacing(GTK_GRID(grid), args.columnspacing); gtk_grid_set_row_spacing(GTK_GRID(grid), args.rowspacing); #if GTK_MAJOR_VERSION >= 3 && GTK_MINOR_VERSION >= 12 gtk_widget_set_margin_start(grid, args.margin); gtk_widget_set_margin_end(grid, args.margin); #else gtk_widget_set_margin_left(grid, args.margin); gtk_widget_set_margin_right(grid, args.margin); #endif gtk_widget_set_margin_top(grid, args.margin); gtk_widget_set_margin_bottom(grid, args.margin); widget = grid; #elif defined(UI_GTK2) GtkWidget *grid = gtk_table_new(1, 1, FALSE); gtk_table_set_col_spacings(GTK_TABLE(grid), columnspacing); gtk_table_set_row_spacings(GTK_TABLE(grid), rowspacing); if(margin > 0) { GtkWidget *a = gtk_alignment_new(0.5, 0.5, 1, 1); gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin, margin, margin, margin); gtk_container_add(GTK_CONTAINER(a), grid); widget = a; } else { widget = grid; } #endif current->container->add(current->container, widget, TRUE); UiObject *newobj = uic_object_new(obj, grid); newobj->container = ui_grid_container(obj, grid); uic_obj_add(obj, newobj); return widget; } UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) { UiObject* current = uic_current_obj(obj); UI_APPLY_LAYOUT1(current, args); GtkWidget *sw = SCROLLEDWINDOW_NEW(); UiObject *newobj = uic_object_new(obj, sw); newobj->container = ui_scrolledwindow_container(obj, sw); uic_obj_add(obj, newobj); return sw; } void ui_select_tab(UIWIDGET tabview, int tab) { gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab); } /* -------------------- Splitpane -------------------- */ static GtkWidget* create_paned(UiOrientation orientation) { #if GTK_MAJOR_VERSION >= 3 switch(orientation) { case UI_HORIZONTAL: return gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); case UI_VERTICAL: return gtk_paned_new(GTK_ORIENTATION_VERTICAL); } #else switch(orientation) { case UI_HORIZONTAL: return gtk_hpaned_new(); case UI_VERTICAL: return gtk_vpaned_new(); } #endif return NULL; } /* * -------------------- Layout Functions -------------------- * * functions for setting layout attributes for the current container * */ void ui_layout_fill(UiObject *obj, UiBool fill) { UiContainer *ct = uic_get_current_container(obj); ct->layout.fill = ui_bool2lb(fill); } void ui_layout_hexpand(UiObject *obj, UiBool expand) { UiContainer *ct = uic_get_current_container(obj); ct->layout.hexpand = expand; } void ui_layout_vexpand(UiObject *obj, UiBool expand) { UiContainer *ct = uic_get_current_container(obj); ct->layout.vexpand = expand; } void ui_layout_colspan(UiObject* obj, int cols) { UiContainer* ct = uic_get_current_container(obj); ct->layout.colspan = cols; } void ui_layout_rowspan(UiObject* obj, int rows) { UiContainer* ct = uic_get_current_container(obj); ct->layout.rowspan = rows; } void ui_newline(UiObject *obj) { UiContainer *ct = uic_get_current_container(obj); ct->layout.newline = TRUE; }