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

timer

Web 上の Objective-C のコードを真似て作りました。

timer.png

サンプルコード

Powered by Prism

timer/dub.json

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

/**
 *  timer/source/app.d     Version 0.0.1        Timer App
 */
module timer.main;
import core.attribute : optional, selector;
import std.stdio;
import cocoa.window;
import cocoa.menus;
import timer.view;

string appName;
string versionNo = "0.0.1";
string helpMessage =  "CocoaAPIを使用して、簡単なCocoa Appを\nD言語で表示しています。";

NSWindow win;
ViewController vCtrlr;
NSRect wRect = NSMakeRect(0, 0, 200, 100);

void main() {
    NSApp.delegate_ = cast(void*) AppDelegate.alloc.init;
    NSApp.activationPolicy = NSAppActivationPolicy.Regular;
    NSApp.run;
}

void buildWindow() {
    appName = NSProcessInfo.processInfo.processName.toDs;
    NSApp.menu = miniMenu(appName);
    immutable wStyle = WinStyle.Titled | WinStyle.Closable;
    win = NSWindow.alloc.init(wRect, wStyle, backing.Buffered, false);
    win.title = (appName ~ "  (D言語)").toNs;
    dView = DrawView.alloc.init;
    win.contentView = dView;
    vCtrlr = ViewController.alloc.init;
    vCtrlr.view.subview = dView;
    win.center;
    win.makeKeyAndOrderFront = null;
    NSApp.activateIgnoringOtherApps = true;
}

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 true;
    }
    void applicationDidFinishLaunching(NSNotification notification) 
            @selector("applicationDidFinishLaunching:") {
        buildWindow;
        buildContents;
    }
    void aboutPanel() @selector("aboutPanel") {
        dialog(appName, "Version " ~ versionNo);
    }
    void showHelp() @selector("showHelp") {
        dialog("Help", helpMessage);
    }
} 

extern (Objective-C) 
class ViewController : NSViewController {
    override static ViewController alloc() @selector("alloc");
    override ViewController init() @selector("init");
    override void loadView() @selector("loadView") { 
        // printf("loadView\n"); 
    }
    override void viewDidLoad() @selector("viewDidLoad") { 
        printf("viewDidLoad\n"); 
    }
}               
timer/source/view.d

/**  
 *     timer/source/view.d  
 */  
module timer.view;
import core.attribute : optional, selector;
import std.stdio;
import std.format;
import cocoa.window;
import cocoa.control;
import cocoa.datetime;
import timer.main;

DrawView dView;
string timeString;
NSTimer tm;
Label label;
Button btn1, btn2;
int cnt = 0;
NSRect lRect = NSMakeRect(0, 40, 200, 50);
NSRect b1Rect = NSMakeRect(10, 10, 100, 25);
NSRect b2Rect = NSMakeRect(120, 10, 70, 25);

void buildContents() {
    timeString = format("    %.1f", 0.0);
    label = Label.alloc.init(lRect);
    NSFont font = NSFont.nameSize("Menlo Regular".toNs, 40); // 
    label.attrStr = timeString.toAttrStr(font, NSColor.blue);
    label.setValues;
    btn1 = Button.alloc.init(b1Rect);
    btn1.setButton("Start", NSColor.teal, "onClickedButton");
    btn2 = Button.alloc.init(b2Rect);
    btn2.setButton("Reset", NSColor.green, "resetButton");
}

extern (Objective-C)
class DrawView : NSView {
    override static DrawView alloc() @selector("alloc");
    override DrawView init() @selector("init");
    override void drawRect(NSRect rectFrame) @selector("drawRect:") {
        NSColor.white.set;
        NSRectFill(rectFrame);
    }
}

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

extern (Objective-C)
class Button : NSButton {
    override static Button alloc() @selector("alloc");
    override Button init(NSRect) @selector("initWithFrame:");
    void setButton(string title, NSColor color, string action)
                @selector("setButtonTitle:color:action:") {
        this.title = title;
        this.bezelStyle = BezelStyle.Push;
        this.bezelColor = color;
        this.bordered = true;
        this.target = this;
        this.action_ = action;
        dView.subview = this;
    }
    void onClickedButton() @selector("onClickedButton") {
        if (btn1.title.toDs == "Start") {
            tm = btn1.startTimer("onTimerTick", 0.1);    
            NSRunLoop.main.add(tm, "NSDefaultRunLoopMode".toNs);
            btn1.title = "Stop";
            btn1.bezelColor = NSColor.red;
        } else {
            tm.invalidate;
            btn1.title = "Start";
            btn1.bezelColor = NSColor.teal;
        }
    }
    void resetButton() @selector("resetButton") {
        if (btn1.title.toDs == "Start") {
            timeString = format("    %.1f", 0.0);
            cnt = 0;
            this.reDraw(timeString);
        }
    }
    void onTimerTick() @selector("onTimerTick") {
        timeString = format("%7.1f", ++cnt / 10.0);
        this.reDraw(timeString);
    }
    void reDraw(string str) @selector("reDraw:") {
        NSFont font = NSFont.nameSize("Menlo Regular".toNs, 40); // 
        label.attrStr = str.toAttrStr(font, NSColor.blue);
        dView.needsDisplay = true;
    }
}

NSTimer startTimer(NSObject oj, string s, NSTimeInterval ti) {
    return NSTimer.scheduledTimer(ti, oj, sel_registerName(s.toCs), null, true);
}               
cocoa/datetime.d
cocoa/window.d
cocoa/control.d
cocoa/menus.d