ui/cocoa/window.m

changeset 112
c3f2f16fa4b8
parent 110
c00e968d018b
child 113
dde28a806552
--- a/ui/cocoa/window.m	Sat Oct 04 14:54:25 2025 +0200
+++ b/ui/cocoa/window.m	Sun Oct 19 21:20:08 2025 +0200
@@ -30,6 +30,8 @@
 
 #import "MainWindow.h"
 #import "WindowManager.h"
+#import "BoxContainer.h"
+#import "EventData.h"
 
 #import <objc/runtime.h>
 
@@ -38,20 +40,17 @@
 #include "../common/context.h"
 #include "../common/menu.h"
 #include "../common/toolbar.h"
+#include "../common/object.h"
 
 #include <cx/mempool.h>
 
 
-static UiObject* create_window(const char *title, BOOL simple, BOOL sidebar) {
-    CxMempool *mp = cxMempoolCreateSimple(256);
-    UiObject *obj = cxCalloc(mp->allocator, 1, sizeof(UiObject));
-    obj->ref = 0;
+static UiObject* create_window(const char *title, BOOL simple, BOOL sidebar, BOOL splitview) {
+    UiObject *obj = uic_object_new_toplevel();
     
-    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;
+    window.releasedWhenClosed = false; // TODO: we still need a cleanup strategy
     
     obj->wobj = (__bridge void*)window;
     
@@ -64,23 +63,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) {
@@ -230,3 +233,188 @@
     }];
     
 }
