# HG changeset patch # User Olaf Wintermann # Date 1731419883 -3600 # Node ID 958bae3722711d5e62f608c225afabb25061c47d # Parent d41b1ffc5f77d2582fa9fbb7821f855d2ed549dd implement ui_dialog_window (WINUI) diff -r d41b1ffc5f77 -r 958bae372271 make/vs/testapp/main.c --- a/make/vs/testapp/main.c Sun Nov 10 15:27:44 2024 +0100 +++ b/make/vs/testapp/main.c Tue Nov 12 14:58:03 2024 +0100 @@ -121,7 +121,7 @@ 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, .default_button = 4, .show_closebutton = UI_OFF); + UiObject *dialog = ui_dialog_window(event->obj, .title = "Dialog Window", .lbutton1 = "Cancel 1", .lbutton2 = "Btn 2", .rbutton3 = "Btn3", .rbutton4 = "Login 4", .onclick = action_dialog_button, .default_button = 4, .show_closebutton = UI_OFF); ui_vbox(dialog, .margin = 10, .spacing = 10) { ui_label(dialog, .label = "Enter password:"); diff -r d41b1ffc5f77 -r 958bae372271 make/vs/toolkit.sln --- a/make/vs/toolkit.sln Sun Nov 10 15:27:44 2024 +0100 +++ b/make/vs/toolkit.sln Tue Nov 12 14:58:03 2024 +0100 @@ -9,8 +9,6 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winui", "..\..\ui\winui\winui.vcxproj", "{59F97886-BF49-4B3F-9EF6-FA7A84F3AB56}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uicommon", "uicommon\uicommon.vcxproj", "{8B88698E-C185-4383-99FE-0C34D6DEED2E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -63,18 +61,6 @@ {59F97886-BF49-4B3F-9EF6-FA7A84F3AB56}.Release|x86.ActiveCfg = Release|Win32 {59F97886-BF49-4B3F-9EF6-FA7A84F3AB56}.Release|x86.Build.0 = Release|Win32 {59F97886-BF49-4B3F-9EF6-FA7A84F3AB56}.Release|x86.Deploy.0 = Release|Win32 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Debug|ARM64.ActiveCfg = Debug|x64 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Debug|ARM64.Build.0 = Debug|x64 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Debug|x64.ActiveCfg = Debug|x64 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Debug|x64.Build.0 = Debug|x64 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Debug|x86.ActiveCfg = Debug|Win32 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Debug|x86.Build.0 = Debug|Win32 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Release|ARM64.ActiveCfg = Release|x64 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Release|ARM64.Build.0 = Release|x64 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Release|x64.ActiveCfg = Release|x64 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Release|x64.Build.0 = Release|x64 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Release|x86.ActiveCfg = Release|Win32 - {8B88698E-C185-4383-99FE-0C34D6DEED2E}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff -r d41b1ffc5f77 -r 958bae372271 ui/common/context.c --- a/ui/common/context.c Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/common/context.c Tue Nov 12 14:58:03 2024 +0100 @@ -41,6 +41,7 @@ #include "document.h" #include "types.h" + static UiContext* global_context; void uic_init_global_context(void) { diff -r d41b1ffc5f77 -r 958bae372271 ui/common/document.c --- a/ui/common/document.c Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/common/document.c Tue Nov 12 14:58:03 2024 +0100 @@ -35,6 +35,7 @@ #include #include + static CxMap *documents; void uic_docmgr_init() { diff -r d41b1ffc5f77 -r 958bae372271 ui/common/menu.c --- a/ui/common/menu.c Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/common/menu.c Tue Nov 12 14:58:03 2024 +0100 @@ -34,6 +34,7 @@ #include #include + static UiMenu *menus_begin; static UiMenu *menus_end; static CxList *current; diff -r d41b1ffc5f77 -r 958bae372271 ui/common/properties.c --- a/ui/common/properties.c Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/common/properties.c Tue Nov 12 14:58:03 2024 +0100 @@ -39,6 +39,7 @@ #include #include +#include #include "ucx_properties.h" static CxMap *application_properties; @@ -60,6 +61,14 @@ return ui_configfile(NULL); } +#ifndef _WIN32 +#define UI_PATH_SEPARATOR '/' +#define UI_ENV_HOME "HOME" +#else +#define UI_PATH_SEPARATOR '\\' +#define UI_ENV_HOME "USERPROFILE" +#endif + char* ui_configfile(char *name) { const char *appname = ui_appname(); if(!appname) { @@ -70,7 +79,7 @@ cxBufferInit(&buf, NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); // add base dir - char *homeenv = getenv("HOME"); + char *homeenv = getenv(UI_ENV_HOME); if(homeenv == NULL) { cxBufferDestroy(&buf); return NULL; @@ -78,19 +87,22 @@ cxstring home = cx_str(homeenv); cxBufferWrite(home.ptr, 1, home.length, &buf); - if(home.ptr[home.length-1] != '/') { - cxBufferPut(&buf, '/'); + if(home.ptr[home.length-1] != UI_PATH_SEPARATOR) { + cxBufferPut(&buf, UI_PATH_SEPARATOR); } #ifdef UI_COCOA // on OS X the app dir is $HOME/Library/Application Support/$APPNAME/ - ucx_buffer_puts(buf, "Library/Application Support/"); + cxBufferPutString(&buf, "Library/Application Support/"); +#elif defined(_WIN32) + // on Windows the app dir is $USERPROFILE/AppData/Local/$APPNAME/ + cxBufferPutString(&buf, "AppData\\Local\\"); #else // app dir is $HOME/.$APPNAME/ cxBufferPut(&buf, '.'); #endif cxBufferPutString(&buf, appname); - cxBufferPut(&buf, '/'); + cxBufferPut(&buf, UI_PATH_SEPARATOR); // add file name if(name) { diff -r d41b1ffc5f77 -r 958bae372271 ui/gtk/text.c --- a/ui/gtk/text.c Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/gtk/text.c Tue Nov 12 14:58:03 2024 +0100 @@ -78,9 +78,12 @@ NULL); UiTextArea *uitext = malloc(sizeof(UiTextArea)); + uitext->obj = obj; uitext->ctx = obj->ctx; uitext->var = var; uitext->last_selection_state = 0; + uitext->onchange = args.onchange; + uitext->onchangedata = args.onchangedata; g_signal_connect( text_area, @@ -266,13 +269,19 @@ void ui_textbuf_changed(GtkTextBuffer *textbuffer, UiTextArea *textarea) { UiText *value = textarea->var->value; + + UiEvent e; + e.obj = textarea->obj; + e.window = e.obj->window; + e.document = textarea->ctx->document; + e.eventdata = value; + e.intval = 0; + + if(textarea->onchange) { + textarea->onchange(&e, textarea->onchangedata); + } + if(value->observers) { - UiEvent e; - e.obj = textarea->ctx->obj; - e.window = e.obj->window; - e.document = textarea->ctx->document; - e.eventdata = value; - e.intval = 0; ui_notify_evt(value->observers, &e); } } diff -r d41b1ffc5f77 -r 958bae372271 ui/gtk/text.h --- a/ui/gtk/text.h Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/gtk/text.h Tue Nov 12 14:58:03 2024 +0100 @@ -61,9 +61,12 @@ } UiUndoMgr; typedef struct UiTextArea { - UiContext *ctx; - UiVar *var; - int last_selection_state; + UiObject *obj; + UiContext *ctx; + UiVar *var; + int last_selection_state; + ui_callback onchange; + void *onchangedata; } UiTextArea; typedef struct UiTextField { diff -r d41b1ffc5f77 -r 958bae372271 ui/ui/properties.h --- a/ui/ui/properties.h Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/ui/properties.h Tue Nov 12 14:58:03 2024 +0100 @@ -35,8 +35,6 @@ extern "C" { #endif -typedef struct CxMap UiProperties; - char* ui_get_property(char *name); void ui_set_property(char *name, char *value); diff -r d41b1ffc5f77 -r 958bae372271 ui/ui/toolkit.h --- a/ui/ui/toolkit.h Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/ui/toolkit.h Tue Nov 12 14:58:03 2024 +0100 @@ -84,6 +84,7 @@ #ifdef __cplusplus +#include #ifndef UI_WINUI_PCH #include #undef GetCurrentTime @@ -105,6 +106,7 @@ void* data1 = nullptr; void* data2 = nullptr; void* data3 = nullptr; + std::function Show; UiWidget(winrt::Microsoft::UI::Xaml::UIElement& elm); }; diff -r d41b1ffc5f77 -r 958bae372271 ui/winui/button.cpp --- a/ui/winui/button.cpp Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/winui/button.cpp Tue Nov 12 14:58:03 2024 +0100 @@ -46,7 +46,7 @@ -static void set_button_label(ButtonBase button, const char* label, const char* stockid, const char *icon, UiLabelType type) { +void ui_set_button_label(ButtonBase button, const char* label, const char* stockid, const char *icon, UiLabelType type) { // TODO: stockid if (type == UI_LABEL_ICON) { @@ -92,7 +92,7 @@ // create button with label Button button = Button(); - set_button_label(button, args.label, args.stockid, args.icon, args.labeltype); + ui_set_button_label(button, args.label, args.stockid, args.icon, args.labeltype); // create toolkit wrapper object and register destructor UIElement elm = button; @@ -180,7 +180,7 @@ UiObject* current = uic_current_obj(obj); // set label - set_button_label(button, args.label, args.stockid, args.icon, args.labeltype); + ui_set_button_label(button, args.label, args.stockid, args.icon, args.labeltype); togglebutton_register_callback(button, obj, args); // create toolkit wrapper object and register destructor @@ -267,7 +267,7 @@ UiObject* current = uic_current_obj(obj); // set label - set_button_label(button, args.label, args.stockid, args.icon, args.labeltype); + ui_set_button_label(button, args.label, args.stockid, args.icon, args.labeltype); togglebutton_register_callback(button, obj, args); // create toolkit wrapper object and register destructor diff -r d41b1ffc5f77 -r 958bae372271 ui/winui/button.h --- a/ui/winui/button.h Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/winui/button.h Tue Nov 12 14:58:03 2024 +0100 @@ -35,6 +35,7 @@ #include "../common/context.h" +void ui_set_button_label(winrt::Microsoft::UI::Xaml::Controls::Primitives::ButtonBase button, const char* label, const char* stockid, const char *icon, UiLabelType type); void togglebutton_register_checked_observers(winrt::Microsoft::UI::Xaml::Controls::Primitives::ToggleButton button, UiObject* obj, UiVar* var); void togglebutton_register_unchecked_observers(winrt::Microsoft::UI::Xaml::Controls::Primitives::ToggleButton button, UiObject* obj, UiVar* var); diff -r d41b1ffc5f77 -r 958bae372271 ui/winui/text.cpp --- a/ui/winui/text.cpp Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/winui/text.cpp Tue Nov 12 14:58:03 2024 +0100 @@ -56,7 +56,9 @@ UiObject* current = uic_current_obj(obj); // create textarea and toolkit wrapper - RichEditBox textarea = RichEditBox(); + TextBox textarea = TextBox(); + textarea.AcceptsReturn(true); + ScrollViewer::SetVerticalScrollBarVisibility(textarea, ScrollBarVisibility::Auto); UIElement elm = textarea; UiWidget* widget = new UiWidget(elm); ui_context_add_widget_destructor(current->ctx, widget); @@ -97,14 +99,46 @@ } +// -------------------------- getter/setter for textarea UiText -------------------------- +char* ui_wtext_get(UiText *text, std::wstring &value) { + if (text->value.ptr) { + text->value.free(text->value.ptr); + } + + text->value.ptr = wchar2utf8(value.c_str(), value.length()); + text->value.free = free; + + return text->value.ptr; +} + +std::wstring ui_wtext_set(UiText *text, const char* value) { + if (text->value.ptr) { + text->value.free(text->value.ptr); + } + + text->value.ptr = _strdup(value); + text->value.free = free; + + int len; + wchar_t* wstr = str2wstr(value, &len); + std::wstring s(wstr); + free(wstr); + + return s; +} extern "C" char* ui_textarea_get(UiText *text) { - return NULL; + UiWidget* widget = (UiWidget*)text->obj; + TextBox box = widget->uielement.as(); + std::wstring wstr(box.Text()); + return ui_wtext_get(text, wstr); } extern "C" void ui_textarea_set(UiText *text, const char *newvalue) { - + UiWidget* widget = (UiWidget*)text->obj; + TextBox box = widget->uielement.as(); + box.Text(ui_wtext_set(text, newvalue)); } extern "C" char* ui_textarea_getsubstr(UiText *text, int begin, int end) { diff -r d41b1ffc5f77 -r 958bae372271 ui/winui/text.h --- a/ui/winui/text.h Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/winui/text.h Tue Nov 12 14:58:03 2024 +0100 @@ -60,6 +60,9 @@ void* ondropdata; }; +char* ui_wtext_get(UiText *text, std::wstring &value); +std::wstring ui_wtext_set(UiText *text, const char* value); + char* ui_wstring_get(UiString* str, std::wstring& value); std::wstring ui_wstring_set(UiString* str, const char* value); diff -r d41b1ffc5f77 -r 958bae372271 ui/winui/toolkit.cpp --- a/ui/winui/toolkit.cpp Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/winui/toolkit.cpp Tue Nov 12 14:58:03 2024 +0100 @@ -36,6 +36,7 @@ #include "../common/context.h" #include "../common/document.h" #include "../common/toolbar.h" +#include "../common/properties.h" #include "icons.h" @@ -166,6 +167,8 @@ uic_init_global_context(); uic_docmgr_init(); uic_toolbar_init(); + + uic_load_app_properties(); } const char* ui_appname() { @@ -229,8 +232,8 @@ void ui_show(UiObject* obj) { if (obj->wobj) { obj->wobj->window.Activate(); - } else { - // TODO + } else if(obj->widget && obj->widget->Show) { + obj->widget->Show(); } } diff -r d41b1ffc5f77 -r 958bae372271 ui/winui/window.cpp --- a/ui/winui/window.cpp Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/winui/window.cpp Tue Nov 12 14:58:03 2024 +0100 @@ -35,6 +35,7 @@ #include "commandbar.h" #include "container.h" #include "util.h" +#include "button.h" #include "../common/context.h" #include "../common/object.h" @@ -201,8 +202,168 @@ return obj; } +static void dialog_button_add_callback(ContentDialog dialog, Button button, int num, UiObject *obj, ui_callback onclick, void *onclickdata) { + button.Click([dialog, num, obj, onclick, onclickdata](IInspectable const& sender, RoutedEventArgs) { + if (onclick) { + UiEvent evt; + evt.obj = obj; + evt.window = obj->window; + evt.document = obj->ctx->document; + evt.eventdata = nullptr; + evt.intval = num; + onclick(&evt, onclickdata); + } + dialog.Hide(); + }); +} + UIEXPORT UiObject* ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs args) { - return NULL; + UiWindow *window = parent->wobj; + if (!window) { + return NULL; + } + + CxMempool* mp = cxBasicMempoolCreate(256); + UiObject* obj = (UiObject*)cxCalloc(mp->allocator, 1, sizeof(UiObject)); + + obj->ctx = uic_context(obj, mp); + + ContentDialog dialog = ContentDialog(); + UIElement elm = dialog; + UiWidget* widget = new UiWidget(elm); + ui_context_add_widget_destructor(obj->ctx, widget); + obj->widget = widget; + + if (args.title) { + wchar_t* wtitle = str2wstr(args.title, nullptr); + dialog.Title(box_value(wtitle)); + free(wtitle); + } + + + Grid dialogContent = Grid(); + GridLength gl; + + // content row + gl.Value = 1; + gl.GridUnitType = GridUnitType::Star; + RowDefinition rowdef0 = RowDefinition(); + rowdef0.Height(gl); + dialogContent.RowDefinitions().Append(rowdef0); + + // button row + gl.Value = 0; + gl.GridUnitType = GridUnitType::Auto; + RowDefinition rowdef1 = RowDefinition(); + rowdef1.Height(gl); + dialogContent.RowDefinitions().Append(rowdef1); + + // coldef + gl.Value = 1; + gl.GridUnitType = GridUnitType::Star; + ColumnDefinition coldef = ColumnDefinition(); + coldef.Width(gl); + dialogContent.ColumnDefinitions().Append(coldef); + + // content + Grid grid = Grid(); + grid.SetRow(grid, 0); + grid.SetColumn(grid, 0); + dialogContent.Children().Append(grid); + obj->container = new UiBoxContainer(grid, UI_BOX_CONTAINER_VBOX, 0, 0); + + // buttons + Grid buttons = Grid(); + Thickness btnsMargin = { (double)0, (double)10, (double)0, (double)0 }; + buttons.Margin(btnsMargin); + + RowDefinition btnrowdef = RowDefinition(); + gl.Value = 0; + gl.GridUnitType = GridUnitType::Auto; + btnrowdef.Height(gl); + buttons.RowDefinitions().Append(btnrowdef); + + gl.Value = 1; + gl.GridUnitType = GridUnitType::Auto; + int c = 0; + if (args.lbutton1) { + ColumnDefinition bcoldef = ColumnDefinition(); + bcoldef.Width(gl); + buttons.ColumnDefinitions().Append(bcoldef); + + Button btn = Button(); + ui_set_button_label(btn, args.lbutton1, NULL, NULL, UI_LABEL_TEXT); + Thickness margin = { (double)5, (double)5, (double)5, (double)5 }; + btn.Margin(margin); + btn.HorizontalAlignment(HorizontalAlignment::Stretch); + dialog_button_add_callback(dialog, btn, 1, obj, args.onclick, args.onclickdata); + + buttons.SetRow(btn, 0); + buttons.SetColumn(btn, c++); + buttons.Children().Append(btn); + } + if (args.lbutton2) { + ColumnDefinition bcoldef = ColumnDefinition(); + bcoldef.Width(gl); + buttons.ColumnDefinitions().Append(bcoldef); + + Button btn = Button(); + ui_set_button_label(btn, args.lbutton2, NULL, NULL, UI_LABEL_TEXT); + Thickness margin = { (double)5, (double)5, (double)5, (double)5 }; + btn.Margin(margin); + btn.HorizontalAlignment(HorizontalAlignment::Stretch); + dialog_button_add_callback(dialog, btn, 2, obj, args.onclick, args.onclickdata); + + buttons.SetRow(btn, 0); + buttons.SetColumn(btn, c++); + buttons.Children().Append(btn); + } + if (args.rbutton3) { + ColumnDefinition bcoldef = ColumnDefinition(); + bcoldef.Width(gl); + buttons.ColumnDefinitions().Append(bcoldef); + + Button btn = Button(); + ui_set_button_label(btn, args.rbutton3, NULL, NULL, UI_LABEL_TEXT); + Thickness margin = { (double)5, (double)5, (double)5, (double)5 }; + btn.Margin(margin); + btn.HorizontalAlignment(HorizontalAlignment::Stretch); + dialog_button_add_callback(dialog, btn, 3, obj, args.onclick, args.onclickdata); + + buttons.SetRow(btn, 0); + buttons.SetColumn(btn, c++); + buttons.Children().Append(btn); + } + if (args.rbutton4) { + ColumnDefinition bcoldef = ColumnDefinition(); + bcoldef.Width(gl); + buttons.ColumnDefinitions().Append(bcoldef); + + Button btn = Button(); + ui_set_button_label(btn, args.rbutton4, NULL, NULL, UI_LABEL_TEXT); + Thickness margin = { (double)5, (double)5, (double)5, (double)5 }; + btn.Margin(margin); + btn.HorizontalAlignment(HorizontalAlignment::Stretch); + dialog_button_add_callback(dialog, btn, 4, obj, args.onclick, args.onclickdata); + + buttons.SetRow(btn, 0); + buttons.SetColumn(btn, c++); + buttons.Children().Append(btn); + } + + dialogContent.SetRow(buttons, 1); + dialogContent.SetColumn(buttons, 0); + dialogContent.Children().Append(buttons); + + + dialog.Content(dialogContent); + dialog.XamlRoot(window->window.Content().XamlRoot()); + + obj->widget->Show = [dialog]() { + dialog.ShowAsync(); + }; + + return obj; } void ui_window_size(UiObject *obj, int width, int height) { diff -r d41b1ffc5f77 -r 958bae372271 ui/winui/winui.vcxproj --- a/ui/winui/winui.vcxproj Sun Nov 10 15:27:44 2024 +0100 +++ b/ui/winui/winui.vcxproj Tue Nov 12 14:58:03 2024 +0100 @@ -88,8 +88,9 @@ - _DEBUG;DISABLE_XAML_GENERATED_MAIN__;UI_WINUI;UI_WINUI_PCH;%(PreprocessorDefinitions) + _DEBUG;DISABLE_XAML_GENERATED_MAIN__;UI_WINUI;UI_WINUI_PCH;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) $(SolutionDir)..\..\ucx;%(AdditionalIncludeDirectories) + stdc17 shell32.lib;gdi32.lib;%(AdditionalDependencies) @@ -113,6 +114,14 @@ + + + + + + + + @@ -160,6 +169,30 @@ + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + @@ -226,9 +259,6 @@ {27da0164-3475-43e2-a1a4-a5d07d305749} - - {8b88698e-c185-4383-99fe-0c34d6deed2e} -