D言語からObjective-CとCocoaAPIを使いたい
画像の拡大縮小と回転を行いたい
zoom.d に図形の回転を加えました。frameRotation を使用しました。

サンプルコード
Powered by Prism
rotate/dub.json
{
"authors": ["hidhok"],
"description": "A D/Objective-C Cocoa application.",
"name": "rotate",
"dflags": ["-L-framework", "-LCocoa"],
"sourceFiles": ["../cocoa/window",
"../cocoa/control",
"../cocoa/menus"]
}
rotate/source/app.d
/**
* rotate/source/app.d Version 0.0.2 rotation Test
*/
module rotate.main;
import core.attribute : optional, selector;
import std.stdio;
import std.format;
import std.conv : to;
import std.math;
import cocoa.window;
import cocoa.control;
import cocoa.menus;
string appName;
string versionNo = "0.0.2";
string helpMessage = "CocoaAPIを使用して 画像の回転 を、\nD言語で表示してみました。";
NSWindow win;
NSScrollView scrView;
BezierView bzView;
Label angleVal, zoomVal;
string pathType, dashType;
double scaleFactor = 1, angle = 0;
void main() {
auto delegate_ = AppDelegate.alloc.init;
NSApp.delegate_ = cast(void*) delegate_;
NSApp.activationPolicy = NSAppActivationPolicy.regular;
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 true;
}
void applicationDidFinishLaunching(NSNotification notification)
@selector("applicationDidFinishLaunching:") {
buildWindow;
buildContents;
}
void aboutPanel() @selector("aboutPanel") {
dialog(appName, "Version " ~ versionNo);
}
void showHelp() @selector("showHelp") {
dialog("Help", helpMessage);
}
}
void buildWindow() {
appName = NSProcessInfo.processInfo.processName.toDs;
NSApp.menu = miniMenu(appName);
NSRect w_rect = nRect(100, 500, 300, 450);
immutable w_style = NSWindowStyleMask.titled |
NSWindowStyleMask.closable |
NSWindowStyleMask.resizable |
NSWindowStyleMask.miniaturizable;
win = NSWindow.alloc.init(w_rect, w_style, backing.buffered, false);
win.title = (appName ~ " (D言語)").toNs;
win.minSize = NSSize(300, 478);
ViewController vCtrler = ViewController.alloc.init;
vCtrler.view.subview = win.contentView;
win.delegate_ = vCtrler;
win.makeKeyAndOrderFront = null;
NSApp.activateIgnoringOtherApps = true;
}
extern (Objective-C)
class ViewController : NSViewController, NSWindowDelegate {
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");
}
void winDidResize(NSNotification) @selector("windowDidResize:") {
setToCenter(scaleFactor, angle);
bzView.needsDisplay = true;
}
}
void buildContents() {
/* NSScrollView & NSClipView & BezierView */
scrView = NSScrollView.alloc.init(nRect(10, 160, 280, 280));
scrView.resizeMask = ResizeMask.Width | ResizeMask.Height;
win.contentView.subview = scrView;
bzView = BezierView.alloc.init(nRect(0, 0, 280, 280));
NSClipView cpView = NSClipView.alloc.init;
scrView.contentView = cpView;
cpView.subview = bzView;
/* Box */
Box box1, box2;
box1 = Box.alloc.init(nRect(10, 60, 135, 88));
box2 = Box.alloc.init(nRect(155, 60, 135, 88));
box1.setBoxTitle("Path Type");
box2.setBoxTitle("Dash Type");
/* Radio Button */
RadioBtn[6] rb;
string[6] btnTitle = ["Line", "Square", "Oval", "Solid", "10-10", "8-2-8"];
foreach (i; 0 .. 3) {
int j = i + 3;
rb[i] = RadioBtn.alloc.init(nRect(0, 40 - i * 20, 100, 20));
rb[j] = RadioBtn.alloc.init(nRect(0, 40 - i * 20, 100, 20));
rb[i].setRadioBtn(btnTitle[i], box1, "onRadioBtnBox1");
rb[j].setRadioBtn(btnTitle[j], box2, "onRadioBtnBox2");
}
/* Initial value setting */
pathType = "Square";
rb[1].state = StateValue.On;
rb[3].state = StateValue.On;
/* Slider & sliderLabel */
Slider sliderAngle = Slider.alloc.init(nRect(98, 25, 190, 30));
Slider sliderZoom = Slider.alloc.init(nRect(98, 0, 190, 30));
sliderAngle.action_ = "sliderAngleAction";
sliderZoom.action_ = "sliderZoomAction";
sliderAngle.setInitValues(0, 0, 359.999);
sliderZoom.setInitValues(1, 0.01, 5);
Label titleAngle = Label.alloc.init(nRect(12, 30, 50, 20));
Label titleZoom = Label.alloc.init(nRect(12, 5, 50, 20));
titleAngle.text = "Angle";
titleZoom.text = "Zoom ✕";
angleVal = Label.alloc.init(nRect(55, 30, 45, 20));
zoomVal = Label.alloc.init(nRect(60, 5, 45, 20));
angleVal.text = format("%5.2f", sliderAngle.value);
zoomVal.text = format("%5.2f", sliderZoom.value);
bzView.needsDisplay = true;
}
extern (Objective-C)
class Box : NSBox {
override static Box alloc() @selector("alloc");
override Box init(NSRect) @selector("initWithFrame:");
void setBoxTitle(string title) @selector("setBoxTitle:") {
this.title = title;
win.contentView.subView = this;
}
}
extern (Objective-C)
class RadioBtn : NSButton, Res {
override static RadioBtn alloc() @selector("alloc");
override RadioBtn init(NSRect) @selector("initWithFrame:");
bool respondsToSelector(SEL) @selector("respondsToSelector:");
void setRadioBtn(string title, Box box, string action)
@selector("setRadioBtn:box:action:") {
this.title = title;
this.type = NSButtonType.Radio;
this.target = this;
this.action_ = action;
box.subview = this;
}
void onRadioBtnBox1() @selector("onRadioBtnBox1") {
pathType = this.title.toDs;
bzView.needsDisplay = true;
}
void onRadioBtnBox2() @selector("onRadioBtnBox2") {
dashType = this.title.toDs;
bzView.needsDisplay = true;
}
}
extern (Objective-C)
class Slider : NSSlider {
override static Slider alloc() @selector("alloc");
override Slider init(NSRect) @selector("initWithFrame:");
void setInitValues(double start, double min, double max)
@selector("setInitValues:min:max:") {
this.resizeMask = ResizeMask.Width;
this.target = this;
this.continuous = true;
this.maxValue = max;
this.minValue = min;
this.value = start;
this.sliderType = NSSliderType.Linear;
this.vertical = false;
win.contentView.subview = this;
}
void sliderAngleAction() @selector("sliderAngleAction") {
angle = this.value;
angleVal.text = format("%5.2f", angle);
bzView.setAngle(angle);
bzView.needsDisplay = true;
}
void sliderZoomAction() @selector("sliderZoomAction") {
scaleFactor = this.value;
zoomVal.text = format("%5.2f", scaleFactor);
bzView.setZoom(scaleFactor);
bzView.needsDisplay = true;
}
}
extern (Objective-C)
class Label : NSTextField {
override static Label alloc() @selector("alloc");
override Label init(NSRect) @selector("initWithFrame:");
void text(string labelStr) @selector("setVAluesText:") {
this.bgColor = NSColor.clear;
this.bordered = false;
this.editable = false;
this.selectable = false;
this.str = labelStr;
win.contentView.subview = this;
}
}
extern (Objective-C)
class BezierView : NSView {
override static BezierView alloc() @selector("alloc");
override BezierView init() @selector("init");
override BezierView init(NSRect) @selector("initWithFrame:");
override void drawRect(NSRect r) @selector("drawRect:") {
double bx = 140, by = 140, ra = 140/3;
NSBezierPath path;
path.lineWidth = 20;
NSColor.red.stroke;
switch (pathType) {
case "Line":
path = NSBezierPath.bezierPath;
path.moveToPoint(NSPoint(bx-ra, bx-ra));
path.lineToPoint(NSPoint(bx+ra, by+ra));
break;
case "Square":
path = NSBezierPath.rect(nRect(bx-ra, by-ra, ra*2, ra*2));
break;
case "Oval":
path = NSBezierPath.oval(nRect(bx-ra*3/2, by-ra, ra*3, ra*2));
break;
default:
break;
}
switch (dashType) {
case "Solid":
break;
case "10-10":
path.dashLine([10, 10]);
break;
case "8-2-8":
path.dashLine([8, 2, 8]);
break;
default:
break;
}
path.stroke;
}
void setZoom(double sf) @selector("setZoom:") {
NSRect frame = this.frame;
NSRect bounds = this.bounds;
frame.size.width = bounds.size.width * sf;
frame.size.height = bounds.size.height * sf;
this.frame = frame;
this.bounds = bounds;
setToCenter(sf, angle);
}
void setAngle(double a) @selector("setAngle:") {
this.frameRotation(a);
setToCenter(scaleFactor, a);
}
}
void setToCenter(double sf, double ag) {
double cx, cy, ox, oy;
cx = scrView.frame.size.width / 2;
cy = scrView.frame.size.height / 2;
double radian = PI * (45 + ag) / 180;
ox = cx - 140 * sf * 1.4142 * cos(radian);
oy = cy - 140 * sf * 1.4142 * sin(radian);
bzView.frameOrigin = NSPoint(ox, oy);
}
NSRect nRect(double x, double y, double w, double h) {
return NSMakeRect(x, y, w, h);
}
cocoa/window.d
cocoa/control.d
cocoa/menus.d
- Log
- 2024-06-07 修正しました
- 2024-01-20 upload