+
+/* ------------------------------------- Dialog Window ------------------------------------- */
+
+@implementation UiDialogWindow
+
+- (BOOL) getIsVisible {
+    return self.isVisible;
+}
+
+- (void) setVisible:(BOOL)visible {
+    //[self makeKeyAndOrderFront:nil];
+    if(visible) {
+        [_parent beginSheet:self completionHandler:^(NSModalResponse returnCode) {
+            // TODO: close event
+        }];
+    } else {
+        [self.sheetParent endSheet:self returnCode:NSModalResponseCancel];
+    }
+}
+
+- (void)cancelOperation:(id)sender {
+    [self.sheetParent endSheet:self returnCode:NSModalResponseCancel];
+    // TODO: close event
+}
+
+@end
+
+UiObject *ui_dialog_window_create(UiObject *parent, UiDialogWindowArgs *args) {
+    UiObject *obj = uic_object_new_toplevel();
+    UiDialogWindow *panel = [[UiDialogWindow alloc] initWithContentRect:NSMakeRect(0, 0, args->width, args->height)
+                                                 styleMask:(NSWindowStyleMaskTitled |
+                                                             NSWindowStyleMaskClosable |
+                                                             NSWindowStyleMaskResizable |
+                                                             NSWindowStyleMaskUtilityWindow)
+                                                   backing:NSBackingStoreBuffered
+                                                     defer:NO];
+    panel.parent = (__bridge NSWindow*)parent->wobj;
+    panel.obj = obj;
+    panel.modal = args->modal;
+    panel.onclick = args->onclick;
+    panel.onclickdata = args->onclickdata;
+    [panel center];
+    [[WindowManager sharedWindowManager] addWindow:panel];
+    obj->wobj = (__bridge void*)panel;
+    
+    NSView *content = panel.contentView;
+    
+    // Create a view for the dialog window buttons (lbutton1, lbutton2, rbutton3, rbutton4)
+    NSView *buttonArea = [[NSView alloc]init];
+    buttonArea.translatesAutoresizingMaskIntoConstraints = NO;
+    [content addSubview:buttonArea];
+    [NSLayoutConstraint activateConstraints:@[
+        [buttonArea.bottomAnchor constraintEqualToAnchor:content.bottomAnchor constant:-10],
+        [buttonArea.leadingAnchor constraintEqualToAnchor:content.leadingAnchor constant:10],
+        [buttonArea.trailingAnchor constraintEqualToAnchor:content.trailingAnchor constant:-10],
+        [buttonArea.heightAnchor constraintEqualToConstant:20]
+    ]];
+    
+    NSButton *lbutton1 = nil;
+    if(args->lbutton1) {
+        lbutton1 = [[NSButton alloc]init];
+        lbutton1.title = [[NSString alloc]initWithUTF8String:args->lbutton1];
+        lbutton1.translatesAutoresizingMaskIntoConstraints = NO;
+        [buttonArea addSubview:lbutton1];
+        [NSLayoutConstraint activateConstraints:@[
+            [lbutton1.topAnchor constraintEqualToAnchor:buttonArea.topAnchor constant:0],
+            [lbutton1.leadingAnchor constraintEqualToAnchor:buttonArea.leadingAnchor constant:0]
+        ]];
+        
+        EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata];
+        event.obj = obj;
+        event.value = 1;
+        lbutton1.target = event;
+        lbutton1.action = @selector(handleEvent:);
+        objc_setAssociatedObject(lbutton1, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+    }
+    NSButton *lbutton2 = nil;
+    if(args->lbutton2) {
+        lbutton2 = [[NSButton alloc]init];
+        lbutton2.title = [[NSString alloc]initWithUTF8String:args->lbutton2];
+        lbutton2.translatesAutoresizingMaskIntoConstraints = NO;
+        [buttonArea addSubview:lbutton2];
+        NSLayoutXAxisAnchor *anchor = lbutton1 != nil ? lbutton1.trailingAnchor : buttonArea.leadingAnchor;
+        int off = lbutton1 != nil ? 4 : 0;
+        [NSLayoutConstraint activateConstraints:@[
+            [lbutton2.topAnchor constraintEqualToAnchor:buttonArea.topAnchor constant:0],
+            [lbutton2.leadingAnchor constraintEqualToAnchor:anchor constant:off]
+        ]];
+        
+        EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata];
+        event.obj = obj;
+        event.value = 2;
+        lbutton2.target = event;
+        lbutton2.action = @selector(handleEvent:);
+        objc_setAssociatedObject(lbutton2, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+    }
+    
+    NSButton *rbutton4 = nil;
+    if(args->rbutton4) {
+        rbutton4 = [[NSButton alloc]init];
+        rbutton4.title = [[NSString alloc]initWithUTF8String:args->rbutton4];
+        rbutton4.translatesAutoresizingMaskIntoConstraints = NO;
+        [buttonArea addSubview:rbutton4];
+        [NSLayoutConstraint activateConstraints:@[
+            [rbutton4.topAnchor constraintEqualToAnchor:buttonArea.topAnchor constant:0],
+            [rbutton4.trailingAnchor constraintEqualToAnchor:buttonArea.trailingAnchor constant:0]
+        ]];
+        
+        EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata];
+        event.obj = obj;
+        event.value = 2;
+        rbutton4.target = event;
+        rbutton4.action = @selector(handleEvent:);
+        objc_setAssociatedObject(rbutton4, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+    }
+    NSButton *rbutton3 = nil;
+    if(args->rbutton3) {
+        rbutton3 = [[NSButton alloc]init];
+        rbutton3.title = [[NSString alloc]initWithUTF8String:args->rbutton3];
+        rbutton3.translatesAutoresizingMaskIntoConstraints = NO;
+        [buttonArea addSubview:rbutton3];
+        NSLayoutXAxisAnchor *anchor = rbutton4 != nil ? rbutton4.leadingAnchor : buttonArea.trailingAnchor;
+        int off = rbutton4 != nil ? -4 : 0;
+        [NSLayoutConstraint activateConstraints:@[
+            [rbutton3.topAnchor constraintEqualToAnchor:buttonArea.topAnchor constant:0],
+            [rbutton3.trailingAnchor constraintEqualToAnchor:anchor constant:off]
+        ]];
+        
+        EventData *event = [[EventData alloc] init:args->onclick userdata:args->onclickdata];
+        event.obj = obj;
+        event.value = 2;
+        rbutton3.target = event;
+        rbutton3.action = @selector(handleEvent:);
+        objc_setAssociatedObject(rbutton3, "eventdata", event, OBJC_ASSOCIATION_RETAIN);
+    }
+    switch(args->default_button) {
+        default: break;
+        case 1: if(lbutton1 != nil) lbutton1.keyEquivalent = @"\r"; break;
+        case 2: if(lbutton2 != nil) lbutton2.keyEquivalent = @"\r"; break;
+        case 3: if(rbutton3 != nil) rbutton3.keyEquivalent = @"\r"; break;
+        case 4: if(rbutton4 != nil) rbutton4.keyEquivalent = @"\r"; break;
+    }
+    
+    // space between left and right buttons
+    NSView *space = [[NSView alloc]init];
+    space.translatesAutoresizingMaskIntoConstraints = NO;
+    [buttonArea addSubview:space];
+    NSLayoutXAxisAnchor *leftAnchor = buttonArea.leadingAnchor;
+    NSLayoutXAxisAnchor *rightAnchor = buttonArea.trailingAnchor;
+    if(lbutton2 != nil) {
+        leftAnchor = lbutton2.trailingAnchor;
+    } else if(lbutton1 != nil) {
+        leftAnchor = lbutton1.trailingAnchor;
+    }
+    
+    if(rbutton3 != nil) {
+        rightAnchor = rbutton3.leadingAnchor;
+    } else if(rbutton4 != nil) {
+        rightAnchor = rbutton4.leadingAnchor;
+    }
+    [NSLayoutConstraint activateConstraints:@[
+        [space.topAnchor constraintEqualToAnchor:buttonArea.topAnchor],
+        [space.leadingAnchor constraintEqualToAnchor:leftAnchor constant:10],
+        [space.trailingAnchor constraintEqualToAnchor:rightAnchor constant:-10]
+    ]];
+    
+    // dialog window main content
+    BoxContainer *vbox = [[BoxContainer alloc] init:NSUserInterfaceLayoutOrientationVertical spacing:0];
+    vbox.translatesAutoresizingMaskIntoConstraints = NO;
+    [content addSubview:vbox];
+    
+    [NSLayoutConstraint activateConstraints:@[
+        [vbox.topAnchor constraintEqualToAnchor:content.topAnchor constant:0],
+        [vbox.leadingAnchor constraintEqualToAnchor:content.leadingAnchor],
+        [vbox.trailingAnchor constraintEqualToAnchor:content.trailingAnchor],
+        [vbox.bottomAnchor constraintEqualToAnchor:buttonArea.topAnchor constant:0]
+    ]];
+     
+    UiContainerX *container = ui_create_container(obj, vbox);
+    vbox.container = container;
+    uic_object_push_container(obj, container);
+    
+    return obj;
+}
+

mercurial