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

Quartz2D Test Program

Quart2D (Quartz View) のグラフィックを D/Cocoa で動かしてみました。

プログラムソースは、Apple Documentation Archive : Quartz 2D Programming Guideです。

QuartzView Image

サンプルコード

Powered by Prism

quartzview/dub.json

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

/**
 *  quartzview/source/app.d     Version 0.0.3        Quartz View Sample Program
 *    Apple Documentation Archive : Quartz 2D Programming Guide
 */
module quartzview.main;
import core.attribute : optional, selector;
import std.stdio;
import cocoa.window;
import cocoa.control;
import cocoa.menus;
import quartzview.view;

string appName;
string versionNo = "0.0.3";
string helpMessage =  "簡単な Quartz View を\nCocoaAPI " 
                        ~ "を使用して、\nD言語で表示しています。";

NSWindow win;
// ViewController vCtrl;
QuartzView qView;

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

void buildMainWindow() {
    appName = NSProcessInfo.processInfo.processName.toDs;
    NSApp.menu = miniMenu(appName);
    NSRect wRect = nR(0, 0, 300, 300);
    immutable wStyle = WinStyle.Titled | 
                       WinStyle.Closable | 
                       WinStyle.Resizable | 
                       WinStyle.Miniaturizable;
    win = NSWindow.alloc.init(wRect, wStyle, NSBacking.Buffered, false);
    win.title = (appName ~ "  (D言語)").toNs;
    // vCtrl = ViewController.alloc.init;
    qView = QuartzView.alloc.init;
    // vCtrl.view.subview = qView;
    win.contentView = qView;
    // win.bgColor = NSColor.white;
    win.minSize = nS(150, 100);
    win.moveTop = nP(150, 900);
    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:") {
        buildMainWindow;
    }
    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"); 
    }
} */            
quartzview/source/view.d

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

extern (Objective-C)
class QuartzView : NSView {
    override static QuartzView alloc() @selector("alloc");
    override QuartzView init() @selector("init");
    override QuartzView init(NSRect) @selector("initWithFrame:");
    void draw(NSRect r) @selector("drawRect:") {
        NSColor.white.set;
        NSRectFill(r);
       
        CGContextRef aContext = NSGraphicsContext.current.cgContext;
        /*
        CGContextSetRGBFillColor(aContext, 1, 0, 0, 1);
        CGContextFillRect(aContext, CGRectMake(10, 10, 200, 100));
        CGContextSetRGBFillColor(aContext, 0, 0, 1, 0.5);
        CGContextFillRect(aContext, CGRectMake(10, 10, 100, 200));
        */
        aContext.setRGBFillColor( 1, 0, 0, 1);
        aContext.fillRect = CGRectMake(10, 10, 200, 100);
        aContext.setRGBFillColor(0, 0, 1, 0.5);
        aContext.fillRect = CGRectMake(10, 10, 100, 200);
    }
}                
cocoa/graphics.d

/**
 *    cocoa/graphics.d         Version 0.0.2
 */
module cocoa.graphics;
import core.attribute : optional, selector;
import std.conv : to;
import cocoa.window;
import cocoa.control;

struct CGContext;
alias CGContextRef = CGContext*;

extern (Objective-C)
extern class NSGraphicsContext : NSObject {
    static NSGraphicsContext graphicsContextWithAttributes(NSDictionary)
        @selector("graphicsContextWithAttributes:");
    static NSGraphicsContext graphicsContextWithCGContext(CGContextRef, bool)
        @selector("graphicsContextWithCGContext:flipped:");
    static NSGraphicsContext currentContext() @selector("currentContext");
    static NSGraphicsContext current() @selector("currentContext");
    CGContextRef cgContext() @selector("CGContext");
    static void saveGraphicsState() @selector("saveGraphicsState");
    static void restoreGraphicsState() @selector("restoreGraphicsState");
}

extern(C) void CGContextFillRect(CGContextRef c, CGRect rect);
extern(C) void CGContextSetRGBFillColor(CGContextRef c, 
    CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); 

void fillRect(CGContextRef c, CGRect rect) {
    return CGContextFillRect(c, rect);
}

void setRGBFillColor(CGContextRef c, CGFloat red, 
            CGFloat green, CGFloat blue, CGFloat alpha) {
    return CGContextSetRGBFillColor(c, red, green, blue, alpha);
}

extern (Objective-C)
extern class NSGradient : NSObject {
    override static NSGradient alloc() @selector("alloc");
    NSGradient initColorsLocations(NSColor, ...) 
        @selector("initWithColorsAndLocations:...");
    NSGradient initStartColor(NSColor, NSColor) 
        @selector("initWithStartingColor:endingColor:");
    void drawInBezierPath(NSBezierPath, CGFloat) 
        @selector("drawInBezierPath:angle:");
    void drawFromCenter(NSPoint, CGFloat, NSPoint, CGFloat, NSUInteger) 
        @selector("drawFromCenter:radius:toCenter:radius:options:");
}

enum NSGradientDraws: size_t {  // NSGradientDrawingOptions
    None         = 0,
    BeforeStart  = 1 << 0,      // NSGradientDrawsBeforeStartingLocation
    AfterEnd     = 1 << 1       // NSGradientDrawsAfterEndingLocation
}               
cocoa/window.d
cocoa/control.d
cocoa/menus.d