ui/cocoa/window.m

Sat, 04 Oct 2025 14:52:59 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 04 Oct 2025 14:52:59 +0200
changeset 110
c00e968d018b
parent 108
77254bd6dccb
child 112
c3f2f16fa4b8
permissions
-rw-r--r--

fix repolist menu button

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2024 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import "window.h"

#import "MainWindow.h"
#import "WindowManager.h"

#import <objc/runtime.h>

#include "../ui/window.h"
#include "../ui/properties.h"
#include "../common/context.h"
#include "../common/menu.h"
#include "../common/toolbar.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;
    
    obj->ctx = uic_context(obj, mp);
    
    MainWindow *window = [[MainWindow alloc] init:obj withSidebar:sidebar];
    [[WindowManager sharedWindowManager] addWindow:window];
    window.releasedWhenClosed = false;
    
    obj->wobj = (__bridge void*)window;
    
    MainWindowController *controller = [[MainWindowController alloc] initWithWindow:obj window:window];
    window.windowController = controller;
    [window setNextResponder:(NSResponder*)controller];
    objc_setAssociatedObject(window, "windowcontroller", controller, OBJC_ASSOCIATION_RETAIN);
    
    return obj;
}

UiObject* ui_window(const char *title, void *window_data) {
    UiObject *obj = create_window(title, 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);
    obj->window = window_data;
    return obj;
}

UiObject* ui_sidebar_window(const char *title, void *window_data) {
    UiObject *obj = create_window(title, FALSE, TRUE);
    obj->window = window_data;
    return obj;
}

/* --------------------------------- File Dialogs --------------------------------- */

void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata) {
    NSOpenPanel *openPanel = [NSOpenPanel openPanel];
    if((mode & UI_FILEDIALOG_SELECT_MULTI) == UI_FILEDIALOG_SELECT_MULTI) {
        openPanel.allowsMultipleSelection = YES;
    }
    if((mode & UI_FILEDIALOG_SELECT_FOLDER) == UI_FILEDIALOG_SELECT_FOLDER) {
        openPanel.canChooseFiles = NO;
        openPanel.canChooseDirectories = YES;
    }
    
    NSWindow *window = (__bridge NSWindow*)obj->wobj;
    [openPanel beginSheetModalForWindow:window completionHandler:^(NSModalResponse result) {
        UiEvent event;
        event.obj = obj;
        event.window = obj->window;
        event.document = obj->ctx->document;
        event.intval = 0;
        event.set = 0;
        
        UiFileList flist = { NULL, 0 };
        event.eventdata = &flist;
        event.eventdatatype = UI_EVENT_DATA_FILE_LIST;
        
        if(result == NSModalResponseOK) {
            NSArray<NSURL *> *urls = [openPanel URLs];
            flist.files = calloc(urls.count, sizeof(char*));
            for(NSURL *url in urls) {
                if([url isFileURL]) {
                    flist.files[flist.nfiles++] = strdup(url.path.UTF8String);
                }
            }
        }
        
        if(file_selected_callback) {
            file_selected_callback(&event, cbdata);
        }
        ui_filelist_free(flist);
    }];
}

void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata) {
    NSSavePanel *savePanel = [NSSavePanel savePanel];
    if(name) {
        NSString *nameStr = [[NSString alloc] initWithUTF8String:name];
        [savePanel setNameFieldStringValue: nameStr];
    }
    
    NSWindow *window = (__bridge NSWindow*)obj->wobj;
    [savePanel beginSheetModalForWindow:window completionHandler:^(NSModalResponse result) {
        UiEvent event;
        event.obj = obj;
        event.window = obj->window;
        event.document = obj->ctx->document;
        event.intval = 0;
        event.set = 0;
        
        UiFileList flist = { NULL, 0 };
        event.eventdata = &flist;
        event.eventdatatype = UI_EVENT_DATA_FILE_LIST;
        
        if(result == NSModalResponseOK) {
            NSURL *url = [savePanel URL];
            if([url isFileURL]) {
                NSString *path = url.path;
                flist.files = malloc(sizeof(char*));
                flist.files[0] = strdup(path.UTF8String);
                flist.nfiles = 1;
            }
            file_selected_callback(NULL, NULL);
        }
        if(file_selected_callback) {
            file_selected_callback(&event, cbdata);
        }
        ui_filelist_free(flist);
    }];
}

/* ------------------------------------- Dialog ------------------------------------- */

void ui_dialog_create(UiObject *parent, UiDialogArgs *args) {
    NSAlert *dialog = [[NSAlert alloc] init];
    
    if(args->title) {
        dialog.messageText = [[NSString alloc]initWithUTF8String:args->title];
    }
    if(args->content) {
        dialog.informativeText = [[NSString alloc]initWithUTF8String:args->content];
    }
    NSTextField *textfield = nil;
    if(args->input) {
        NSRect frame = NSMakeRect(0,0,300,22);
        textfield = args->password ? [[NSSecureTextField alloc] initWithFrame:frame] : [[NSTextField alloc]initWithFrame:frame];
        if(args->input_value) {
            textfield.stringValue = [[NSString alloc]initWithUTF8String:args->input_value];
        }
        dialog.accessoryView = textfield;
    }
    
    int b = 0;
    int b1 = -1;
    int b2 = -1;
    if(args->button1_label) {
        [dialog addButtonWithTitle:[[NSString alloc]initWithUTF8String:args->button1_label]];
        b1 = b++;
    }
    if(args->button2_label) {
        [dialog addButtonWithTitle:[[NSString alloc]initWithUTF8String:args->button2_label]];
        b2 = b;
    }
    if(args->closebutton_label) {
        [dialog addButtonWithTitle:[[NSString alloc]initWithUTF8String:args->closebutton_label]];
    }
    
    ui_callback callback = args->result;
    void *userdata = args->resultdata;
    
    NSWindow *window = (__bridge NSWindow*)parent->wobj;
    [dialog beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) {
        UiEvent event;
        event.obj = parent;
        event.window = event.obj->window;
        event.document = event.obj->ctx->document;
        event.eventdata = NULL;
        event.eventdatatype = 0;
        event.set = 0;
        event.intval = 0;
        
        long ret = returnCode - NSAlertFirstButtonReturn;
        if(ret == b1) {
            event.intval = 1;
        } else if(ret == b2) {
            event.intval = 2;
        }
        
        NSString *value = nil;
        if(textfield) {
            value = textfield.stringValue;
            event.eventdata = (void*)value.UTF8String;
            event.eventdatatype = UI_EVENT_DATA_STRING;
        }
        
        if(callback) {
            callback(&event, userdata);
        }
    }];
    
}

mercurial