2014-03-29 22:57:49 -05:00
// 29 march 2014
package ui
import (
"unsafe"
2014-03-30 13:25:01 -05:00
"image"
2014-03-29 22:57:49 -05:00
)
// #cgo LDFLAGS: -lobjc -framework Foundation -framework AppKit
// #include <stdlib.h>
//// #include <HIToolbox/Events.h>
// #include "objc_darwin.h"
import "C"
2014-05-10 13:59:11 -05:00
func makeArea ( parentWindow C . id , alternate bool , s * sysData ) C . id {
2014-05-13 08:33:37 -05:00
area := C . makeArea ( )
2014-04-13 11:52:10 -05:00
area = newScrollView ( area )
addControl ( parentWindow , area )
return area
}
func areaInScrollView ( scrollview C . id ) C . id {
return getScrollViewContent ( scrollview )
}
2014-03-29 22:57:49 -05:00
//export areaView_drawRect
func areaView_drawRect ( self C . id , rect C . struct_xrect ) {
2014-03-30 13:25:01 -05:00
s := getSysData ( self )
// TODO clear clip rect
2014-03-30 13:29:02 -05:00
// rectangles in Cocoa are origin/size, not point0/point1; if we don't watch for this, weird things will happen when scrolling
// TODO change names EVERYWHERE ELSE to match
cliprect := image . Rect ( int ( rect . x ) , int ( rect . y ) , int ( rect . x + rect . width ) , int ( rect . y + rect . height ) )
2014-05-15 18:55:16 -05:00
max := C . frame ( self )
2014-03-30 13:25:01 -05:00
cliprect = image . Rect ( 0 , 0 , int ( max . width ) , int ( max . height ) ) . Intersect ( cliprect )
if cliprect . Empty ( ) { // no intersection; nothing to paint
return
}
i := s . handler . Paint ( cliprect )
C . drawImage (
2014-05-15 21:15:54 -05:00
unsafe . Pointer ( pixelData ( i ) ) , C . intptr_t ( i . Rect . Dx ( ) ) , C . intptr_t ( i . Rect . Dy ( ) ) , C . intptr_t ( i . Stride ) ,
C . intptr_t ( cliprect . Min . X ) , C . intptr_t ( cliprect . Min . Y ) )
2014-03-30 13:25:01 -05:00
}
2014-03-30 16:52:27 -05:00
func parseModifiers ( e C . id ) ( m Modifiers ) {
const (
_NSShiftKeyMask = 1 << 17
_NSControlKeyMask = 1 << 18
_NSAlternateKeyMask = 1 << 19
_NSCommandKeyMask = 1 << 20
)
2014-05-13 08:33:37 -05:00
mods := uintptr ( C . modifierFlags ( e ) )
2014-03-30 16:52:27 -05:00
if ( mods & _NSShiftKeyMask ) != 0 {
m |= Shift
}
if ( mods & _NSControlKeyMask ) != 0 {
// TODO
}
if ( mods & _NSAlternateKeyMask ) != 0 {
m |= Alt
}
if ( mods & _NSCommandKeyMask ) != 0 {
m |= Ctrl
}
return m
}
2014-05-07 18:40:46 -05:00
// TODO pressing both buttons 1 and 3 simultaneously gets turned into button 2; see if we can turn that off for our NSView only
2014-03-30 16:52:27 -05:00
func areaMouseEvent ( self C . id , e C . id , click bool , up bool ) {
var me MouseEvent
s := getSysData ( self )
xp := C . getTranslatedEventPoint ( self , e )
me . Pos = image . Pt ( int ( xp . x ) , int ( xp . y ) )
2014-05-12 10:34:24 -05:00
// for the most part, Cocoa won't geenerate an event outside the Area... except when dragging outside the Area, so check for this
2014-05-15 18:55:16 -05:00
max := C . frame ( self )
2014-05-12 10:34:24 -05:00
if ! me . Pos . In ( image . Rect ( 0 , 0 , int ( max . width ) , int ( max . height ) ) ) {
return
}
2014-03-30 16:52:27 -05:00
me . Modifiers = parseModifiers ( e )
2014-05-13 08:33:37 -05:00
which := uint ( C . buttonNumber ( e ) ) + 1
2014-03-30 16:52:27 -05:00
if which == 3 { // swap middle and right button numbers
which = 2
} else if which == 2 {
which = 3
}
if click && up {
me . Up = which
} else if click {
me . Down = which
2014-05-15 18:55:16 -05:00
me . Count = uint ( C . clickCount ( e ) )
2014-03-30 16:52:27 -05:00
} else {
which = 0 // reset for Held processing below
}
2014-05-10 20:03:04 -05:00
// the docs do say don't use this for tracking since it returns the state now, and mouse move events work by tracking, but as far as I can tell dragging the mouse over the inactive window does n ot generate an event on Mac OS X, so :/ (TODO see what happens when the program is the current one; in my own separate tests no harm was done so eh; also no need for this if tracking doesn't touch dragging)
2014-05-13 08:33:37 -05:00
held := C . pressedMouseButtons ( )
2014-03-30 16:52:27 -05:00
if which != 1 && ( held & 1 ) != 0 { // button 1
me . Held = append ( me . Held , 1 )
}
if which != 2 && ( held & 4 ) != 0 { // button 2; mind the swap
me . Held = append ( me . Held , 2 )
}
if which != 3 && ( held & 2 ) != 0 { // button 3
me . Held = append ( me . Held , 3 )
}
held >>= 3
for i := uint ( 4 ) ; held != 0 ; i ++ {
if which != i && ( held & 1 ) != 0 {
me . Held = append ( me . Held , i )
}
held >>= 1
}
repaint := s . handler . Mouse ( me )
if repaint {
2014-05-15 18:55:16 -05:00
C . display ( self )
2014-03-30 16:52:27 -05:00
}
}
2014-05-07 18:40:46 -05:00
//export areaView_mouseMoved_mouseDragged
2014-05-13 08:33:37 -05:00
func areaView_mouseMoved_mouseDragged ( self C . id , e C . id ) {
2014-05-10 20:03:04 -05:00
// for moving, this is handled by the tracking rect stuff above
2014-05-10 13:31:22 -05:00
// for dragging, if multiple buttons are held, only one of their xxxMouseDragged: messages will be sent, so this is OK to do
2014-03-30 16:52:27 -05:00
areaMouseEvent ( self , e , false , false )
}
2014-05-07 18:40:46 -05:00
//export areaView_mouseDown
2014-05-13 08:33:37 -05:00
func areaView_mouseDown ( self C . id , e C . id ) {
2014-03-30 16:52:27 -05:00
areaMouseEvent ( self , e , true , false )
}
//export areaView_mouseUp
2014-05-13 08:33:37 -05:00
func areaView_mouseUp ( self C . id , e C . id ) {
2014-03-30 16:52:27 -05:00
areaMouseEvent ( self , e , true , true )
}
2014-05-13 08:33:37 -05:00
func sendKeyEvent ( self C . id , e C . id , ke KeyEvent ) bool {
2014-03-30 18:53:44 -05:00
s := getSysData ( self )
handled , repaint := s . handler . Key ( ke )
if repaint {
2014-05-15 18:55:16 -05:00
C . display ( self )
2014-03-30 18:53:44 -05:00
}
2014-05-13 08:33:37 -05:00
return handled
2014-03-30 18:53:44 -05:00
}
2014-05-13 08:33:37 -05:00
func areaKeyEvent ( self C . id , e C . id , up bool ) bool {
2014-03-30 18:53:44 -05:00
var ke KeyEvent
2014-05-13 08:33:37 -05:00
keyCode := uintptr ( C . keyCode ( e ) )
2014-03-30 18:53:44 -05:00
ke , ok := fromKeycode ( keyCode )
if ! ok {
// no such key; modifiers by themselves are handled by -[self flagsChanged:]
2014-05-13 08:33:37 -05:00
return false
2014-03-30 18:53:44 -05:00
}
// either ke.Key or ke.ExtKey will be set at this point
ke . Modifiers = parseModifiers ( e )
ke . Up = up
2014-05-13 08:33:37 -05:00
return sendKeyEvent ( self , e , ke )
2014-03-30 18:53:44 -05:00
}
//export areaView_keyDown
2014-05-13 08:33:37 -05:00
func areaView_keyDown ( self C . id , e C . id ) C . BOOL {
return toBOOL ( areaKeyEvent ( self , e , false ) )
2014-03-30 18:53:44 -05:00
}
//export areaView_keyUp
2014-05-13 08:33:37 -05:00
func areaView_keyUp ( self C . id , e C . id ) C . BOOL {
return toBOOL ( areaKeyEvent ( self , e , true ) )
2014-03-30 18:53:44 -05:00
}
//export areaView_flagsChanged
2014-05-13 08:33:37 -05:00
func areaView_flagsChanged ( self C . id , e C . id ) C . BOOL {
2014-03-30 18:53:44 -05:00
var ke KeyEvent
// Mac OS X sends this event on both key up and key down.
// Fortunately -[e keyCode] IS valid here, so we can simply map from key code to Modifiers, get the value of [e modifierFlags], the respective bit is set or not — that will give us the up/down state
2014-05-13 08:33:37 -05:00
keyCode := uintptr ( C . keyCode ( e ) )
2014-03-30 18:53:44 -05:00
mod , ok := keycodeModifiers [ keyCode ] // comma-ok form to avoid adding entries
if ! ok { // unknown modifier; ignore
2014-05-13 08:33:37 -05:00
return C . NO
2014-03-30 18:53:44 -05:00
}
ke . Modifiers = parseModifiers ( e )
ke . Up = ( ke . Modifiers & mod ) == 0
2014-05-13 08:33:37 -05:00
return toBOOL ( sendKeyEvent ( self , e , ke ) )
2014-03-30 18:53:44 -05:00
}