Thu, 05 Dec 2024 08:40:37 +0100
fix grid colspan/rowspan
/* * 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 <string.h> #include <stdbool.h> #include "toolkit.h" #include "toolbar.h" #include "icon.h" #include "../common/document.h" #include "../common/properties.h" #include "../common/menu.h" #include "../common/toolbar.h" #include "../common/threadpool.h" #include <cx/utils.h> #include <cx/string.h> #include <cx/printf.h> #include <pthread.h> #ifdef UI_APPLICATION UI_APPLICATION app; #endif static const char *application_name; static ui_callback startup_func; static void *startup_data; static ui_callback open_func; void *open_data; static ui_callback exit_func; void *exit_data; static ui_callback appclose_fnc; static void *appclose_udata; static UiObject *active_window; static int scale_factor = 1; UIEXPORT void ui_init(const char *appname, int argc, char **argv) { application_name = appname; uic_init_global_context(); #if GTK_MAJOR_VERSION >= 4 gtk_init(); #else gtk_init(&argc, &argv); #endif ui_css_init(); uic_docmgr_init(); uic_menu_init(); uic_toolbar_init(); ui_image_init(); uic_load_app_properties(); #if GTK_MAJOR_VERSION >= 4 scale_factor = 1; // TODO #elif defined(UI_SUPPORTS_SCALE) scale_factor = gdk_monitor_get_scale_factor( gdk_display_get_primary_monitor(gdk_display_get_default())); #endif } const char* ui_appname() { return application_name; } void ui_onstartup(ui_callback f, void *userdata) { startup_func = f; startup_data = userdata; } void ui_onopen(ui_callback f, void *userdata) { open_func = f; open_data = userdata; } void ui_onexit(ui_callback f, void *userdata) { exit_func = f; exit_data = userdata; } #ifndef UI_GTK2 static void app_startup(GtkApplication* app, gpointer userdata) { if(startup_func) { startup_func(NULL, startup_data); } } static void app_activate(GtkApplication* app, gpointer userdata) { printf("activate\n"); } #endif void ui_main() { #ifdef UI_APPLICATION cxmutstr appid = cx_asprintf( "ui.%s", application_name ? application_name : "application1"); app = UI_APPLICATION_NEW(appid.ptr); g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); g_application_run(G_APPLICATION (app), 0, NULL); g_object_unref (app); free(appid.ptr); #else if(startup_func) { startup_func(NULL, startup_data); } gtk_main(); #endif if(exit_func) { exit_func(NULL, exit_data); } uic_store_app_properties(); } #ifndef UI_GTK2 void ui_app_quit() { g_application_quit(G_APPLICATION(app)); } GtkApplication* ui_get_application() { return GTK_APPLICATION(app); } #endif void ui_show(UiObject *obj) { gboolean visible = gtk_widget_is_visible(obj->widget); uic_check_group_widgets(obj->ctx); #if GTK_MAJOR_VERSION >= 4 gtk_window_present(GTK_WINDOW(obj->widget)); #elif GTK_MAJOR_VERSION <= 3 gtk_widget_show_all(obj->widget); #endif if(!visible) { obj->ref++; } } void ui_close(UiObject *obj) { uic_context_prepare_close(obj->ctx); #if GTK_CHECK_VERSION(4, 0, 0) gtk_window_close(GTK_WINDOW(obj->widget)); #else gtk_widget_destroy(obj->widget); #endif } static gboolean ui_job_finished(void *data) { UiJob *job = data; UiEvent event; event.obj = job->obj; event.window = job->obj->window; event.document = job->obj->ctx->document; event.intval = 0; event.eventdata = NULL; job->finish_callback(&event, job->finish_data); free(job); return FALSE; } static void* ui_jobthread(void *data) { UiJob *job = data; int result = job->job_func(job->job_data); if(!result && job->finish_callback) { g_idle_add(ui_job_finished, job); } else { free(job); } return NULL; } static gboolean ui_idle_func(void *data) { UiJob *job = data; job->job_func(job->job_data); free(job); return FALSE; } void ui_call_mainthread(ui_threadfunc tf, void* td) { UiJob *job = malloc(sizeof(UiJob)); job->job_func = tf; job->job_data = td; job->finish_callback = NULL; job->finish_data = NULL; job->obj = NULL; g_idle_add(ui_idle_func, job); } void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd) { UiJob *job = malloc(sizeof(UiJob)); job->obj = obj; job->job_func = tf; job->job_data = td; job->finish_callback = f; job->finish_data = fd; pthread_t pid; pthread_create(&pid, NULL, ui_jobthread, job); } void ui_set_enabled(UIWIDGET widget, int enabled) { gtk_widget_set_sensitive(widget, enabled); } void ui_set_show_all(UIWIDGET widget, int value) { // TODO: gtk4 #if GTK_MAJOR_VERSION <= 3 gtk_widget_set_no_show_all(widget, !value); #endif } void ui_set_visible(UIWIDGET widget, int visible) { // TODO: gtk4 #if GTK_MAJOR_VERSION <= 3 if(visible) { gtk_widget_set_no_show_all(widget, FALSE); gtk_widget_show_all(widget); } else { gtk_widget_hide(widget); } #endif } void ui_clipboard_set(char *str) { #if GTK_MAJOR_VERSION >= 4 // TODO: gtk4: needs widget #else GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); gtk_clipboard_set_text(cb, str, strlen(str)); #endif } char* ui_clipboard_get() { #if GTK_MAJOR_VERSION >= 4 // TODO: gtk4: needs widget return NULL; #else GtkClipboard *cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); char *str = gtk_clipboard_wait_for_text(cb); if(str) { char *copy = strdup(str); g_free(str); return copy; } else { return NULL; } #endif } int ui_get_scalefactor() { return scale_factor; } void ui_destroy_userdata(GtkWidget *object, void *userdata) { free(userdata); } void ui_destroy_vardata(GtkWidget *object, UiVarEventData *data) { if(data->var) { ui_destroy_boundvar(data->obj->ctx, data->var); } free(data); } void ui_destroy_boundvar(UiContext *ctx, UiVar *var) { uic_unbind_var(var); if(var->type == UI_VAR_SPECIAL) { ui_free(var->from_ctx, var); } else { ui_free(var->from_ctx, var); // TODO: free or unbound //uic_remove_bound_var(ctx, var); } } void ui_set_active_window(UiObject *obj) { active_window = obj; } UiObject *ui_get_active_window() { return active_window; } #if GTK_MAJOR_VERSION >= 3 static GtkCssProvider* ui_gtk_css_provider; #if GTK_MAJOR_VERSION == 4 static const char *ui_gtk_css = "#path-textfield-box {\n" " background-color: alpha(currentColor, 0.1);" " border-radius: 6px;" " padding: 0px;" "}\n" ".pathbar-extra-button {\n" " border-top-right-radius: 6px;" " border-bottom-right-radius: 6px;" " border-top-left-radius: 0px;" " border-bottom-left-radius: 0px;" "}\n" "#pathbar button {\n" " margin: 3px;" " border-radius: 4px;" " padding-top: 0px;" " padding-bottom: 0px;" " padding-left: 8px;" " padding-right: 8px;" "}\n" "#path-textfield-box entry {\n" " background-color: #00000000;" " border-top-left-radius: 6px;" " border-bottom-left-radius: 6px;" " border-top-right-radius: 0px;" " border-bottom-right-radius: 0px;" "}\n" ".pathbar-button-inactive {\n" " color: alpha(currentColor, 0.5);" "}\n" ".ui_test {\n" " background-color: red;\n" "}\n" ".ui_label_title {\n" " font-weight: bold;\n" "}\n" ; #elif GTK_MAJOR_VERSION == 3 static const char *ui_gtk_css = "#path-textfield-box {\n" " background-color: @theme_base_color;\n" " border-radius: 5px;\n" " padding: 0px;\n" "}\n" ".pathbar-button-inactive {\n" " color: alpha(currentColor, 0.5);" "}\n" ".ui_test {\n" " background-color: red;\n" "}\n" ".ui_label_title {\n" " font-weight: bold;\n" "}\n" ; #endif void ui_css_init(void) { ui_gtk_css_provider = gtk_css_provider_new(); #ifdef UI_GTK3 gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1, NULL); GdkScreen *screen = gdk_screen_get_default(); gtk_style_context_add_provider_for_screen( screen, GTK_STYLE_PROVIDER(ui_gtk_css_provider), GTK_STYLE_PROVIDER_PRIORITY_USER); #endif /* UI_GTK3 */ #ifdef UI_GTK4 #if GTK_MINOR_VERSION < 12 gtk_css_provider_load_from_data(ui_gtk_css_provider, ui_gtk_css, -1); #else gtk_css_provider_load_from_string(ui_gtk_css_provider, ui_gtk_css); #endif /* GTK_MINOR_VERSION < 12 */ GdkDisplay *display = gdk_display_get_default(); gtk_style_context_add_provider_for_display(display, GTK_STYLE_PROVIDER(ui_gtk_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); #endif /* UI_GTK4 */ } #endif void ui_set_name_and_style(GtkWidget *widget, const char *name, const char *style_classes) { if(name) { gtk_widget_set_name(widget, name); } if(style_classes) { cxstring *cls = NULL; size_t numClasses = cx_strsplit_a(cxDefaultAllocator, cx_str(style_classes), CX_STR(" "), 128, &cls); for(int i=0;i<numClasses;i++) { cxmutstr m = cx_strdup(cls[i]); #if GTK_MAJOR_VERSION >= 4 gtk_widget_add_css_class(widget, m.ptr); #elif GTK_MAJOR_VERSION >= 3 GtkStyleContext *ctx = gtk_widget_get_style_context(widget); gtk_style_context_add_class(ctx, m.ptr); #endif free(m.ptr); } free(cls); } } void ui_set_widget_groups(UiContext *ctx, GtkWidget *widget, const int *groups) { if(!groups) { return; } size_t ngroups = uic_group_array_size(groups); ui_set_widget_ngroups(ctx, widget, groups, ngroups); } void ui_set_widget_ngroups(UiContext *ctx, GtkWidget *widget, const int *groups, size_t ngroups) { if(ngroups > 0) { uic_add_group_widget_i(ctx, widget, (ui_enablefunc)ui_set_enabled, groups, ngroups); ui_set_enabled(widget, FALSE); } }