2014-08-05 13:33:25 -05:00
// 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 ) )
2014-08-29 16:43:54 -05:00
# define toNSObject ( x ) ( ( NSObject * ) ( x ) )
2014-08-22 21:32:31 -05:00
# define toNSTextField ( x ) ( ( NSTextField * ) ( x ) )
2014-08-05 13:33:25 -05:00
# define toNSInteger ( x ) ( ( NSInteger ) ( x ) )
# define fromNSInteger ( x ) ( ( intptr_t ) ( x ) )
# define toNSUInteger ( x ) ( ( NSUInteger ) ( x ) )
# define fromNSUInteger ( x ) ( ( uintptr_t ) ( x ) )
2014-08-23 18:29:17 -05:00
@ interface goAreaView : NSView < NSTextFieldDelegate > {
2014-08-05 13:33:25 -05:00
@ public
void * goarea ;
NSTrackingArea * trackingArea ;
}
@ end
2014-08-11 10:44:55 -05:00
@ implementation goAreaView
2014-08-05 13:33:25 -05:00
- ( 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 )
2014-08-21 09:19:08 -05:00
# 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 )
2014-08-05 13:33:25 -05:00
2014-08-29 16:55:27 -05:00
// 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 )
2014-08-29 16:43:54 -05:00
- ( void ) observeValueForKeyPath : ( NSString * ) keyPath ofObject : ( id ) object change : ( NSDictionary * ) change context : ( void * ) context
2014-08-23 18:29:17 -05:00
{
areaTextFieldDismissed ( self -> goarea ) ;
2014-08-29 16:43:54 -05:00
[ toNSObject ( object ) removeObserver : self forKeyPath : @ "firstResponder" ] ;
2014-08-23 18:29:17 -05:00
}
2014-08-05 13:33:25 -05:00
@ end
2014-08-05 13:40:08 -05:00
Class getAreaClass ( void )
2014-08-05 13:33:25 -05:00
{
2014-08-11 10:44:55 -05:00
return [ goAreaView class ] ;
2014-08-05 13:33:25 -05:00
}
id newArea ( void * goarea )
{
2014-08-11 10:44:55 -05:00
goAreaView * a ;
2014-08-05 13:33:25 -05:00
2014-08-11 10:44:55 -05:00
a = [ [ goAreaView alloc ] initWithFrame : NSZeroRect ] ;
2014-08-05 13:33:25 -05:00
a -> goarea = goarea ;
return ( id ) a ;
}
2014-08-10 12:19:42 -05:00
BOOL drawImage ( void * pixels , intptr_t width , intptr_t height , intptr_t stride , intptr_t xdest , intptr_t ydest )
2014-08-05 13:33:25 -05:00
{
unsigned char * planes [ 1 ] ; // NSBitmapImageRep wants an array of planes ; we have one plane
NSBitmapImageRep * bitmap ;
2014-08-10 12:19:42 -05:00
BOOL success ;
2014-08-05 13:33:25 -05:00
planes [ 0 ] = ( unsigned char * ) pixels ;
bitmap = [ [ NSBitmapImageRep alloc ]
initWithBitmapDataPlanes : planes
pixelsWide : toNSInteger ( width )
pixelsHigh : toNSInteger ( height )
bitsPerSample : 8
samplesPerPixel : 4
hasAlpha : YES
isPlanar : NO
2014-08-10 12:19:42 -05:00
// NSCalibratedRGBColorSpace changes the colors ; let ' s not
// thanks to JtRip in irc . freenode . net / # macdev
colorSpaceName : NSDeviceRGBColorSpace
2014-08-05 13:33:25 -05:00
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 ] ;
2014-08-10 12:19:42 -05:00
success = [ bitmap drawInRect : NSMakeRect ( ( CGFloat ) xdest , ( CGFloat ) ydest , ( CGFloat ) width , ( CGFloat ) height )
2014-08-05 13:33:25 -05:00
fromRect : NSZeroRect // draw whole image
operation : NSCompositeSourceOver
fraction : 1.0
respectFlipped : YES
hints : nil ] ;
[ bitmap release ] ;
2014-08-10 12:19:42 -05:00
return success ;
2014-08-05 13:33:25 -05:00
}
2014-08-11 10:52:10 -05:00
// 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 ;
2014-08-05 13:33:25 -05:00
uintptr_t modifierFlags ( id e )
{
return fromNSUInteger ( [ toNSEvent ( e ) modifierFlags ] ) ;
}
struct xpoint getTranslatedEventPoint ( id area , id e )
{
NSPoint p ;
struct xpoint q ;
2014-08-11 10:44:55 -05:00
p = [ toNSView ( area ) convertPoint : [ toNSEvent ( e ) locationInWindow ] fromView : nil ] ;
2014-08-05 13:33:25 -05:00
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 ] ) ;
}
2014-08-21 12:17:35 -05:00
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 ] ;
}
2014-08-09 20:27:28 -05:00
void areaRepaintAll ( id view )
2014-08-05 13:33:25 -05:00
{
[ toNSView ( view ) display ] ;
}
2014-08-22 21:32:31 -05:00
2014-08-23 18:29:17 -05:00
void areaSetTextField ( id area , id textfield )
2014-08-22 21:32:31 -05:00
{
2014-08-23 18:29:17 -05:00
goAreaView * a = ( goAreaView * ) area ;
NSTextField * tf = toNSTextField ( textfield ) ;
2014-08-22 21:32:31 -05:00
2014-08-23 18:29:17 -05:00
[ a addSubview : tf ] ;
2014-08-22 21:32:31 -05:00
}
2014-08-23 18:29:17 -05:00
void areaTextFieldOpen ( id area , id textfield , intptr_t x , intptr_t y )
2014-08-22 21:32:31 -05:00
{
2014-08-23 18:29:17 -05:00
goAreaView * a = ( goAreaView * ) area ;
2014-08-22 21:32:31 -05:00
NSTextField * tf = toNSTextField ( textfield ) ;
2014-08-25 15:07:35 -05:00
// see TextField . preferredSize ( ) in textfield_darwin . go
2014-08-22 21:32:31 -05:00
[ tf sizeToFit ] ;
2014-08-25 15:07:35 -05:00
[ tf setFrameSize : NSMakeSize ( textfieldWidth , [ tf frame ] . size . height ) ] ;
2014-08-22 21:32:31 -05:00
[ tf setFrameOrigin : NSMakePoint ( ( CGFloat ) x , ( CGFloat ) y ) ] ;
[ tf setHidden : NO ] ;
[ [ tf window ] makeFirstResponder : tf ] ;
2014-08-29 16:43:54 -05:00
[ [ tf window ] addObserver : a forKeyPath : @ "firstResponder" options : NSKeyValueObservingOptionNew context : NULL ] ;
2014-08-22 21:32:31 -05:00
}