--- a/ui/cocoa/MainWindow.m Sat Oct 04 14:54:25 2025 +0200 +++ b/ui/cocoa/MainWindow.m Sun Oct 19 21:20:08 2025 +0200 @@ -31,6 +31,7 @@ #import "GridLayout.h" #import "BoxContainer.h" #import "../common/object.h" +#import "../ui/properties.h" #import <objc/runtime.h> #import "EventData.h" @@ -39,7 +40,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 +59,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,31 +80,77 @@ [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 + const char *sidebarMaterialProperty = ui_get_property("ui.cocoa.sidebar.usematerial"); + BOOL useMaterial = YES; + if(sidebarMaterialProperty && (sidebarMaterialProperty[0] == 'f' || sidebarMaterialProperty[0] == 'F')) { + useMaterial = NO; + } + + if(useMaterial) { + NSVisualEffectView *v = [[NSVisualEffectView alloc] initWithFrame:NSMakeRect(0,0,0,0)]; + v.material = NSVisualEffectMaterialSidebar; + v.blendingMode = NSVisualEffectBlendingModeBehindWindow; + v.state = NSVisualEffectStateActive; + _sidebar = v; + } else { + _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], + ]]; + UiContainerX *container = ui_create_container(obj, vbox); + vbox.container = container; + uic_object_push_container(obj, container); + } + _topOffset = top; return self; } +- (BOOL) getIsVisible { + return [self isVisible]; +} + +- (void) setVisible:(BOOL)visible { + if(visible) { + [self makeKeyAndOrderFront:nil]; + } else { + [self close]; + } +} + + @end @@ -312,6 +362,7 @@ // create a vertical stackview as default container BoxContainer *vbox = [[BoxContainer alloc] init:NSUserInterfaceLayoutOrientationVertical spacing:args->spacing]; + vbox.container = ui_create_container(obj, vbox); //GridLayout *vbox = [[GridLayout alloc] init]; vbox.translatesAutoresizingMaskIntoConstraints = false; [sidebar addSubview:vbox]; @@ -321,7 +372,41 @@ [vbox.trailingAnchor constraintEqualToAnchor:sidebar.trailingAnchor], [vbox.bottomAnchor constraintEqualToAnchor:sidebar.bottomAnchor] ]]; - uic_object_push_container(obj, ui_create_container(obj, vbox)); + uic_object_push_container(obj, vbox.container); 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.container = ui_create_container(obj, vbox); + 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, vbox.container); + 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); +} +