D言語からObjective-CとCocoaAPIを使いたい

swin2 : swin の改版です

Code を分けました。Menu の Services 及び Preferences (環境設定) window、Web Help を設けました。

NSAlert で suppressionButton を実装しました。

コマンドラインからの文字列を表示します。

swin2.png

サンプルコード

Powered by Prism

swin2/dub.json

{
    "authors": ["hidhok"],
    "description": "A D/Objective-C Cocoa application.",
    "name": "swin2",
    "dflags": ["-L-framework", "-LCocoa"],
    "sourceFiles": ["../cocoa/window",
                    "../cocoa/control",
                    "../cocoa/menu"]
}               
swin2/source/app.d

/**
 *	  swin2/source/app.d       Version 0.1.3
 */
module swin2.main;
import core.attribute : optional, selector;
import std.stdio;
import std.conv : to;
import std.process : executeShell;
import cocoa.window;
import cocoa.control;
import cocoa.menu;
import swin2.view;

string appName;
string versionNo = "0.1.3";
string helpMessage = "CocoaAPIを使用して、\n" ~
        "Labelを D言語で表示します。\nコマンドラインからの文字列も表示できます。";

NSWindow mainWin, prefWin, subWin;
SubWindowController prefCtrler;
bool prefWinFlag = false;
NSControlStateValue alertSupBtnState = state.Off;

void main(string[] args) {
    auto delegate_ = AppDelegate.alloc.init;
    NSApp.delegate_ = cast(void*) delegate_;
    NSApp.activationPolicy = NSAppActivationPolicy.regular;
    cmdLineProcess = args;
    NSApp.run;
}

extern (Objective-C)
class AppDelegate : NSObject {
    override static AppDelegate alloc() @selector("alloc");
    override typeof(this) init() @selector("init");
    bool applicationShouldTerminateAfterLastWindowClosed(
            NSNotification notification) @selector(
            "applicationShouldTerminateAfterLastWindowClosed:") {
        // return alert("終了の確認", "アプリを終了しますか");
        if (alertSupBtnState == state.On)
            return true;
        else
            return alert("アプリを終了しますか", "Cancelでメインウインドに復帰します");
    }
    void applicationDidFinishLaunching(NSNotification notification) 
            @selector("applicationDidFinishLaunching:") {
		buildMainWindow;
		buildContents;
    }
    void aboutPanel() @selector("aboutPanel") {
        NSMutableDictionary options = NSMutableDictionary.dictionary;
        // NSImage img = NSImage.name("AppIcon.icns".toNs);
        // options.setObjKey(img, "ApplicationIcon".toNs);
        options.setObjKey(versionNo.toNs, "Version".toNs);
        options.setObjKey("horkew.la.coocan.jp".toNs, "Copyright".toNs);
        options.setObjKey(versionNo.toNs, "ApplicationVersion".toNs);
        NSApplication.shared_.aboutPanelOptions(options.copy);
    }
    void showHelp() @selector("showHelp") {
        dialog("Help", helpMessage);
    }
    void showWebHelp() @selector("showWebHelp") {
        executeShell("open http://horkew.la.coocan.jp/D+CocoAPI/help.html");
    }
    void preferences() @selector("preferences") {
        if (!prefWinFlag) {
            prefWin = subWindow("環境設定", nRect(0, 0, 300, 200));
            prefCtrler = SubWindowController.alloc.init(prefWin);
            prefWinFlag = true;
            prefCtrler.showWindow = prefWin;
        }
    }
    void toolInstruments() @selector("toolInstruments") {
        executeShell("open -a instruments");
    }
    void systemPreferences() @selector("systemPreferences") {
        executeShell("open -a 'System Preferences'");
    }
} 

extern (Objective-C)
class SubWindowController : NSWindowController, NSWindowDelegate {
    override static SubWindowController alloc() @selector("alloc");
    override SubWindowController init(NSWindow) @selector("initWithWindow:");
    override void showWindow(NSWindow win) @selector("showWindow:") {
        win.delegate_  = this;
        win.makeKeyAndOrderFront = null;
    }
    /*   NSWindowDelegate   */
    void winWillClose(NSNotification) @selector("windowWillClose:") {
        prefWinFlag = false;
    }
    void winDidResize(NSNotification) @selector("windowDidResize:");
}

NSWindow subWindow(string titleStr, NSRect winRect) {
    immutable style = NSWindowStyleMask.titled | NSWindowStyleMask.closable;
    subWin = NSWindow.alloc.init(winRect, style, backing.buffered, false);
    subWin.title = titleStr.toNs;
    subWin.center;
    sView = SubView.alloc.init;
    subWin.contentView = sView;
    // sView.bgColor = colorGray(0.9); // no property
    return subWin;
} 

