1 ! Copyright (C) 2006, 2010 Slava Pestov
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien alien.c-types alien.data alien.strings
4 arrays assocs cocoa kernel math cocoa.messages cocoa.subclassing
5 cocoa.classes cocoa.views cocoa.application cocoa.pasteboard
6 cocoa.runtime cocoa.types cocoa.windows sequences io.encodings.utf8
7 ui ui.private ui.gadgets ui.gadgets.private ui.gadgets.worlds ui.gestures
8 core-foundation.strings core-graphics core-graphics.types threads
9 combinators math.rectangles ;
10 IN: ui.backend.cocoa.views
12 : send-mouse-moved ( view event -- )
13 [ mouse-location ] [ drop window ] 2bi move-hand fire-motion yield ;
15 : button ( event -- n )
16 #! Cocoa -> Factor UI button mapping
17 -> buttonNumber H{ { 0 1 } { 2 2 } { 1 3 } } at ;
54 : key-code ( event -- string ? )
55 dup -> keyCode key-codes at
56 [ t ] [ -> charactersIgnoringModifiers CF>string f ] ?if ;
58 : event-modifiers ( event -- modifiers )
59 -> modifierFlags modifiers modifier ;
61 : key-event>gesture ( event -- modifiers keycode action? )
62 [ event-modifiers ] [ key-code ] bi ;
64 : send-key-event ( view gesture -- )
65 swap window propagate-key-gesture ;
67 : interpret-key-event ( view event -- )
68 NSArray swap -> arrayWithObject: -> interpretKeyEvents: ;
70 : send-key-down-event ( view event -- )
71 [ key-event>gesture <key-down> send-key-event ]
72 [ interpret-key-event ]
75 : send-key-up-event ( view event -- )
76 key-event>gesture <key-up> send-key-event ;
78 : mouse-event>gesture ( event -- modifiers button )
79 [ event-modifiers ] [ button ] bi ;
81 : send-button-down$ ( view event -- )
82 [ nip mouse-event>gesture <button-down> ]
85 2tri send-button-down ;
87 : send-button-up$ ( view event -- )
88 [ nip mouse-event>gesture <button-up> ]
93 : send-scroll$ ( view event -- )
94 [ nip [ -> deltaX ] [ -> deltaY ] bi [ neg ] bi@ 2array ]
99 : send-action$ ( view event gesture -- junk )
100 [ drop window ] dip send-action f ;
102 : add-resize-observer ( observer object -- )
104 "updateFactorGadgetSize:"
105 "NSViewFrameDidChangeNotification" <NSString>
108 : string-or-nil? ( NSString -- ? )
109 [ CF>string NSStringPboardType = ] [ t ] if* ;
111 : valid-service? ( gadget send-type return-type -- ? )
112 2dup [ string-or-nil? ] [ string-or-nil? ] bi* and
113 [ drop [ gadget-selection? ] [ drop t ] if ] [ 3drop f ] if ;
115 : NSRect>rect ( NSRect world -- rect )
116 [ [ [ CGRect-x ] [ CGRect-y ] bi ] [ dim>> second ] bi* swap - 2array ]
117 [ drop [ CGRect-w ] [ CGRect-h ] bi 2array ]
120 : rect>NSRect ( rect world -- NSRect )
121 [ [ loc>> first2 ] [ dim>> second ] bi* swap - ]
122 [ drop dim>> first2 ]
125 CONSTANT: selector>action H{
126 { "undo:" undo-action }
127 { "redo:" redo-action }
128 { "cut:" cut-action }
129 { "copy:" copy-action }
130 { "paste:" paste-action }
131 { "delete:" delete-action }
132 { "selectAll:" select-all-action }
133 { "newDocument:" new-action }
134 { "openDocument:" open-action }
135 { "saveDocument:" save-action }
136 { "saveDocumentAs:" save-as-action }
137 { "revertDocumentToSaved:" revert-action }
140 : validate-action ( world selector -- ? validated? )
142 [ swap world-focus parents-handle-gesture? t ] [ drop f f ] if* ;
145 { +superclass+ "NSOpenGLView" }
146 { +name+ "FactorView" }
147 { +protocols+ { "NSTextInput" } }
151 { "drawRect:" void { id SEL NSRect }
152 [ 2drop window draw-world ]
156 { "acceptsFirstMouse:" char { id SEL id }
160 { "mouseEntered:" void { id SEL id }
161 [ nip send-mouse-moved ]
164 { "mouseExited:" void { id SEL id }
165 [ 3drop forget-rollover ]
168 { "mouseMoved:" void { id SEL id }
169 [ nip send-mouse-moved ]
172 { "mouseDragged:" void { id SEL id }
173 [ nip send-mouse-moved ]
176 { "rightMouseDragged:" void { id SEL id }
177 [ nip send-mouse-moved ]
180 { "otherMouseDragged:" void { id SEL id }
181 [ nip send-mouse-moved ]
184 { "mouseDown:" void { id SEL id }
185 [ nip send-button-down$ ]
188 { "mouseUp:" void { id SEL id }
189 [ nip send-button-up$ ]
192 { "rightMouseDown:" void { id SEL id }
193 [ nip send-button-down$ ]
196 { "rightMouseUp:" void { id SEL id }
197 [ nip send-button-up$ ]
200 { "otherMouseDown:" void { id SEL id }
201 [ nip send-button-down$ ]
204 { "otherMouseUp:" void { id SEL id }
205 [ nip send-button-up$ ]
208 { "scrollWheel:" void { id SEL id }
212 { "keyDown:" void { id SEL id }
213 [ nip send-key-down-event ]
216 { "keyUp:" void { id SEL id }
217 [ nip send-key-up-event ]
220 { "validateUserInterfaceItem:" char { id SEL id }
223 2dup [ window ] [ utf8 alien>string ] bi* validate-action
224 [ [ 2drop ] dip >c-bool ] [ SUPER-> validateUserInterfaceItem: ] if
228 { "undo:" id { id SEL id }
229 [ nip undo-action send-action$ ]
232 { "redo:" id { id SEL id }
233 [ nip redo-action send-action$ ]
236 { "cut:" id { id SEL id }
237 [ nip cut-action send-action$ ]
240 { "copy:" id { id SEL id }
241 [ nip copy-action send-action$ ]
244 { "paste:" id { id SEL id }
245 [ nip paste-action send-action$ ]
248 { "delete:" id { id SEL id }
249 [ nip delete-action send-action$ ]
252 { "selectAll:" id { id SEL id }
253 [ nip select-all-action send-action$ ]
256 { "newDocument:" id { id SEL id }
257 [ nip new-action send-action$ ]
260 { "openDocument:" id { id SEL id }
261 [ nip open-action send-action$ ]
264 { "saveDocument:" id { id SEL id }
265 [ nip save-action send-action$ ]
268 { "saveDocumentAs:" id { id SEL id }
269 [ nip save-as-action send-action$ ]
272 { "revertDocumentToSaved:" id { id SEL id }
273 [ nip revert-action send-action$ ]
276 ! Multi-touch gestures: this is undocumented.
277 ! http://cocoadex.com/2008/02/nsevent-modifications-swipe-ro.html
278 { "magnifyWithEvent:" void { id SEL id }
282 { 1 [ zoom-in-action send-action$ ] }
283 { -1 [ zoom-out-action send-action$ ] }
289 { "swipeWithEvent:" void { id SEL id }
293 { 1 [ left-action send-action$ ] }
294 { -1 [ right-action send-action$ ] }
298 { 1 [ up-action send-action$ ] }
299 { -1 [ down-action send-action$ ] }
308 { "acceptsFirstResponder" char { id SEL }
313 { "validRequestorForSendType:returnType:" id { id SEL id id }
315 ! We return either self or nil
316 [ over window-focus ] 2dip
317 valid-service? [ drop ] [ 2drop f ] if
321 { "writeSelectionToPasteboard:types:" char { id SEL id id }
323 CF>string-array NSStringPboardType swap member? [
324 [ drop window-focus gadget-selection ] dip over
325 [ set-pasteboard-string 1 ] [ 2drop 0 ] if
330 { "readSelectionFromPasteboard:" char { id SEL id }
332 pasteboard-string dup [
333 [ drop window ] dip swap user-input 1
339 { "insertText:" void { id SEL id }
340 [ nip CF>string swap window user-input ]
343 { "hasMarkedText" char { id SEL }
347 { "markedRange" NSRange { id SEL }
348 [ 2drop 0 0 <NSRange> ]
351 { "selectedRange" NSRange { id SEL }
352 [ 2drop 0 0 <NSRange> ]
355 { "setMarkedText:selectedRange:" void { id SEL id NSRange }
359 { "unmarkText" void { id SEL }
363 { "validAttributesForMarkedText" id { id SEL }
364 [ 2drop NSArray -> array ]
367 { "attributedSubstringFromRange:" id { id SEL NSRange }
371 { "characterIndexForPoint:" NSUInteger { id SEL NSPoint }
375 { "firstRectForCharacterRange:" NSRect { id SEL NSRange }
376 [ 3drop 0 0 0 0 <CGRect> ]
379 { "conversationIdentifier" NSInteger { id SEL }
380 [ drop alien-address ]
384 { "updateFactorGadgetSize:" void { id SEL id }
385 [ 2drop [ window ] [ view-dim ] bi >>dim drop yield ]
388 { "doCommandBySelector:" void { id SEL SEL }
392 { "initWithFrame:pixelFormat:" id { id SEL NSRect id }
395 SUPER-> initWithFrame:pixelFormat:
396 dup dup add-resize-observer
400 { "isOpaque" char { id SEL }
406 { "dealloc" void { id SEL }
415 : sync-refresh-to-screen ( GLView -- )
416 -> openGLContext -> CGLContextObj NSOpenGLCPSwapInterval 1 <int>
417 CGLSetParameter drop ;
419 : <FactorView> ( dim pixel-format -- view )
420 [ FactorView ] 2dip <GLView> [ sync-refresh-to-screen ] keep ;
422 : save-position ( world window -- )
423 -> frame CGRect-top-left 2array >>window-loc drop ;
426 { +superclass+ "NSObject" }
427 { +name+ "FactorWindowDelegate" }
430 { "windowDidMove:" void { id SEL id }
432 2nip -> object [ -> contentView window ] keep save-position
436 { "windowDidBecomeKey:" void { id SEL id }
438 2nip -> object -> contentView window focus-world
442 { "windowDidResignKey:" void { id SEL id }
445 2nip -> object -> contentView
446 dup -> isInFullScreenMode 0 =
447 [ window [ unfocus-world ] when* ]
452 { "windowShouldClose:" char { id SEL id }
458 { "windowWillClose:" void { id SEL id }
460 2nip -> object -> contentView
461 [ window ungraft ] [ unregister-window ] bi
465 : install-window-delegate ( window -- )
466 FactorWindowDelegate install-delegate ;