# HG changeset patch # User Olaf Wintermann # Date 1729687938 -7200 # Node ID 870dd3d41d83bae69f62ff62c3232867a091df9e # Parent 54f5d7eb1335082669cbddcacd75c6e70d9edcca add dialog window (GTK) diff -r 54f5d7eb1335 -r 870dd3d41d83 application/main.c --- a/application/main.c Tue Oct 22 21:17:01 2024 +0200 +++ b/application/main.c Wed Oct 23 14:52:18 2024 +0200 @@ -79,6 +79,22 @@ ui_dialog(event->obj, .title = "Dialog Title", .content = "Content Label", .button1_label = "btn1", .button2_label = "btn2", .input = TRUE, .closebutton_label = "Cancel"); } +void action_dialog_button(UiEvent *event, void *userdata) { + ui_close(event->obj); +} + +void action_toolbar_dialog(UiEvent *event, void *userdata) { + + UiObject *dialog = ui_dialog_window(event->obj, .title = "Dialog Window", .lbutton1 = "Cancel 1", .lbutton2 = "Btn2", .rbutton3 = "Btn3", .rbutton4 = "Login 4", .onclick = action_dialog_button, .show_closebutton = UI_OFF); + + ui_vbox(dialog, .margin = 10, .spacing = 10) { + ui_label(dialog, .label = "Enter password:"); + ui_passwordfield(dialog, .varname = "password"); + } + + ui_show(dialog); +} + void action_toolbar_newwindow(UiEvent *event, void *userdata) { UiObject *obj = ui_simple_window("New Window", NULL); @@ -236,7 +252,12 @@ } } ui_tab(obj, "Tab 2") { - ui_button(obj, .label = "Button", .onclick=action_tab2_button); + ui_button(obj, .label = "Button 1", .onclick=action_tab2_button); + ui_button(obj, .label = "Button 2", .onclick=action_tab2_button); + ui_button(obj, .label = "Button 3", .onclick=action_tab2_button); + ui_button(obj, .label = "Button 4", .onclick=action_tab2_button); + ui_button(obj, .label = "Button 5", .onclick=action_tab2_button); + ui_button(obj, .label = "Button 6", .onclick=action_tab2_button); } ui_tab(obj, "Tab 3") { UiTabViewArgs args = {0}; @@ -276,7 +297,7 @@ ui_toolbar_item("Test", .label = "Test", .onclick = action_toolbar_button); ui_toolbar_item("Test2", .label = "New Window", .onclick = action_toolbar_newwindow); - ui_toolbar_item("Test3", .label = "Test 3", .onclick = action_toolbar_button); + ui_toolbar_item("Test3", .label = "Dialog", .onclick = action_toolbar_dialog); ui_toolbar_item("Test4", .label = "Test 4", .onclick = action_toolbar_button); ui_toolbar_item("Test5", .label = "Test 5", .onclick = action_toolbar_button); ui_toolbar_item("Test6", .label = "Test 6", .onclick = action_toolbar_button); diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/gtk/button.c --- a/ui/gtk/button.c Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/gtk/button.c Wed Oct 23 14:52:18 2024 +0200 @@ -59,7 +59,8 @@ const char *label, const char *icon, ui_callback onclick, - void *userdata) + void *userdata, + int event_value) { GtkWidget *button = gtk_button_new_with_label(label); ui_button_set_icon_name(button, icon); @@ -69,7 +70,7 @@ event->obj = obj; event->userdata = userdata; event->callback = onclick; - event->value = 0; + event->value = event_value; event->customdata = NULL; g_signal_connect( @@ -89,7 +90,7 @@ UIWIDGET ui_button_create(UiObject *obj, UiButtonArgs args) { UiObject* current = uic_current_obj(obj); - GtkWidget *button = ui_create_button(obj, args.label, args.icon, args.onclick, args.onclickdata); + GtkWidget *button = ui_create_button(obj, args.label, args.icon, args.onclick, args.onclickdata, 0); ui_set_name_and_style(button, args.name, args.style_class); ui_set_widget_groups(obj->ctx, button, args.groups); UI_APPLY_LAYOUT1(current, args); diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/gtk/button.h --- a/ui/gtk/button.h Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/gtk/button.h Wed Oct 23 14:52:18 2024 +0200 @@ -46,7 +46,8 @@ const char *label, const char *icon, ui_callback onclick, - void *userdata); + void *userdata, + int event_value); void ui_setup_togglebutton( UiObject *obj, diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/gtk/container.c --- a/ui/gtk/container.c Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/gtk/container.c Wed Oct 23 14:52:18 2024 +0200 @@ -242,7 +242,7 @@ -static GtkWidget* box_set_margin(GtkWidget *box, int margin) { +GtkWidget* ui_box_set_margin(GtkWidget *box, int margin) { GtkWidget *ret = box; #if GTK_MAJOR_VERSION >= 3 #if GTK_MAJOR_VERSION * 1000 + GTK_MINOR_VERSION >= 3012 @@ -270,7 +270,7 @@ GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing); ui_set_name_and_style(box, args.name, args.style_class); - GtkWidget *widget = args.margin > 0 ? box_set_margin(box, args.margin) : box; + GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box; ct->add(ct, widget, TRUE); UiObject *newobj = uic_object_new(obj, box); @@ -288,7 +288,7 @@ return ui_box_create(obj, args, UI_CONTAINER_HBOX); } -static GtkWidget* create_grid(int colspacing, int rowspacing) { +GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing) { #if GTK_MAJOR_VERSION >= 3 GtkWidget *grid = gtk_grid_new(); gtk_grid_set_column_spacing(GTK_GRID(grid), colspacing); @@ -306,9 +306,9 @@ UI_APPLY_LAYOUT1(current, args); GtkWidget *widget; - GtkWidget *grid = create_grid(args.columnspacing, args.rowspacing); + GtkWidget *grid = ui_create_grid_widget(args.columnspacing, args.rowspacing); ui_set_name_and_style(grid, args.name, args.style_class); - widget = box_set_margin(grid, args.margin); + widget = ui_box_set_margin(grid, args.margin); current->container->add(current->container, widget, TRUE); UiObject *newobj = uic_object_new(obj, grid); @@ -621,13 +621,13 @@ break; } case UI_CONTAINER_GRID: { - sub = create_grid(data->columnspacing, data->rowspacing); + sub = ui_create_grid_widget(data->columnspacing, data->rowspacing); newobj->container = ui_grid_container(newobj, sub); break; } } newobj->widget = sub; - GtkWidget *widget = box_set_margin(sub, data->margin); + GtkWidget *widget = ui_box_set_margin(sub, data->margin); data->add_tab(data->widget, tab_index, name, widget); diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/gtk/container.h --- a/ui/gtk/container.h Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/gtk/container.h Wed Oct 23 14:52:18 2024 +0200 @@ -137,11 +137,13 @@ UiContainer* ui_frame_container(UiObject *obj, GtkWidget *frame); void ui_frame_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill); +GtkWidget* ui_box_set_margin(GtkWidget *box, int margin); UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type); UiContainer* ui_box_container(UiObject *obj, GtkWidget *box, UiSubContainerType type); void ui_box_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill); +GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing); UiContainer* ui_grid_container(UiObject *obj, GtkWidget *grid); void ui_grid_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill); diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/gtk/headerbar.c --- a/ui/gtk/headerbar.c Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/gtk/headerbar.c Wed Oct 23 14:52:18 2024 +0200 @@ -114,7 +114,7 @@ UiObject *obj, enum UiToolbarPos pos) { - GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.onclick, item->args.onclickdata); + GtkWidget *button = ui_create_button(obj, item->args.label, item->args.icon, item->args.onclick, item->args.onclickdata, 0); WIDGET_ADD_CSS_CLASS(button, "flat"); headerbar_add(headerbar, box, button, pos); } diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/gtk/toolkit.c --- a/ui/gtk/toolkit.c Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/gtk/toolkit.c Wed Oct 23 14:52:18 2024 +0200 @@ -166,8 +166,11 @@ } void ui_close(UiObject *obj) { - // TODO - //gtk_widget_destroy(obj->widget); +#if GTK_CHECK_VERSION(4, 0, 0) + gtk_window_close(GTK_WINDOW(obj->widget)); +#else + gtk_widget_destroy(obj->widget); +#endif } @@ -345,6 +348,9 @@ ".pathbar-button-inactive {\n" " color: alpha(currentColor, 0.5);" "}\n" +".ui_test {\n" +" background-color: red;\n" +"}\n" ; #elif GTK_MAJOR_VERSION == 3 diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/gtk/toolkit.h --- a/ui/gtk/toolkit.h Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/gtk/toolkit.h Wed Oct 23 14:52:18 2024 +0200 @@ -59,7 +59,7 @@ #define WINDOW_DESTROY(window) gtk_window_destroy(GTK_WINDOW(window)) #define WINDOW_SET_CONTENT(window, child) gtk_window_set_child(GTK_WINDOW(window), child) #define BOX_ADD(box, child) gtk_box_append(GTK_BOX(box), child) -#define BOX_ADD_EXPAND(box, child) gtk_widget_set_hexpand(child, TRUE); gtk_box_append(GTK_BOX(box), child) +#define BOX_ADD_EXPAND(box, child) gtk_widget_set_hexpand(child, TRUE); gtk_widget_set_vexpand(child, TRUE); gtk_box_append(GTK_BOX(box), child) #define BOX_ADD_NO_EXPAND(box, child) gtk_box_append(GTK_BOX(box), child) #define ENTRY_SET_TEXT(entry, text) gtk_editable_set_text(GTK_EDITABLE(entry), text) #define ENTRY_GET_TEXT(entry) gtk_editable_get_text(GTK_EDITABLE(entry)) @@ -73,8 +73,8 @@ #define WINDOW_DESTROY(window) gtk_widget_destroy(window) #define WINDOW_SET_CONTENT(window, child) gtk_container_add(GTK_CONTAINER(window), child) #define BOX_ADD(box, child) gtk_container_add(GTK_CONTAINER(box), child) -#define BOX_ADD_EXPAND(box, child) gtk_box_pack_end(GTK_BOX(box), child, TRUE, TRUE, 0) -#define BOX_ADD_NO_EXPAND(box, child) gtk_box_pack_end(GTK_BOX(box), child, TRUE, FALSE, 0) +#define BOX_ADD_EXPAND(box, child) gtk_box_pack_start(GTK_BOX(box), child, TRUE, TRUE, 0) +#define BOX_ADD_NO_EXPAND(box, child) gtk_box_pack_start(GTK_BOX(box), child, TRUE, FALSE, 0) #define ENTRY_SET_TEXT(entry, text) gtk_entry_set_text(GTK_ENTRY(entry), text) #define ENTRY_GET_TEXT(entry) gtk_entry_get_text(GTK_ENTRY(entry)) #define SCROLLEDWINDOW_NEW() gtk_scrolled_window_new(NULL, NULL) diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/gtk/window.c --- a/ui/gtk/window.c Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/gtk/window.c Wed Oct 23 14:52:18 2024 +0200 @@ -42,6 +42,7 @@ #include "toolbar.h" #include "container.h" #include "headerbar.h" +#include "button.h" static int nwindows = 0; @@ -586,3 +587,145 @@ ui_gtkfilechooser(obj, GTK_FILE_CHOOSER_ACTION_SAVE, 0, name, file_selected_callback, cbdata); } +#if GTK_CHECK_VERSION(4, 10, 0) +#define DIALOG_NEW() gtk_window_new() +#else +#define DIALOG_NEW() gtk_dialog_new() + +static void ui_dialogwindow_response(GtkDialog* self, gint response_id, gpointer user_data) { + UiEventData *event = user_data; + // TODO: do we need to check if response_id == GTK_RESPONSE_DELETE_EVENT? + if(event->callback) { + UiEvent e; + e.obj = event->obj; + e.window = event->obj->window; + e.document = event->obj->ctx->document; + e.eventdata = NULL; + e.intval = event->value; + event->callback(&e, event->userdata); + } +} + +#endif + +#if GTK_CHECK_VERSION(4, 0, 0) +#define HEADERBAR_SHOW_CLOSEBUTTON(headerbar, set) gtk_header_bar_set_show_title_buttons(GTK_HEADER_BAR(headerbar), set) +#else +#define HEADERBAR_SHOW_CLOSEBUTTON(headerbar, set) gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(headerbar), set) +#endif + + + +UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) { + GtkWidget *dialog = DIALOG_NEW(); + gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent->widget)); + if(args.modal != UI_OFF) { + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + } + + CxMempool *mp = cxBasicMempoolCreate(256); + UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject)); + obj->ctx = uic_context(obj, mp); + obj->widget = dialog; + nwindows++; + + if(args.title != NULL) { + gtk_window_set_title(GTK_WINDOW(dialog), args.title); + } + +#if ! GTK_CHECK_VERSION(4, 10, 0) + UiEventData *event = malloc(sizeof(UiEventData)); + event->obj = obj; + event->userdata = args.onclickdata; + event->callback = args.onclick; + event->value = 0; + event->customdata = NULL; + + g_signal_connect(dialog, "response", G_CALLBACK(ui_dialogwindow_response), event); + g_signal_connect( + dialog, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); +#endif + + g_signal_connect( + dialog, + "destroy", + G_CALLBACK(ui_exit_event), + obj); + +#if GTK_MAJOR_VERSION < 4 + GtkWidget *c = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_container_remove(GTK_CONTAINER(dialog), c); +#endif + + GtkWidget *content_vbox = ui_gtk_vbox_new(0); + obj->container = ui_box_container(obj, content_vbox, UI_CONTAINER_VBOX); + if(args.lbutton1 || args.lbutton2 || args.rbutton3 || args.rbutton4) { +#if GTK_CHECK_VERSION(3, 10, 0) + if(args.titlebar_buttons != UI_OFF) { + GtkWidget *headerbar = gtk_header_bar_new(); + gtk_window_set_titlebar(GTK_WINDOW(dialog), headerbar); + if(args.show_closebutton == UI_OFF) { + HEADERBAR_SHOW_CLOSEBUTTON(headerbar, FALSE); + } + + if(args.lbutton1) { + GtkWidget *button = ui_create_button(obj, args.lbutton1, NULL, args.onclick, args.onclickdata, 1); + gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button); + } + if(args.lbutton2) { + GtkWidget *button = ui_create_button(obj, args.lbutton2, NULL, args.onclick, args.onclickdata, 2); + gtk_header_bar_pack_start(GTK_HEADER_BAR(headerbar), button); + } + + if(args.rbutton4) { + GtkWidget *button = ui_create_button(obj, args.rbutton4, NULL, args.onclick, args.onclickdata, 4); + gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button); + } + if(args.rbutton3) { + GtkWidget *button = ui_create_button(obj, args.rbutton3, NULL, args.onclick, args.onclickdata, 3); + gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), button); + } + return obj; + } +#endif + GtkWidget *vbox = ui_gtk_vbox_new(0); + WINDOW_SET_CONTENT(obj->widget, vbox); + + GtkWidget *separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); + + GtkWidget *grid = ui_create_grid_widget(10, 10); + GtkWidget *widget = ui_box_set_margin(grid, 16); + gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE); + + if(args.lbutton1) { + GtkWidget *button = ui_create_button(obj, args.lbutton1, NULL, args.onclick, args.onclickdata, 1); + gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1); + } + if(args.lbutton2) { + GtkWidget *button = ui_create_button(obj, args.lbutton2, NULL, args.onclick, args.onclickdata, 2); + gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1); + } + GtkWidget *space = gtk_label_new(NULL); + gtk_widget_set_hexpand(space, TRUE); + gtk_grid_attach(GTK_GRID(grid), space, 2, 0, 1, 1); + if(args.rbutton3) { + GtkWidget *button = ui_create_button(obj, args.rbutton3, NULL, args.onclick, args.onclickdata, 3); + gtk_grid_attach(GTK_GRID(grid), button, 3, 0, 1, 1); + } + if(args.rbutton3) { + GtkWidget *button = ui_create_button(obj, args.rbutton4, NULL, args.onclick, args.onclickdata, 4); + gtk_grid_attach(GTK_GRID(grid), button, 4, 0, 1, 1); + } + + BOX_ADD_EXPAND(vbox, content_vbox); + BOX_ADD_NO_EXPAND(vbox, separator); + BOX_ADD_NO_EXPAND(vbox, widget); + } else { + WINDOW_SET_CONTENT(obj->widget, content_vbox); + } + + return obj; +} diff -r 54f5d7eb1335 -r 870dd3d41d83 ui/ui/window.h --- a/ui/ui/window.h Tue Oct 22 21:17:01 2024 +0200 +++ b/ui/ui/window.h Wed Oct 23 14:52:18 2024 +0200 @@ -50,8 +50,32 @@ void *resultdata; } UiDialogArgs; +typedef struct UiDialogWindowArgs { + UiBool modal; + UiBool titlebar_buttons; + UiBool show_closebutton; + const char *title; + const char *lbutton1; + const char *lbutton2; + const char *rbutton3; + const char *rbutton4; + const int *lbutton1_groups; + const int *lbutton2_groups; + const int *rbutton3_groups; + const int *rbutton4_groups; + int default_button; + int width; + int height; + ui_callback onclick; + void *onclickdata; +} UiDialogWindowArgs; + UIEXPORT UiObject* ui_window(const char *title, void *window_data); UIEXPORT UiObject* ui_simple_window(const char *title, void *window_data); +UIEXPORT UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args); + +#define ui_dialog_window(parent, ...) ui_dialog_window_create(parent, (UiDialogWindowArgs){ __VA_ARGS__ }); +#define ui_dialog_window0(parent) ui_dialog_window_create(parent, (UiDialogWindowArgs){ 0 }); UIEXPORT void ui_window_size(UiObject *obj, int width, int height);