ui/cocoa/container.m

changeset 112
c3f2f16fa4b8
parent 110
c00e968d018b
child 113
dde28a806552
--- a/ui/cocoa/container.m	Sat Oct 04 14:54:25 2025 +0200
+++ b/ui/cocoa/container.m	Sun Oct 19 21:20:08 2025 +0200
@@ -29,82 +29,21 @@
 #import "Container.h"
 #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
-*/
-
+#import "TabView.h"
 
 /* -------------------- 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);
     
     // 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;
 }
@@ -120,17 +59,134 @@
 UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) {
     GridLayout *grid = [[GridLayout alloc] init];
     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 (__bridge void*)frame;
+}
+
+UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) {
+    return ui_frame_create(obj, args); // TODO
+}
+
+UIWIDGET ui_scrolledwindow_create(UiObject *obj, UiFrameArgs *args) {
+    int colspacing = args->spacing;
+    int rowspacing = args->spacing;
+    if(args->subcontainer == UI_CONTAINER_GRID) {
+        colspacing = args->columnspacing;
+        rowspacing = args->rowspacing;
+    }
+    ScrollViewContainer *scrollview = [[ScrollViewContainer alloc]init:args->subcontainer columnSpacing:colspacing rowSpacing:rowspacing];
+    scrollview.hasVerticalScroller = YES;
+    scrollview.scrollerStyle = NSScrollerStyleOverlay;
+    scrollview.autohidesScrollers = YES;
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ui_container_add(obj, scrollview, &layout);
+    
+    UiContainerX *container = ui_create_container(obj, scrollview);
+    uic_object_push_container(obj, container);
+    
+    return (__bridge void*)scrollview;
+}
+
+UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args) {
+    NSView<TabView, Container> *tabview;
+    switch(args->tabview) {
+        default: tabview = [[UiTopTabView alloc]init:obj args:args]; break;
+    }
+    
+    UiLayout layout = UI_ARGS2LAYOUT(args);
+    ui_container_add(obj, tabview, &layout);
+    
+    UiContainerX *container = ui_create_container(obj, tabview);
+    uic_object_push_container(obj, container);
+    
+    return (__bridge void*)tabview;
+}
+
+void ui_tab_create(UiObject *obj, const char* title) {
+    UiContainerX *ctn = obj->container_end;
+    id<TabView> tabview = (__bridge id<TabView>)ctn->container;
+    NSString *s = title ? [[NSString alloc]initWithUTF8String:title] : @"";
+    NSView<Container> *sub = [tabview createTab:-1 title:s];
+    
+    UiContainerX *container = ui_create_container(obj, sub);
+    uic_object_push_container(obj, container);
+}
+
+void ui_tabview_select(UIWIDGET tabview, int tab) {
+    id<TabView> tabv = (__bridge id<TabView>)tabview;
+    [tabv selectTab:tab];
+}
+
+void ui_tabview_remove(UIWIDGET tabview, int tab) {
+    id<TabView> tabv = (__bridge id<TabView>)tabview;
+    [tabv removeTab:tab];
+}
+
+UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) {
+    id<TabView> tabv = (__bridge id<TabView>)tabview;
+    NSString *s = name ? [[NSString alloc]initWithUTF8String:name] : @"";
+    return [tabv addTab:tab_index title:s];
+}
+
+
+
+
 void ui_container_begin_close(UiObject *obj) {
     UiContainerX *ct = obj->container_end;
     ct->close = 1;
@@ -145,6 +201,94 @@
     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
+
+
+/* -------------------------- Expander Container -------------------------- */
+
+// TODO
+
+
+/* ------------------------ ScrollView Container ------------------------ */
+
+@implementation ScrollViewContainer
+
+@synthesize container = _container;
+
+- (id)init:(UiSubContainerType)subContainer columnSpacing:(int)columnSpacing rowSpacing:(int)rowSpacing {
+    self = [super init];
+    
+    if(subContainer != UI_CONTAINER_NO_SUB) {
+        GridLayout *child;
+        switch(subContainer) {
+            default:
+            case UI_CONTAINER_VBOX: {
+                child = [[BoxContainer alloc]init:NSUserInterfaceLayoutOrientationVertical spacing:columnSpacing];
+                break;
+            }
+            case UI_CONTAINER_HBOX: {
+                child = [[BoxContainer alloc]init:NSUserInterfaceLayoutOrientationHorizontal spacing:columnSpacing];
+                break;
+            }
+            case UI_CONTAINER_GRID: {
+                child = [[GridLayout alloc]init];
+                child.columnspacing = columnSpacing;
+                child.rowspacing = rowSpacing;
+                break;
+            }
+        }
+        child.translatesAutoresizingMaskIntoConstraints = NO;
+        
+        self.documentView = child;
+        [child.widthAnchor constraintEqualToAnchor:self.contentView.widthAnchor].active = YES;
+        
+        _child = child;
+    }
+    
+    
+    return self;
+}
+
+- (void) addView:(NSView*)view layout:(UiLayout*)layout {
+    if(_child != nil) {
+        _child.container = self.container; // required, otherwise child has no container and can't access the newline property
+        view.translatesAutoresizingMaskIntoConstraints = NO;
+        [_child addView:view layout:layout];
+    } else {
+        self.documentView = view;
+        [view.widthAnchor constraintEqualToAnchor:self.contentView.widthAnchor].active = YES;
+    }
+}
+
+@end
+
 /* ------------------------- private functions ------------------------- */
 
 UiContainerX* ui_create_container(UiObject *obj, id<Container> container) {
@@ -153,24 +297,20 @@
     ctn->close = 0;
     ctn->prev = NULL;
     ctn->next = NULL;
+    container.container = ctn;
     return ctn;
 }
 
 void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout) {
     UiContainerX *ctn = obj->container_end;
     id<Container> container = (__bridge id<Container>)ctn->container;
-    container.uilayout = *layout;
-    [container addView:view];
+    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 layout:&adjustedLayout];
 }
 
-/* ---------------------- 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");
-    }
-}

mercurial