Tue, 07 Oct 2025 15:42:18 +0200
implement splitview window (Cocoa)
--- a/make/xcode/toolkit/toolkit.xcodeproj/project.pbxproj Tue Oct 07 14:59:11 2025 +0200 +++ b/make/xcode/toolkit/toolkit.xcodeproj/project.pbxproj Tue Oct 07 15:42:18 2025 +0200 @@ -46,6 +46,9 @@ ED65815F2CFF4BF200F5402F /* WindowManager.m in Sources */ = {isa = PBXBuildFile; fileRef = ED65815E2CFF4BF200F5402F /* WindowManager.m */; }; ED679B0A2E5B266C001D4F71 /* label.m in Sources */ = {isa = PBXBuildFile; fileRef = ED679B092E5B266C001D4F71 /* label.m */; }; ED679B0D2E5B2FB0001D4F71 /* UiThread.m in Sources */ = {isa = PBXBuildFile; fileRef = ED679B0C2E5B2FB0001D4F71 /* UiThread.m */; }; + ED6FB03D2E95466F006C6E8E /* args.c in Sources */ = {isa = PBXBuildFile; fileRef = ED6FB0382E95466F006C6E8E /* args.c */; }; + ED6FB03E2E95466F006C6E8E /* container.c in Sources */ = {isa = PBXBuildFile; fileRef = ED6FB03A2E95466F006C6E8E /* container.c */; }; + ED6FB03F2E95466F006C6E8E /* wrapper.c in Sources */ = {isa = PBXBuildFile; fileRef = ED6FB03C2E95466F006C6E8E /* wrapper.c */; }; ED83C2BF2E8EA49200054B22 /* BoxContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = ED83C2BE2E8EA49200054B22 /* BoxContainer.m */; }; ED8687E52D999CF3002F3EC2 /* menu.m in Sources */ = {isa = PBXBuildFile; fileRef = ED8687E42D999CF3002F3EC2 /* menu.m */; }; ED99F04A2E5CBD2E00A4CC97 /* widget.m in Sources */ = {isa = PBXBuildFile; fileRef = ED99F0492E5CBD2E00A4CC97 /* widget.m */; }; @@ -156,6 +159,12 @@ ED679B092E5B266C001D4F71 /* label.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = label.m; path = /Users/olaf/Projekte/toolkit/ui/cocoa/label.m; sourceTree = "<absolute>"; }; ED679B0B2E5B2FB0001D4F71 /* UiThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = UiThread.h; path = /Users/olaf/Projekte/toolkit/ui/cocoa/UiThread.h; sourceTree = "<absolute>"; }; ED679B0C2E5B2FB0001D4F71 /* UiThread.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = UiThread.m; path = /Users/olaf/Projekte/toolkit/ui/cocoa/UiThread.m; sourceTree = "<absolute>"; }; + ED6FB0372E95466F006C6E8E /* args.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = args.h; path = /Users/olaf/Projekte/toolkit/ui/common/args.h; sourceTree = "<absolute>"; }; + ED6FB0382E95466F006C6E8E /* args.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = args.c; path = /Users/olaf/Projekte/toolkit/ui/common/args.c; sourceTree = "<absolute>"; }; + ED6FB0392E95466F006C6E8E /* container.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = container.h; path = /Users/olaf/Projekte/toolkit/ui/common/container.h; sourceTree = "<absolute>"; }; + ED6FB03A2E95466F006C6E8E /* container.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = container.c; path = /Users/olaf/Projekte/toolkit/ui/common/container.c; sourceTree = "<absolute>"; }; + ED6FB03B2E95466F006C6E8E /* wrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = wrapper.h; path = /Users/olaf/Projekte/toolkit/ui/common/wrapper.h; sourceTree = "<absolute>"; }; + ED6FB03C2E95466F006C6E8E /* wrapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = wrapper.c; path = /Users/olaf/Projekte/toolkit/ui/common/wrapper.c; sourceTree = "<absolute>"; }; ED83C2BD2E8EA49200054B22 /* BoxContainer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BoxContainer.h; path = /Users/olaf/Projekte/toolkit/ui/cocoa/BoxContainer.h; sourceTree = "<absolute>"; }; ED83C2BE2E8EA49200054B22 /* BoxContainer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BoxContainer.m; path = /Users/olaf/Projekte/toolkit/ui/cocoa/BoxContainer.m; sourceTree = "<absolute>"; }; ED8687E32D999CF3002F3EC2 /* menu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = menu.h; path = ../../../ui/cocoa/menu.h; sourceTree = SOURCE_ROOT; }; @@ -216,6 +225,12 @@ ED6580D92CFF19DB00F5402F /* common */ = { isa = PBXGroup; children = ( + ED6FB0372E95466F006C6E8E /* args.h */, + ED6FB0382E95466F006C6E8E /* args.c */, + ED6FB0392E95466F006C6E8E /* container.h */, + ED6FB03A2E95466F006C6E8E /* container.c */, + ED6FB03B2E95466F006C6E8E /* wrapper.h */, + ED6FB03C2E95466F006C6E8E /* wrapper.c */, ED6580DA2CFF19F900F5402F /* condvar.h */, ED6580DB2CFF19F900F5402F /* condvar.c */, ED6580DC2CFF19F900F5402F /* context.h */, @@ -440,6 +455,9 @@ buildActionMask = 2147483647; files = ( ED679B0A2E5B266C001D4F71 /* label.m in Sources */, + ED6FB03D2E95466F006C6E8E /* args.c in Sources */, + ED6FB03E2E95466F006C6E8E /* container.c in Sources */, + ED6FB03F2E95466F006C6E8E /* wrapper.c in Sources */, ED6580EE2CFF19F900F5402F /* context.c in Sources */, ED6580EF2CFF19F900F5402F /* menu.c in Sources */, EDCD22352E59F3B1000612AF /* ListDataSource.m in Sources */,
--- a/make/xcode/toolkit/toolkit/main.m Tue Oct 07 14:59:11 2025 +0200 +++ b/make/xcode/toolkit/toolkit/main.m Tue Oct 07 15:42:18 2025 +0200 @@ -63,8 +63,9 @@ return doc; } +static int clickcount = 0; static void action_button(UiEvent *event, void *userdata) { - printf("button click\n"); + printf("button click %d\n", clickcount++); } static void toolbar_action(UiEvent *event, void *userdata) { @@ -94,113 +95,33 @@ return elm; } + + void application_startup(UiEvent *event, void *data) { - UiObject *obj = ui_window("My Window", NULL); + UiObject *obj = ui_splitview_window("My Window", TRUE); //WindowData *wdata = ui_malloc(obj->ctx, sizeof(WindowData)); //wdata->tbtoggle = ui_int_new(obj->ctx, "tbtoggle"); //obj->window = wdata; MyDocument *doc = create_doc(); ui_attach_document(obj->ctx, doc); - /* + ui_sidebar(obj) { - ui_button(obj, .label = "Sidebar Button"); - ui_textarea(obj, .varname = "todo: fix layout", .fill = TRUE); - } - */ - //ui_button(obj, .label = "Button 1"); - //ui_button(obj, .label = "Button 2"); - - /* - ui_grid(obj, .spacing = 0) { - ui_button(obj, .label = "HBox Button 1", .hfill = TRUE); - ui_button(obj, .label = "HBox Button 2", .hexpand = TRUE, .hfill = TRUE); - ui_button(obj, .label = "HBox Button 3", .hfill = TRUE); - ui_newline(obj); - ui_grid(obj, .spacing = 0, .colspan = 3) { - ui_button(obj, .label = "V1 Button 1"); - ui_newline(obj); - ui_textarea(obj, .varname = "text1", .vexpand = TRUE, .vfill = TRUE); - ui_newline(obj); - ui_button(obj, .label = "V1 Button 3"); + ui_vbox(obj, .margin = 0, .fill = TRUE) { + //ui_button(obj, .label = "Button"); + ui_textarea(obj, .varname = "text", .fill = TRUE); } - ui_newline(obj); - ui_button(obj, .label = "HBox 2 Button 1", .hfill = TRUE); - ui_button(obj, .label = "HBox 2 Button 2", .hfill = TRUE); - ui_button(obj, .label = "HBox 2 Button 3"); - } - //*/ - - ui_grid(obj, .fill = TRUE, .margin = 10, .columnspacing = 10, .rowspacing = 10) { - ui_button(obj, .label = "Button 1"); - ui_button(obj, .label = "Button 2"); - ui_button(obj, .label = "Button 3", .hfill = TRUE, .hexpand = TRUE); - ui_newline(obj); - - ui_button(obj, .label = "Button X2", .colspan = 3, .hfill = TRUE); - ui_newline(obj); - - ui_textarea(obj, .varname = "text", .fill = TRUE, .colspan = 3); } - /* - ui_button(obj, .label = "HBox Button 1"); - ui_button(obj, .label = "HBox Button 2"); - ui_grid(obj, .fill = TRUE, .columnspacing = 20, .rowspacing = 10, .margin = 50) { - ui_hbox(obj, .spacing = 8, .colspan = 1) { - ui_button(obj, .label = "HBox Button 1"); - ui_button(obj, .label = "HBox Button 2"); - ui_button(obj, .label = "HBox Button 3"); - ui_button(obj, .label = "HBox Button 4"); - } - ui_newline(obj); - - ui_spinbox(obj, .width = 300, .varname = "number", .digits = 2, .step = 0.1); - ui_button(obj, .label = "spinbox", .hfill = TRUE); - ui_newline(obj); - ui_textfield(obj, .width = 300); - ui_button(obj, .label = "textfield", .hfill = TRUE); + + ui_left_panel0(obj) { + ui_button(obj, .label = "left"); } - ui_button(obj, .label = "HBox Button 3"); - */ - /* - ui_grid(obj, .spacing = 0, .fill = TRUE) { - ui_button(obj, .label = "HBox Button 1", .hfill = TRUE); - ui_button(obj, .label = "HBox Button 2", .hexpand = TRUE, .hfill = TRUE); - ui_button(obj, .label = "HBox Button 3", .hfill = TRUE); - ui_newline(obj); - ui_grid(obj, .spacing = 0, .fill = TRUE, .colspan = 3) { - ui_button(obj, .label = "V1 Button 1"); - ui_newline(obj); - ui_textarea(obj, .varname = "text2", .hfill = TRUE, .vfill = TRUE, .hexpand = TRUE, .vexpand = TRUE); - } + ui_right_panel0(obj) { + ui_button(obj, .label = "right"); } - */ - - //ui_button(obj, .label = "Button 3"); - /* - ui_button(obj, .label = "Button 1", .hexpand = TRUE, .hfill = TRUE); - ui_newline(obj); - - ui_grid(obj, .margin = 10, .hexpand = TRUE, .hfill = TRUE) { - ui_button(obj, .label = "H1"); - ui_button(obj, .label = "H2 Ext", .hexpand = TRUE, .hfill = TRUE); - ui_button(obj, .label = "H3"); - } - ui_newline(obj); - - ui_grid(obj, .fill = TRUE) { - ui_button(obj, .label = "B1"); - ui_newline(obj); - - } - ui_newline(obj); - - ui_button(obj, .label = "Button 2", .hexpand = TRUE, .hfill = TRUE); - ui_newline(obj); - */ - + UiModel *model = ui_model(obj->ctx, UI_STRING, "Column 0", UI_STRING, "Column 1", UI_STRING, "Column 2", -1); model->columnsize[1] = -1;
--- a/ui/cocoa/BoxContainer.m Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/BoxContainer.m Tue Oct 07 15:42:18 2025 +0200 @@ -21,12 +21,11 @@ } else { layout.vexpand = TRUE; layout.vfill = TRUE; - self.newline = FALSE; } self.uilayout = layout; [super addView:view margin:margin]; if(_orientation == NSUserInterfaceLayoutOrientationVertical) { - self.newline = TRUE; + self.container->newline = TRUE; } }
--- a/ui/cocoa/GridLayout.h Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/GridLayout.h Tue Oct 07 15:42:18 2025 +0200 @@ -56,6 +56,8 @@ @interface GridLayout : NSView<Container> +@property UiContainerX *container; + @property int columnspacing; @property int rowspacing; @property CxList *children;
--- a/ui/cocoa/GridLayout.m Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/GridLayout.m Tue Oct 07 15:42:18 2025 +0200 @@ -32,9 +32,8 @@ @implementation GridLayout -@synthesize label=_label; @synthesize uilayout=_uilayout; -@synthesize newline=_newline; +@synthesize container=_container; - (GridLayout*)init { self = [super init]; @@ -84,10 +83,6 @@ GridDef *col = &cols[x]; GridDef *row = &rows[y]; - if(elm->margin.left + elm->margin.right > 0) { - printf(""); // break - } - NSSize size = elm->view.intrinsicContentSize; NSSize size2 = elm->view.fittingSize; if(size.width == NSViewNoIntrinsicMetric) { @@ -321,10 +316,10 @@ _preferredSize.width = -1; _preferredSize.height = -1; - if(_newline) { + if(self.container->newline) { _y++; _x = 0; - _newline = FALSE; + self.container->newline = FALSE; } GridElm elm;
--- a/ui/cocoa/MainWindow.h Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/MainWindow.h Tue Oct 07 15:42:18 2025 +0200 @@ -32,8 +32,11 @@ @interface MainWindow : NSWindow @property (strong) NSView *sidebar; +@property (strong) NSView *leftPanel; +@property (strong) NSView *rightPanel; +@property int topOffset; -- (MainWindow*)init:(UiObject*)obj withSidebar:(BOOL)sidebar; +- (MainWindow*)init:(UiObject*)obj withSidebar:(BOOL)hasSidebar withSplitview:(BOOL)hasSplitview; @end
--- a/ui/cocoa/MainWindow.m Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/MainWindow.m Tue Oct 07 15:42:18 2025 +0200 @@ -39,7 +39,7 @@ @implementation MainWindow -- (MainWindow*)init:(UiObject*)obj withSidebar:(BOOL)sidebar { +- (MainWindow*)init:(UiObject*)obj withSidebar:(BOOL)hasSidebar withSplitview:(BOOL)hasSplitview{ NSRect frame = NSMakeRect(300, 200, 600, 500); self = [self initWithContentRect:frame @@ -58,12 +58,15 @@ int top = 4; NSView *content = self.contentView; - if(sidebar) { + + // A sidebar or splitview window need a NSSplitView + NSSplitView *splitview; + if(hasSidebar || hasSplitview) { self.styleMask |= NSWindowStyleMaskFullSizeContentView; self.titleVisibility = NSWindowTitleHidden; self.titlebarAppearsTransparent = YES; - NSSplitView *splitview = [[NSSplitView alloc]init]; + splitview = [[NSSplitView alloc]init]; splitview.vertical = YES; splitview.dividerStyle = NSSplitViewDividerStyleThin; splitview.translatesAutoresizingMaskIntoConstraints = false; @@ -76,27 +79,44 @@ [splitview.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor] ]]; - _sidebar = [[NSView alloc]initWithFrame:NSMakeRect(0,0,100,100)]; - [splitview addArrangedSubview:_sidebar]; - - content = [[NSView alloc]initWithFrame:NSMakeRect(0,0,100,100)]; - [splitview addArrangedSubview:content]; - top = 34; } - // create a vertical stackview as default container - BoxContainer *vbox = [[BoxContainer alloc] init:NSUserInterfaceLayoutOrientationVertical spacing:0]; - //GridLayout *vbox = [[GridLayout alloc] init]; - vbox.translatesAutoresizingMaskIntoConstraints = false; - [content addSubview:vbox]; - [NSLayoutConstraint activateConstraints:@[ - [vbox.topAnchor constraintEqualToAnchor:content.topAnchor constant:top], - [vbox.leadingAnchor constraintEqualToAnchor:content.leadingAnchor], - [vbox.trailingAnchor constraintEqualToAnchor:content.trailingAnchor], - [vbox.bottomAnchor constraintEqualToAnchor:content.bottomAnchor], - ]]; - uic_object_push_container(obj, ui_create_container(obj, vbox)); + if(hasSidebar) { + // add the sidebar + _sidebar = [[NSView alloc]initWithFrame:NSMakeRect(0,0,0,0)]; + _sidebar.translatesAutoresizingMaskIntoConstraints = NO; + [splitview addArrangedSubview:_sidebar]; + [_sidebar.widthAnchor constraintGreaterThanOrEqualToConstant:250].active = YES; + } + if(hasSplitview) { + // add the splitview window left/right panels + _leftPanel = [[NSView alloc]initWithFrame:NSMakeRect(0,0,100,100)]; + [splitview addArrangedSubview:_leftPanel]; + _rightPanel = [[NSView alloc]initWithFrame:NSMakeRect(0,0,100,100)]; + [splitview addArrangedSubview:_rightPanel]; + } else if(hasSidebar) { + // sidebar only window: add content view + content = [[NSView alloc]initWithFrame:NSMakeRect(0,0,100,100)]; + [splitview addArrangedSubview:content]; + } + + // normal or sidebar-only windows get a container + if(!hasSplitview) { + // create a vertical stackview as default container + BoxContainer *vbox = [[BoxContainer alloc] init:NSUserInterfaceLayoutOrientationVertical spacing:0]; + //GridLayout *vbox = [[GridLayout alloc] init]; + vbox.translatesAutoresizingMaskIntoConstraints = false; + [content addSubview:vbox]; + [NSLayoutConstraint activateConstraints:@[ + [vbox.topAnchor constraintEqualToAnchor:content.topAnchor constant:top], + [vbox.leadingAnchor constraintEqualToAnchor:content.leadingAnchor], + [vbox.trailingAnchor constraintEqualToAnchor:content.trailingAnchor], + [vbox.bottomAnchor constraintEqualToAnchor:content.bottomAnchor], + ]]; + uic_object_push_container(obj, ui_create_container(obj, vbox)); + } + _topOffset = top; return self; } @@ -325,3 +345,36 @@ return NULL; } + +static UIWIDGET splitview_window_add_panel(UiObject *obj, NSView *panel, UiSidebarArgs *args) { + MainWindow *window = (__bridge MainWindow*)obj->wobj; + BoxContainer *vbox = [[BoxContainer alloc] init:NSUserInterfaceLayoutOrientationVertical spacing:0]; + //GridLayout *vbox = [[GridLayout alloc] init]; + vbox.translatesAutoresizingMaskIntoConstraints = false; + [panel addSubview:vbox]; + [NSLayoutConstraint activateConstraints:@[ + [vbox.topAnchor constraintEqualToAnchor:panel.topAnchor constant:window.topOffset], + [vbox.leadingAnchor constraintEqualToAnchor:panel.leadingAnchor], + [vbox.trailingAnchor constraintEqualToAnchor:panel.trailingAnchor], + [vbox.bottomAnchor constraintEqualToAnchor:panel.bottomAnchor], + ]]; + uic_object_push_container(obj, ui_create_container(obj, vbox)); + return (__bridge void*)vbox; +} + +UIWIDGET ui_left_panel_create(UiObject *obj, UiSidebarArgs *args) { + MainWindow *window = (__bridge MainWindow*)obj->wobj; + if(window.leftPanel == nil) { + return NULL; + } + return splitview_window_add_panel(obj, window.leftPanel, args); +} + +UIWIDGET ui_right_panel_create(UiObject *obj, UiSidebarArgs *args) { + MainWindow *window = (__bridge MainWindow*)obj->wobj; + if(window.rightPanel == nil) { + return NULL; + } + return splitview_window_add_panel(obj, window.rightPanel, args); +} +
--- a/ui/cocoa/button.m Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/button.m Tue Oct 07 15:42:18 2025 +0200 @@ -33,6 +33,7 @@ UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs *args) { NSButton *button = [[NSButton alloc] init]; + button.translatesAutoresizingMaskIntoConstraints = NO; if(args->label) { NSString *label = [[NSString alloc] initWithUTF8String:args->label]; button.title = label;
--- a/ui/cocoa/container.h Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/container.h Tue Oct 07 15:42:18 2025 +0200 @@ -42,24 +42,6 @@ UI_LAYOUT_FALSE, }; -struct UiLayout { - UiBool fill; - //UiBool newline; - //char *label; - UiBool hexpand; - UiBool vexpand; - UiBool hfill; - UiBool vfill; - //int width; - int margin; - int margin_left; - int margin_right; - int margin_top; - int margin_bottom; - int colspan; - int rowspan; -}; - #define UI_INIT_LAYOUT(args) (UiLayout) {\ .fill = args->fill, \ .hexpand = args->hexpand, \ @@ -78,8 +60,7 @@ @protocol Container @property UiLayout uilayout; -@property const char *label; -@property UiBool newline; +@property UiContainerX *container; - (void) addView:(NSView*)view margin:(NSEdgeInsets)margin;
--- a/ui/cocoa/container.m Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/container.m Tue Oct 07 15:42:18 2025 +0200 @@ -155,6 +155,7 @@ ctn->close = 0; ctn->prev = NULL; ctn->next = NULL; + container.container = ctn; return ctn; } @@ -177,14 +178,3 @@ [container addView:view margin:margin]; } -/* ---------------------- public layout functions ----------------------- */ - -void ui_newline(UiObject *obj) { - UiContainerX *ctn = obj->container_end; - if(ctn) { - id<Container> container = (__bridge id<Container>)ctn->container; - container.newline = TRUE; - } else { - fprintf(stderr, "Error: obj has no container\n"); - } -}
--- a/ui/cocoa/window.m Tue Oct 07 14:59:11 2025 +0200 +++ b/ui/cocoa/window.m Tue Oct 07 15:42:18 2025 +0200 @@ -42,14 +42,14 @@ #include <cx/mempool.h> -static UiObject* create_window(const char *title, BOOL simple, BOOL sidebar) { +static UiObject* create_window(const char *title, BOOL simple, BOOL sidebar, BOOL splitview) { CxMempool *mp = cxMempoolCreateSimple(256); UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject)); obj->ref = 0; obj->ctx = uic_context(obj, mp); - MainWindow *window = [[MainWindow alloc] init:obj withSidebar:sidebar]; + MainWindow *window = [[MainWindow alloc] init:obj withSidebar:sidebar withSplitview:splitview]; [[WindowManager sharedWindowManager] addWindow:window]; window.releasedWhenClosed = false; @@ -64,23 +64,27 @@ } UiObject* ui_window(const char *title, void *window_data) { - UiObject *obj = create_window(title, FALSE, FALSE); + UiObject *obj = create_window(title, FALSE, FALSE, FALSE); obj->window = window_data; return obj; } UiObject* ui_simple_window(const char *title, void *window_data) { - UiObject *obj = create_window(title, TRUE, FALSE); + UiObject *obj = create_window(title, TRUE, FALSE, FALSE); obj->window = window_data; return obj; } UiObject* ui_sidebar_window(const char *title, void *window_data) { - UiObject *obj = create_window(title, FALSE, TRUE); + UiObject *obj = create_window(title, FALSE, TRUE, FALSE); obj->window = window_data; return obj; } +UiObject* ui_splitview_window(const char *title, UiBool sidebar) { + return create_window(title, FALSE, sidebar, TRUE); +} + /* --------------------------------- File Dialogs --------------------------------- */ void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata) {