2014-03-29 22:57:49 -05:00
// 29 march 2014
package ui
import (
2014-03-30 13:25:01 -05:00
"image"
2014-06-10 15:03:10 -05:00
"unsafe"
2014-03-29 22:57:49 -05:00
)
// #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-05-16 19:44:19 -05:00
area = makeScrollView ( area )
2014-04-13 11:52:10 -05:00
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 )
2014-05-17 19:21:48 -05:00
// no need to clear the clip rect; the NSScrollView does that for us (see the setDrawsBackground: call in objc_darwin.m)
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
2014-06-10 15:03:10 -05:00
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 )
2014-06-10 15:03:10 -05:00
if cliprect . Empty ( ) { // no intersection; nothing to paint
2014-03-30 13:25:01 -05:00
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 (
2014-06-10 15:03:10 -05:00
_NSShiftKeyMask = 1 << 17
_NSControlKeyMask = 1 << 18
2014-03-30 16:52:27 -05:00
_NSAlternateKeyMask = 1 << 19
2014-06-10 15:03:10 -05:00
_NSCommandKeyMask = 1 << 20
2014-03-30 16:52:27 -05:00
)
2014-05-13 08:33:37 -05:00
mods := uintptr ( C . modifierFlags ( e ) )
2014-03-30 16:52:27 -05:00
if ( mods & _NSControlKeyMask ) != 0 {
2014-05-16 18:52:28 -05:00
m |= Ctrl
2014-03-30 16:52:27 -05:00
}
if ( mods & _NSAlternateKeyMask ) != 0 {
m |= Alt
}
2014-05-16 18:52:28 -05:00
if ( mods & _NSShiftKeyMask ) != 0 {
m |= Shift
}
2014-03-30 16:52:27 -05:00
if ( mods & _NSCommandKeyMask ) != 0 {
2014-05-16 18:52:28 -05:00
m |= Super
2014-03-30 16:52:27 -05:00
}
return m
}
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-06-10 15:03:10 -05:00
if which == 3 { // swap middle and right button numbers
2014-03-30 16:52:27 -05:00
which = 2
} else if which == 2 {
which = 3
}
if click && up {
me . Up = which
} else if click {
me . Down = which
2014-05-23 22:48:17 -05:00
// this already works the way we want it to so nothing special needed like with Windows and GTK+
2014-05-15 18:55:16 -05:00
me . Count = uint ( C . clickCount ( e ) )
2014-03-30 16:52:27 -05:00
} else {
2014-06-10 15:03:10 -05:00
which = 0 // reset for Held processing below
2014-03-30 16:52:27 -05:00
}
2014-05-17 15:21:25 -05:00
// the docs do say don't use this for tracking (mouseMoved:) 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 not generate an event on Mac OS X, so :/ (tracking doesn't touch dragging anyway except during mouseEntered: and mouseExited:, which we don't handle, and the only other tracking message, cursorChanged:, we also don't handle (yet...? need to figure out if this is how to set custom cursors or not), so)
2014-05-13 08:33:37 -05:00
held := C . pressedMouseButtons ( )
2014-06-10 15:03:10 -05:00
if which != 1 && ( held & 1 ) != 0 { // button 1
2014-03-30 16:52:27 -05:00
me . Held = append ( me . Held , 1 )
}
2014-06-10 15:03:10 -05:00
if which != 2 && ( held & 4 ) != 0 { // button 2; mind the swap
2014-03-30 16:52:27 -05:00
me . Held = append ( me . Held , 2 )
}
2014-06-10 15:03:10 -05:00
if which != 3 && ( held & 2 ) != 0 { // button 3
2014-03-30 16:52:27 -05:00
me . Held = append ( me . Held , 3 )
}
held >>= 3
for i := uint ( 4 ) ; held != 0 ; i ++ {
2014-06-10 15:03:10 -05:00
if which != i && ( held & 1 ) != 0 {
2014-03-30 16:52:27 -05:00
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-06-06 22:47:48 -05:00
// no need to manually set focus; Mac OS X has already done that for us by this point since we set our view to be a first responder
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-06-02 11:27:23 -05:00
func sendKeyEvent ( self C . id , ke KeyEvent ) {
2014-03-30 18:53:44 -05:00
s := getSysData ( self )
2014-06-02 11:27:23 -05:00
repaint := s . handler . Key ( ke )
2014-03-30 18:53:44 -05:00
if repaint {
2014-05-15 18:55:16 -05:00
C . display ( self )
2014-03-30 18:53:44 -05:00
}
}
2014-06-02 11:27:23 -05:00
func areaKeyEvent ( self C . id , e C . id , up 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-06-02 11:27:23 -05:00
return
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-06-02 11:27:23 -05:00
sendKeyEvent ( self , ke )
2014-03-30 18:53:44 -05:00
}
//export areaView_keyDown
2014-06-02 11:27:23 -05:00
func areaView_keyDown ( self C . id , e C . id ) {
areaKeyEvent ( self , e , false )
2014-03-30 18:53:44 -05:00
}
//export areaView_keyUp
2014-06-02 11:27:23 -05:00
func areaView_keyUp ( self C . id , e C . id ) {
areaKeyEvent ( self , e , true )
2014-03-30 18:53:44 -05:00
}
//export areaView_flagsChanged
2014-06-02 11:27:23 -05:00
func areaView_flagsChanged ( self C . id , e C . id ) {
2014-03-30 18:53:44 -05:00
var ke KeyEvent
// Mac OS X sends this event on both key up and key down.
2014-05-29 13:26:20 -05:00
// Fortunately -[e keyCode] IS valid here, so we can simply map from key code to Modifiers, get the value of [e modifierFlags], and check if 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-06-10 15:03:10 -05:00
mod , ok := keycodeModifiers [ keyCode ] // comma-ok form to avoid adding entries
if ! ok { // unknown modifier; ignore
2014-06-02 11:27:23 -05:00
return
2014-03-30 18:53:44 -05:00
}
ke . Modifiers = parseModifiers ( e )
ke . Up = ( ke . Modifiers & mod ) == 0
2014-05-29 13:26:20 -05:00
ke . Modifier = mod
// don't include the modifier in ke.Modifiers
ke . Modifiers &^= mod
2014-06-02 11:27:23 -05:00
sendKeyEvent ( self , ke )
2014-03-30 18:53:44 -05:00
}