Sun, 19 Oct 2025 12:08:32 +0200
add dialog window (Cocoa)
--- a/make/xcode/toolkit/toolkit/main.m Sun Oct 19 10:10:06 2025 +0200 +++ b/make/xcode/toolkit/toolkit/main.m Sun Oct 19 12:08:32 2025 +0200 @@ -92,6 +92,25 @@ ui_dialog(event->obj, .title = "Error", .content = "Error Message", .input = TRUE, .button1_label = "Add", .button2_label = "Remove", .closebutton_label = "Close"); } +static void toolbar_action2(UiEvent *event, void *userdata) { + printf("toolbar item 2\n"); + UiObject *obj = ui_dialog_window(event->obj, .title = "Dialog Window", .lbutton1 = "Cancel", .rbutton4 = "OK", .default_button = 4); + + ui_grid(obj, .margin = 10, .columnspacing = 10, .rowspacing = 10, .fill = TRUE) { + ui_rlabel(obj, .label = "Label 1"); + ui_textfield(obj, .value = NULL); + ui_newline(obj); + + ui_rlabel(obj, .label = "Label 2"); + ui_textfield(obj, .value = NULL); + ui_newline(obj); + + ui_textarea(obj, .colspan = 2, .hexpand = TRUE, .hfill = TRUE, .vfill = TRUE, .vexpand = TRUE, .width = 600, .height = 300); + } + + ui_show(obj); +} + static void toolbar_toggle(UiEvent *event, void *userdata) { MyDocument *doc = event->document; int i = (int)(doc ? ui_get(doc->tbtoggle) : -1); @@ -232,11 +251,13 @@ ui_menuitem(.label = "Test1", .onclick = action_menuitem); ui_menu_toggleitem(.label = "Check"); } + ui_toolbar_item("item5", .label = "Dialog Window", .icon = "NSImageNameAddTemplate", .onclick = toolbar_action2); ui_toolbar_add_default("item4", UI_TOOLBAR_LEFT); ui_toolbar_add_default("item3", UI_TOOLBAR_LEFT); ui_toolbar_add_default("item1", UI_TOOLBAR_LEFT); ui_toolbar_add_default("item2", UI_TOOLBAR_RIGHT); + ui_toolbar_add_default("item5", UI_TOOLBAR_RIGHT); ui_main();
--- a/ui/cocoa/EventData.m Sun Oct 19 10:10:06 2025 +0200 +++ b/ui/cocoa/EventData.m Sun Oct 19 12:08:32 2025 +0200 @@ -47,6 +47,7 @@ event.document = event.obj->ctx->document; event.eventdata = self.data; event.intval = self.value; + event.set = ui_get_setop(); self.callback(&event, self.userdata); } } @@ -58,6 +59,7 @@ event.document = event.obj->ctx->document; event.eventdata = NULL; event.intval = 0; + event.set = ui_get_setop(); if(_get_eventdata) { _get_eventdata(sender, _var, &event.eventdata, &event.intval); }
--- a/ui/cocoa/MainWindow.h Sun Oct 19 10:10:06 2025 +0200 +++ b/ui/cocoa/MainWindow.h Sun Oct 19 12:08:32 2025 +0200 @@ -29,7 +29,7 @@ #import "toolkit.h" #import "../ui/window.h" -@interface MainWindow : NSWindow +@interface MainWindow : NSWindow<UiToplevelObject> @property (strong) NSView *sidebar; @property (strong) NSView *leftPanel;
--- a/ui/cocoa/MainWindow.m Sun Oct 19 10:10:06 2025 +0200 +++ b/ui/cocoa/MainWindow.m Sun Oct 19 12:08:32 2025 +0200 @@ -138,6 +138,19 @@ return self; } +- (BOOL) getIsVisible { + return [self isVisible]; +} + +- (void) setVisible:(BOOL)visible { + if(visible) { + [self makeKeyAndOrderFront:nil]; + } else { + [self close]; + } +} + + @end
--- a/ui/cocoa/toolkit.h Sun Oct 19 10:10:06 2025 +0200 +++ b/ui/cocoa/toolkit.h Sun Oct 19 12:08:32 2025 +0200 @@ -44,6 +44,13 @@ @end +@protocol UiToplevelObject + +- (BOOL) getIsVisible; +- (void) setVisible:(BOOL)visible; + +@end + void ui_cocoa_onstartup(void); void ui_cocoa_onopen(const char *file); void ui_cocoa_onexit(void);
--- a/ui/cocoa/toolkit.m Sun Oct 19 10:10:06 2025 +0200 +++ b/ui/cocoa/toolkit.m Sun Oct 19 12:08:32 2025 +0200 @@ -148,18 +148,22 @@ void ui_show(UiObject *obj) { if(obj->wobj) { - NSWindow *window = (__bridge NSWindow*)obj->wobj; + id<UiToplevelObject> window = (__bridge id<UiToplevelObject>)obj->wobj; - if(!window.isVisible) { + if(![window getIsVisible]) { obj->ref++; } - [window makeKeyAndOrderFront:nil]; + [window setVisible:YES]; } } void ui_close(UiObject *obj) { // TODO: unref, window close, ... + if(obj->wobj) { + id<UiToplevelObject> window = (__bridge id<UiToplevelObject>)obj->wobj; + [window setVisible:NO]; + } } /* ------------------- Job Control / Threadpool functions ------------------- */
--- a/ui/cocoa/window.h Sun Oct 19 10:10:06 2025 +0200 +++ b/ui/cocoa/window.h Sun Oct 19 12:08:32 2025 +0200 @@ -28,3 +28,13 @@ #import "toolkit.h" #import "../ui/window.h" + +@interface UiDialogWindow : NSPanel<UiToplevelObject> + +@property UiObject *obj; +@property NSWindow *parent; +@property UiTri modal; +@property ui_callback onclick; +@property void *onclickdata; + +@end
--- a/ui/cocoa/window.m Sun Oct 19 10:10:06 2025 +0200 +++ b/ui/cocoa/window.m Sun Oct 19 12:08:32 2025 +0200 @@ -30,6 +30,8 @@ #import "MainWindow.h" #import "WindowManager.h" +#import "BoxContainer.h" +#import "EventData.h" #import <objc/runtime.h> @@ -231,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; +} +