# HG changeset patch # User Olaf Wintermann # Date 1760427944 -7200 # Node ID ffa983c223c1673b9ec48ffd91fa155453453266 # Parent f3ab28ed22e556b72aefab6324c1932d2071c5cf add frame container (Cocoa) diff -r f3ab28ed22e5 -r ffa983c223c1 make/xcode/toolkit/toolkit/main.m --- a/make/xcode/toolkit/toolkit/main.m Mon Oct 13 21:31:58 2025 +0200 +++ b/make/xcode/toolkit/toolkit/main.m Tue Oct 14 09:45:44 2025 +0200 @@ -144,8 +144,16 @@ ui_grid(obj, .margin_left = 10, .margin_right = 10, .columnspacing = 10, .rowspacing = 10, .fill = TRUE) { ui_button(obj, .label = "left", .hexpand = TRUE, .hfill = TRUE); ui_newline(obj); + ui_linkbutton(obj, .varname = "link", .hexpand = TRUE, .hfill = TRUE); + ui_newline(obj); - ui_linkbutton(obj, .varname = "link", .hexpand = TRUE, .hfill = TRUE); + ui_frame(obj, .label = "Test", .margin = 10, .hfill = TRUE, .vfill = TRUE, .hexpand = TRUE, .vexpand = TRUE, .subcontainer = UI_CONTAINER_VBOX, .spacing = 10) { + ui_button(obj, .label = "Test Button"); + ui_button(obj, .label = "Test Button"); + ui_button(obj, .label = "Test Button"); + ui_button(obj, .label = "Test Button"); + ui_button(obj, .label = "Test Button"); + } } } diff -r f3ab28ed22e5 -r ffa983c223c1 ui/cocoa/BoxContainer.m --- a/ui/cocoa/BoxContainer.m Mon Oct 13 21:31:58 2025 +0200 +++ b/ui/cocoa/BoxContainer.m Tue Oct 14 09:45:44 2025 +0200 @@ -13,17 +13,15 @@ return self; } -- (void) addView:(NSView*)view margin:(NSEdgeInsets)margin { - UiLayout layout = self.uilayout; +- (void) addView:(NSView*)view layout:(UiLayout*)layout { if(_orientation == NSUserInterfaceLayoutOrientationVertical) { - layout.hexpand = TRUE; - layout.hfill = TRUE; + layout->hexpand = TRUE; + layout->hfill = TRUE; } else { - layout.vexpand = TRUE; - layout.vfill = TRUE; + layout->vexpand = TRUE; + layout->vfill = TRUE; } - self.uilayout = layout; - [super addView:view margin:margin]; + [super addView:view layout:layout]; if(_orientation == NSUserInterfaceLayoutOrientationVertical) { self.container->newline = TRUE; } diff -r f3ab28ed22e5 -r ffa983c223c1 ui/cocoa/GridLayout.m --- a/ui/cocoa/GridLayout.m Mon Oct 13 21:31:58 2025 +0200 +++ b/ui/cocoa/GridLayout.m Tue Oct 14 09:45:44 2025 +0200 @@ -32,8 +32,7 @@ @implementation GridLayout -@synthesize uilayout=_uilayout; -@synthesize container=_container; +@synthesize container = _container; - (GridLayout*)init { self = [super init]; @@ -293,6 +292,7 @@ } else { frame.size.height = elm->preferred_height; } + frame.size.height -= elm->margin.top + elm->margin.bottom; frame.origin.x = col->pos + elm->margin.left; frame.origin.y = row->pos + elm->margin.top; @@ -312,7 +312,7 @@ return self.preferredSize; } -- (void) addView:(NSView*)view margin:(NSEdgeInsets)margin { +- (void) addView:(NSView*)view layout:(UiLayout*)layout { _preferredSize.width = -1; _preferredSize.height = -1; @@ -325,19 +325,19 @@ GridElm elm; elm.x = _x; elm.y = _y; - elm.margin = margin; - elm.colspan = _uilayout.colspan; - elm.rowspan = _uilayout.rowspan; - if(_uilayout.fill) { + elm.margin = NSEdgeInsetsMake(layout->margin_top, layout->margin_left, layout->margin_bottom, layout->margin_right); + elm.colspan = layout->colspan; + elm.rowspan = layout->rowspan; + if(layout->fill) { elm.hfill = TRUE; elm.vfill = TRUE; elm.hexpand = TRUE; elm.vexpand = TRUE; } else { - elm.hfill = _uilayout.hfill; - elm.vfill = _uilayout.vfill; - elm.hexpand = _uilayout.hexpand; - elm.vexpand = _uilayout.vexpand; + elm.hfill = layout->hfill; + elm.vfill = layout->vfill; + elm.hexpand = layout->hexpand; + elm.vexpand = layout->vexpand; } elm.view = view; cxListAdd(_children, &elm); diff -r f3ab28ed22e5 -r ffa983c223c1 ui/cocoa/MainWindow.m --- a/ui/cocoa/MainWindow.m Mon Oct 13 21:31:58 2025 +0200 +++ b/ui/cocoa/MainWindow.m Tue Oct 14 09:45:44 2025 +0200 @@ -129,7 +129,9 @@ [vbox.trailingAnchor constraintEqualToAnchor:content.trailingAnchor], [vbox.bottomAnchor constraintEqualToAnchor:content.bottomAnchor], ]]; - uic_object_push_container(obj, ui_create_container(obj, vbox)); + UiContainerX *container = ui_create_container(obj, vbox); + vbox.container = container; + uic_object_push_container(obj, container); } _topOffset = top; @@ -347,6 +349,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]; @@ -356,7 +359,7 @@ [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; } @@ -365,6 +368,7 @@ 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:@[ @@ -373,7 +377,7 @@ [vbox.trailingAnchor constraintEqualToAnchor:panel.trailingAnchor], [vbox.bottomAnchor constraintEqualToAnchor:panel.bottomAnchor], ]]; - uic_object_push_container(obj, ui_create_container(obj, vbox)); + uic_object_push_container(obj, vbox.container); return (__bridge void*)vbox; } diff -r f3ab28ed22e5 -r ffa983c223c1 ui/cocoa/container.h --- a/ui/cocoa/container.h Mon Oct 13 21:31:58 2025 +0200 +++ b/ui/cocoa/container.h Tue Oct 14 09:45:44 2025 +0200 @@ -53,10 +53,16 @@ @protocol Container -@property UiLayout uilayout; @property UiContainerX *container; -- (void) addView:(NSView*)view margin:(NSEdgeInsets)margin; +- (void) addView:(NSView*)view layout:(UiLayout*)layout; + +@end + + +@interface FrameContainer : NSBox + +- (id)init:(NSString*)title; @end diff -r f3ab28ed22e5 -r ffa983c223c1 ui/cocoa/container.m --- a/ui/cocoa/container.m Mon Oct 13 21:31:58 2025 +0200 +++ b/ui/cocoa/container.m Tue Oct 14 09:45:44 2025 +0200 @@ -30,81 +30,20 @@ #import "GridLayout.h" #import "BoxContainer.h" -/* ------------------------- container classes ------------------------- */ - -/* -@implementation BoxContainer - -@synthesize label=_label; -@synthesize uilayout=_uilayout; -@synthesize newline=_newline; - -- (BoxContainer*)init:(NSUserInterfaceLayoutOrientation)orientation spacing:(int)spacing { - self = [super init]; - _label = NULL; - _uilayout = (UiLayout){ 0 }; - _newline = false; - - self.distribution = NSStackViewDistributionFillProportionally; - self.spacing = spacing; - - self.orientation = orientation; - if(orientation == NSUserInterfaceLayoutOrientationHorizontal) { - self.alignment = NSLayoutAttributeHeight; - } else { - self.alignment = NSLayoutAttributeWidth; - } - - - return self; -} - -- (void) addView:(NSView*)view { - UiBool fill = _uilayout.fill; - - [self addArrangedSubview:view]; - - if(self.orientation == NSUserInterfaceLayoutOrientationHorizontal) { - [view.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = YES; - if(!fill) { - NSSize isize = view.intrinsicContentSize; - [view.widthAnchor constraintEqualToConstant:isize.width].active = YES; - } - } else { - [view.widthAnchor constraintEqualToAnchor:self.widthAnchor].active = YES; - if(!fill) { - NSSize isize = view.intrinsicContentSize; - NSRect frame = view.frame; - CGFloat height = isize.height > 0 ? isize.height : frame.size.height; - if(height == 0) { - printf("debug"); - } - if(height > 0) { - [view.heightAnchor constraintEqualToConstant:height].active = YES; - } - } - } - - // at the moment, only the fill layout option needs to be reset - _uilayout.fill = UI_DEFAULT; -} - -@end -*/ - - /* -------------------- public container functions --------------------- */ static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, NSUserInterfaceLayoutOrientation orientation) { BoxContainer *box = [[BoxContainer alloc] init:orientation spacing:args->spacing]; box.translatesAutoresizingMaskIntoConstraints = false; + UiContainerX *container = ui_create_container(obj, box); + box.container = container; // add box to the parent UiLayout layout = UI_INIT_LAYOUT(args); ui_container_add(obj, box, &layout); // add new box to the obj container chain - uic_object_push_container(obj, ui_create_container(obj, box)); + uic_object_push_container(obj, container); return (__bridge void*)box; } @@ -122,17 +61,63 @@ grid.translatesAutoresizingMaskIntoConstraints = false; grid.columnspacing = args->columnspacing; grid.rowspacing = args->rowspacing; + UiContainerX *container = ui_create_container(obj, grid); + grid.container = container; // add box to the parent UiLayout layout = UI_INIT_LAYOUT(args); ui_container_add(obj, grid, &layout); // add new box to the obj container chain - uic_object_push_container(obj, ui_create_container(obj, grid)); + uic_object_push_container(obj, container); return (__bridge void*)grid; } +UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) { + NSString *title = args->label ? [[NSString alloc]initWithUTF8String:args->label] : nil; + FrameContainer *frame = [[FrameContainer alloc] init:title]; UiLayout layout = UI_ARGS2LAYOUT(args); + ui_container_add(obj, frame, &layout); + + // add container to the chain + UiContainerX *container; + UiLayout subLayout = {0}; + switch(args->subcontainer) { + default: { + // UI_CONTAINER_NO_SUB + container = ui_create_container(obj, frame); + break; + } + case UI_CONTAINER_VBOX: { + BoxContainer *box = [[BoxContainer alloc]init:NSUserInterfaceLayoutOrientationVertical spacing:args->spacing]; + box.translatesAutoresizingMaskIntoConstraints = false; + [frame addView:box layout:&subLayout]; + container = ui_create_container(obj, box); + break; + } + case UI_CONTAINER_HBOX: { + BoxContainer *box = [[BoxContainer alloc]init:NSUserInterfaceLayoutOrientationHorizontal spacing:args->spacing]; + box.translatesAutoresizingMaskIntoConstraints = false; + [frame addView:box layout:&subLayout]; + container = ui_create_container(obj, box); + break; + } + case UI_CONTAINER_GRID: { + GridLayout *grid = [[GridLayout alloc] init]; + grid.translatesAutoresizingMaskIntoConstraints = false; + grid.columnspacing = args->columnspacing; + grid.rowspacing = args->rowspacing; + [frame addView:grid layout:&subLayout]; + container = ui_create_container(obj, grid); + break; + } + } + + uic_object_push_container(obj, container); + + return NULL; +} + void ui_container_begin_close(UiObject *obj) { UiContainerX *ct = obj->container_end; ct->close = 1; @@ -147,6 +132,35 @@ return 1; } +/* -------------------------- Frame Container -------------------------- */ + +@implementation FrameContainer + +@synthesize container = _container; + +- (id)init:(NSString*)title { + self = [super init]; + self.title = title; + self.boxType = NSBoxPrimary; + if(title != nil) { + self.titlePosition = NSAtTop; + } + return self; +} + +- (void) addView:(NSView*)view layout:(UiLayout*)layout { + [self.contentView addSubview:view]; + view.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [view.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:0], + [view.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:0], + [view.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-0], + [view.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-0] + ]]; +} + +@end + /* ------------------------- private functions ------------------------- */ UiContainerX* ui_create_container(UiObject *obj, id container) { @@ -162,19 +176,13 @@ void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout) { UiContainerX *ctn = obj->container_end; id container = (__bridge id)ctn->container; - container.uilayout = *layout; - NSEdgeInsets margin = {0}; - if(layout->margin > 0) { - margin.left = layout->margin; - margin.right = layout->margin; - margin.top = layout->margin; - margin.bottom = layout->margin; - } else { - margin.left = layout->margin_left; - margin.right = layout->margin_right; - margin.top = layout->margin_top; - margin.bottom = layout->margin_bottom; + UiLayout adjustedLayout = *layout; + if(adjustedLayout.margin > 0) { + adjustedLayout.margin_left = adjustedLayout.margin; + adjustedLayout.margin_right = adjustedLayout.margin; + adjustedLayout.margin_top = adjustedLayout.margin; + adjustedLayout.margin_bottom = adjustedLayout.margin; } - [container addView:view margin:margin]; + [container addView:view layout:layout]; }