void buildMainWindow() {
    appName = NSProcessInfo.processInfo.processName.toDs;
    NSApp.menu = mainMenu(appName);
    NSRect w_rect = NSMakeRect(100, 700, 300, 200);
    immutable w_style = NSWindowStyleMask.titled | 
                        NSWindowStyleMask.closable | 
                        NSWindowStyleMask.resizable | 
                        NSWindowStyleMask.miniaturizable;
    mainWin = NSWindow.alloc.init(w_rect, w_style, backing.buffered, false);
    mainWin.title = (appName ~ "  (D言語)").toNs;
    drView = DrawView.alloc.init;
    // drView.bgColor = NSColor.white; // no property
    mainWin.contentView = drView;
    mainWin.minSize = NSMakeSize(230, 120);
    mainWin.makeKeyAndOrderFront = null;
    NSApp.activateIgnoringOtherApps = true;
}

bool alert(string message, string information) {
    NSAlert al = NSAlert.alloc.init;
    al.addButton("OK".toNs);
    al.addButton("Cancel".toNs);
    al.messageText(message.toNs);
    al.information(information.toNs);
    al.style = alertStyle.critical;
    if (alertSupBtnState == state.Off) {    
        al.showSupBtn = true;
        al.supBtn.title = "次回からこのメッセージを表示しない".toNs;
    } else {
        al.showSupBtn = false;
    }
    
    uint alResult = al.run;

    if (al.supBtn.state == state.On) {
        alertSupBtnState = state.On; 
    }
    bool returnVal;
    switch(alResult) {
    case AlertReturn.OK:
        returnVal = true;
        break;
    case AlertReturn.Cancel:
        returnVal = false;
        buildMainWindow;  // 
        buildContents; //
        break;
    default:
        returnVal = false;
        break;
    }
    al.release;
    return returnVal;
}               
swin2/source/view.d

/** 
 *    swin2/source/view.d
 */
module swin2.view;
import core.attribute : optional, selector;
import std.stdio;
import std.conv : to;
import cocoa.window;
import cocoa.control;
import swin2.main;

DrawView drView;
SubView sView;

string[] argStr;
string text = "Hello World!";
string urlStr = "http://horkew.la.coocan.jp/D+CocoAPI/rainbow.jpg";

void buildContents() {
    Label label = Label.alloc.init(NSMakeRect(25, 25, 250, 150)); 
    NSFont font = NSFont.nameSize("Times New Roman".toNs, 32);
    label.attrStr = text.toAttrStr(font, NSColor.blue);
    label.setValues;
}

void cmdLineProcess(string[] args) {
    if (args.length > 1) {
        argStr = args;
        text = args[1];
    }  
}

extern (Objective-C)
class DrawView : NSView {
    override static DrawView alloc() @selector("alloc");
    override DrawView init() @selector("init");
    override DrawView init(NSRect) @selector("initWithFrame:");
    override void drawRect(NSRect) @selector("drawRect:");
    override void keyDown(NSEvent event) @selector("keyDown:") { /* */ }
    override bool acceptsFirstResponder() @selector("acceptsFirstResponder") {
        return true;
    }
}

extern (Objective-C)
class Label : NSTextField {
    override static Label alloc() @selector("alloc");
    override Label init() @selector("init");
    override Label init(NSRect) @selector("initWithFrame:");
    void setValues() @selector("setValues") {
        this.editable = false;
        this.selectable = false;
        this.bordered = false;
        this.drawsBg = true;
        this.bgColor = colorGray(0.98);
        this.resizeMask = ResizeMask.Width | ResizeMask.Height;
        drView.subview = this;
    }
}

NSColor colorGray(double e) {
    return NSColor.rgba(e, e, e, 1);
}

/* KeyboardEvent.code values */
uint kVK_Escape = 0x0035; // = 53

extern (Objective-C)
class SubView : NSView {
    override static SubView alloc() @selector("alloc");
    override SubView init() @selector("init");
    override SubView init(NSRect) @selector("initWithFrame:");
    override void drawRect(NSRect rect) @selector("drawRect:");
    override void keyDown(NSEvent event) @selector("keyDown:") {
        if (event.keyCode == kVK_Escape)
            subWin.close;
    }
    override bool acceptsFirstResponder() @selector("acceptsFirstResponder") {
        return true;
    }
}               
cocoa/window.d
cocoa/control.d
cocoa/menu.d