forked from andlabs/ui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patharea_darwin.m
236 lines (199 loc) · 6.68 KB
/
area_darwin.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
// 13 may 2014
#include "objc_darwin.h"
#include "_cgo_export.h"
#import <Cocoa/Cocoa.h>
#define toNSEvent(x) ((NSEvent *) (x))
#define toNSView(x) ((NSView *) (x))
#define toNSObject(x) ((NSObject *) (x))
#define toNSTextField(x) ((NSTextField *) (x))
#define toNSInteger(x) ((NSInteger) (x))
#define fromNSInteger(x) ((intptr_t) (x))
#define toNSUInteger(x) ((NSUInteger) (x))
#define fromNSUInteger(x) ((uintptr_t) (x))
@interface goAreaView : NSView <NSTextFieldDelegate> {
@public
void *goarea;
NSTrackingArea *trackingArea;
}
@end
@implementation goAreaView
- (id)initWithFrame:(NSRect)r
{
self = [super initWithFrame:r];
if (self)
[self retrack];
return self;
}
- (void)drawRect:(NSRect)cliprect
{
struct xrect rect;
rect.x = (intptr_t) cliprect.origin.x;
rect.y = (intptr_t) cliprect.origin.y;
rect.width = (intptr_t) cliprect.size.width;
rect.height = (intptr_t) cliprect.size.height;
areaView_drawRect(self, rect, self->goarea);
}
- (BOOL)isFlipped
{
return YES;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
// this will have the Area receive a click that switches to the Window it is in from another one
- (BOOL)acceptsFirstMouse:(NSEvent *)e
{
return YES;
}
- (void)retrack
{
self->trackingArea = [[NSTrackingArea alloc]
initWithRect:[self bounds]
// this bit mask (except for NSTrackingInVisibleRect, which was added later to prevent events from being triggered outside the visible area of the Area) comes from https://github.com/andlabs/misctestprogs/blob/master/cocoaviewmousetest.m (and I wrote this bit mask on 25 april 2014) and yes I know it includes enter/exit even though we don't watch those events; it probably won't really matter anyway but if it does I can change it easily
options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag | NSTrackingInVisibleRect)
owner:self
userInfo:nil];
[self addTrackingArea:self->trackingArea];
}
- (void)updateTrackingAreas
{
[self removeTrackingArea:self->trackingArea];
[self->trackingArea release];
[self retrack];
}
#define event(m, f) \
- (void)m:(NSEvent *)e \
{ \
f(self, e, self->goarea); \
}
event(mouseMoved, areaView_mouseMoved_mouseDragged)
event(mouseDragged, areaView_mouseMoved_mouseDragged)
event(rightMouseDragged, areaView_mouseMoved_mouseDragged)
event(otherMouseDragged, areaView_mouseMoved_mouseDragged)
event(mouseDown, areaView_mouseDown)
event(rightMouseDown, areaView_mouseDown)
event(otherMouseDown, areaView_mouseDown)
event(mouseUp, areaView_mouseUp)
event(rightMouseUp, areaView_mouseUp)
event(otherMouseUp, areaView_mouseUp)
#define retevent(m, f) \
- (BOOL)m:(NSEvent *)e \
{ \
return f(self, e, self->goarea); \
}
retevent(doKeyDown, areaView_keyDown)
retevent(doKeyUp, areaView_keyUp)
retevent(doFlagsChanged, areaView_flagsChanged)
// seems to be triggered when the user would have finished editing the NSTextField anyway according to the system's rules on that (at least on Mountain Lion)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
areaTextFieldDismissed(self->goarea);
[toNSObject(object) removeObserver:self forKeyPath:@"firstResponder"];
}
@end
Class getAreaClass(void)
{
return [goAreaView class];
}
id newArea(void *goarea)
{
goAreaView *a;
a = [[goAreaView alloc] initWithFrame:NSZeroRect];
a->goarea = goarea;
return (id) a;
}
BOOL drawImage(void *pixels, intptr_t width, intptr_t height, intptr_t stride, intptr_t xdest, intptr_t ydest)
{
unsigned char *planes[1]; // NSBitmapImageRep wants an array of planes; we have one plane
NSBitmapImageRep *bitmap;
BOOL success;
planes[0] = (unsigned char *) pixels;
bitmap = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:planes
pixelsWide:toNSInteger(width)
pixelsHigh:toNSInteger(height)
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
// NSCalibratedRGBColorSpace changes the colors; let's not
// thanks to JtRip in irc.freenode.net/#macdev
colorSpaceName:NSDeviceRGBColorSpace
bitmapFormat:0 // this is where the flag for placing alpha first would go if alpha came first; the default is alpha last, which is how we're doing things (otherwise the docs say "Color planes are arranged in the standard order—for example, red before green before blue for RGB color."); this is also where the flag for non-premultiplied colors would go if we used it (the default is alpha-premultiplied)
bytesPerRow:toNSInteger(stride)
bitsPerPixel:32];
success = [bitmap drawInRect:NSMakeRect((CGFloat) xdest, (CGFloat) ydest, (CGFloat) width, (CGFloat) height)
fromRect:NSZeroRect // draw whole image
operation:NSCompositeSourceOver
fraction:1.0
respectFlipped:YES
hints:nil];
[bitmap release];
return success;
}
// can't include the header file with these from the Go side since it's an Objective-C header file; keep them here to be safe
const uintptr_t cNSShiftKeyMask = (uintptr_t) NSShiftKeyMask;
const uintptr_t cNSControlKeyMask = (uintptr_t) NSControlKeyMask;
const uintptr_t cNSAlternateKeyMask = (uintptr_t) NSAlternateKeyMask;
const uintptr_t cNSCommandKeyMask = (uintptr_t) NSCommandKeyMask;
uintptr_t modifierFlags(id e)
{
return fromNSUInteger([toNSEvent(e) modifierFlags]);
}
struct xpoint getTranslatedEventPoint(id area, id e)
{
NSPoint p;
struct xpoint q;
p = [toNSView(area) convertPoint:[toNSEvent(e) locationInWindow] fromView:nil];
q.x = (intptr_t) p.x;
q.y = (intptr_t) p.y;
return q;
}
intptr_t buttonNumber(id e)
{
return fromNSInteger([toNSEvent(e) buttonNumber]);
}
intptr_t clickCount(id e)
{
return fromNSInteger([toNSEvent(e) clickCount]);
}
uintptr_t pressedMouseButtons(void)
{
return fromNSUInteger([NSEvent pressedMouseButtons]);
}
uintptr_t keyCode(id e)
{
return (uintptr_t) ([toNSEvent(e) keyCode]);
}
void areaRepaint(id view, struct xrect r)
{
NSRect s;
s.origin.x = (CGFloat) r.x;
s.origin.y = (CGFloat) r.y;
s.size.width = (CGFloat) r.width;
s.size.height = (CGFloat) r.height;
[toNSView(view) displayRect:s];
}
void areaRepaintAll(id view)
{
[toNSView(view) display];
}
void areaSetTextField(id area, id textfield)
{
goAreaView *a = (goAreaView *) area;
NSTextField *tf = toNSTextField(textfield);
[a addSubview:tf];
}
void areaTextFieldOpen(id area, id textfield, intptr_t x, intptr_t y)
{
goAreaView *a = (goAreaView *) area;
NSTextField *tf = toNSTextField(textfield);
// see TextField.preferredSize() in textfield_darwin.go
[tf sizeToFit];
[tf setFrameSize:NSMakeSize(textfieldWidth, [tf frame].size.height)];
[tf setFrameOrigin:NSMakePoint((CGFloat) x, (CGFloat) y)];
[tf setHidden:NO];
[[tf window] makeFirstResponder:tf];
[[tf window] addObserver:a forKeyPath:@"firstResponder" options:NSKeyValueObservingOptionNew context:NULL];
}