]> gitweb.factorcode.org Git - factor.git/blob - basis/ui/backend/cocoa/views/views.factor
move some allocation words that don't really have much to do with c types out of...
[factor.git] / basis / ui / backend / cocoa / views / views.factor
1 ! Copyright (C) 2006, 2008 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.types cocoa.windows sequences io.encodings.utf8 ui ui.private
7 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
11
12 : send-mouse-moved ( view event -- )
13     [ mouse-location ] [ drop window ] 2bi move-hand fire-motion yield ;
14
15 : button ( event -- n )
16     #! Cocoa -> Factor UI button mapping
17     -> buttonNumber H{ { 0 1 } { 2 2 } { 1 3 } } at ;
18
19 CONSTANT: modifiers
20     {
21         { S+ HEX: 20000 }
22         { C+ HEX: 40000 }
23         { A+ HEX: 100000 }
24         { M+ HEX: 80000 }
25     }
26
27 CONSTANT: key-codes
28     H{
29         { 71 "CLEAR" }
30         { 36 "RET" }
31         { 76 "ENTER" }
32         { 53 "ESC" }
33         { 48 "TAB" }
34         { 51 "BACKSPACE" }
35         { 115 "HOME" }
36         { 117 "DELETE" }
37         { 119 "END" }
38         { 122 "F1" }
39         { 120 "F2" }
40         { 99 "F3" }
41         { 118 "F4" }
42         { 96 "F5" }
43         { 97 "F6" }
44         { 98 "F7" }
45         { 100 "F8" }
46         { 123 "LEFT" }
47         { 124 "RIGHT" }
48         { 125 "DOWN" }
49         { 126 "UP" }
50         { 116 "PAGE_UP" }
51         { 121 "PAGE_DOWN" }
52     }
53
54 : key-code ( event -- string ? )
55     dup -> keyCode key-codes at
56     [ t ] [ -> charactersIgnoringModifiers CF>string f ] ?if ;
57
58 : event-modifiers ( event -- modifiers )
59     -> modifierFlags modifiers modifier ;
60
61 : key-event>gesture ( event -- modifiers keycode action? )
62     [ event-modifiers ] [ key-code ] bi ;
63
64 : send-key-event ( view gesture -- )
65     swap window propagate-key-gesture ;
66
67 : interpret-key-event ( view event -- )
68     NSArray swap -> arrayWithObject: -> interpretKeyEvents: ;
69
70 : send-key-down-event ( view event -- )
71     [ key-event>gesture <key-down> send-key-event ]
72     [ interpret-key-event ]
73     2bi ;
74
75 : send-key-up-event ( view event -- )
76     key-event>gesture <key-up> send-key-event ;
77
78 : mouse-event>gesture ( event -- modifiers button )
79     [ event-modifiers ] [ button ] bi ;
80
81 : send-button-down$ ( view event -- )
82     [ nip mouse-event>gesture <button-down> ]
83     [ mouse-location ]
84     [ drop window ]
85     2tri send-button-down ;
86
87 : send-button-up$ ( view event -- )
88     [ nip mouse-event>gesture <button-up> ]
89     [ mouse-location ]
90     [ drop window ]
91     2tri send-button-up ;
92
93 : send-wheel$ ( view event -- )
94     [ nip [ -> deltaX ] [ -> deltaY ] bi [ sgn neg ] bi@ 2array ]
95     [ mouse-location ]
96     [ drop window ]
97     2tri send-wheel ;
98
99 : send-action$ ( view event gesture -- junk )
100     [ drop window ] dip send-action f ;
101
102 : add-resize-observer ( observer object -- )
103     [
104         "updateFactorGadgetSize:"
105         "NSViewFrameDidChangeNotification" <NSString>
106     ] dip add-observer ;
107
108 : string-or-nil? ( NSString -- ? )
109     [ CF>string NSStringPboardType = ] [ t ] if* ;
110
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 ;
114
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 ]
118     2bi <rect> ;
119
120 : rect>NSRect ( rect world -- NSRect )
121     [ [ loc>> first2 ] [ dim>> second ] bi* swap - ]
122     [ drop dim>> first2 ]
123     2bi <CGRect> ;
124
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 }
138 }
139
140 : validate-action ( world selector -- ? validated? )
141     selector>action at 
142     [ swap world-focus parents-handle-gesture? t ] [ drop f f ] if* ; 
143
144 CLASS: {
145     { +superclass+ "NSOpenGLView" }
146     { +name+ "FactorView" }
147     { +protocols+ { "NSTextInput" } }
148 }
149
150 ! Rendering
151 { "drawRect:" "void" { "id" "SEL" "NSRect" }
152     [ 2drop window relayout-1 yield ]
153 }
154
155 ! Events
156 { "acceptsFirstMouse:" "char" { "id" "SEL" "id" }
157     [ 3drop 1 ]
158 }
159
160 { "mouseEntered:" "void" { "id" "SEL" "id" }
161     [ nip send-mouse-moved ]
162 }
163
164 { "mouseExited:" "void" { "id" "SEL" "id" }
165     [ 3drop forget-rollover ]
166 }
167
168 { "mouseMoved:" "void" { "id" "SEL" "id" }
169     [ nip send-mouse-moved ]
170 }
171
172 { "mouseDragged:" "void" { "id" "SEL" "id" }
173     [ nip send-mouse-moved ]
174 }
175
176 { "rightMouseDragged:" "void" { "id" "SEL" "id" }
177     [ nip send-mouse-moved ]
178 }
179
180 { "otherMouseDragged:" "void" { "id" "SEL" "id" }
181     [ nip send-mouse-moved ]
182 }
183
184 { "mouseDown:" "void" { "id" "SEL" "id" }
185     [ nip send-button-down$ ]
186 }
187
188 { "mouseUp:" "void" { "id" "SEL" "id" }
189     [ nip send-button-up$ ]
190 }
191
192 { "rightMouseDown:" "void" { "id" "SEL" "id" }
193     [ nip send-button-down$ ]
194 }
195
196 { "rightMouseUp:" "void" { "id" "SEL" "id" }
197     [ nip send-button-up$ ]
198 }
199
200 { "otherMouseDown:" "void" { "id" "SEL" "id" }
201     [ nip send-button-down$ ]
202 }
203
204 { "otherMouseUp:" "void" { "id" "SEL" "id" }
205     [ nip send-button-up$ ]
206 }
207
208 { "scrollWheel:" "void" { "id" "SEL" "id" }
209     [ nip send-wheel$ ]
210 }
211
212 { "keyDown:" "void" { "id" "SEL" "id" }
213     [ nip send-key-down-event ]
214 }
215
216 { "keyUp:" "void" { "id" "SEL" "id" }
217     [ nip send-key-up-event ]
218 }
219
220 { "validateUserInterfaceItem:" "char" { "id" "SEL" "id" }
221     [
222         nip -> action
223         2dup [ window ] [ utf8 alien>string ] bi* validate-action
224         [ [ 2drop ] dip >c-bool ] [ SUPER-> validateUserInterfaceItem: ] if
225     ]
226 }
227
228 { "undo:" "id" { "id" "SEL" "id" }
229     [ nip undo-action send-action$ ]
230 }
231
232 { "redo:" "id" { "id" "SEL" "id" }
233     [ nip redo-action send-action$ ]
234 }
235
236 { "cut:" "id" { "id" "SEL" "id" }
237     [ nip cut-action send-action$ ]
238 }
239
240 { "copy:" "id" { "id" "SEL" "id" }
241     [ nip copy-action send-action$ ]
242 }
243
244 { "paste:" "id" { "id" "SEL" "id" }
245     [ nip paste-action send-action$ ]
246 }
247
248 { "delete:" "id" { "id" "SEL" "id" }
249     [ nip delete-action send-action$ ]
250 }
251
252 { "selectAll:" "id" { "id" "SEL" "id" }
253     [ nip select-all-action send-action$ ]
254 }
255
256 { "newDocument:" "id" { "id" "SEL" "id" }
257     [ nip new-action send-action$ ]
258 }
259
260 { "openDocument:" "id" { "id" "SEL" "id" }
261     [ nip open-action send-action$ ]
262 }
263
264 { "saveDocument:" "id" { "id" "SEL" "id" }
265     [ nip save-action send-action$ ]
266 }
267
268 { "saveDocumentAs:" "id" { "id" "SEL" "id" }
269     [ nip save-as-action send-action$ ]
270 }
271
272 { "revertDocumentToSaved:" "id" { "id" "SEL" "id" }
273     [ nip revert-action send-action$ ]
274 }
275
276 ! Multi-touch gestures: this is undocumented.
277 ! http://cocoadex.com/2008/02/nsevent-modifications-swipe-ro.html
278 { "magnifyWithEvent:" "void" { "id" "SEL" "id" }
279     [
280         nip
281         dup -> deltaZ sgn {
282             {  1 [ zoom-in-action send-action$ ] }
283             { -1 [ zoom-out-action send-action$ ] }
284             {  0 [ 2drop ] }
285         } case
286     ]
287 }
288
289 { "swipeWithEvent:" "void" { "id" "SEL" "id" }
290     [
291         nip
292         dup -> deltaX sgn {
293             {  1 [ left-action send-action$ ] }
294             { -1 [ right-action send-action$ ] }
295             {  0
296                 [
297                     dup -> deltaY sgn {
298                         {  1 [ up-action send-action$ ] }
299                         { -1 [ down-action send-action$ ] }
300                         {  0 [ 2drop ] }
301                     } case
302                 ]
303             }
304         } case
305     ]
306 }
307
308 ! "rotateWithEvent:" "void" { "id" "SEL" "id" }}
309
310 { "acceptsFirstResponder" "char" { "id" "SEL" }
311     [ 2drop 1 ]
312 }
313
314 ! Services
315 { "validRequestorForSendType:returnType:" "id" { "id" "SEL" "id" "id" }
316     [
317         ! We return either self or nil
318         [ over window-focus ] 2dip
319         valid-service? [ drop ] [ 2drop f ] if
320     ]
321 }
322
323 { "writeSelectionToPasteboard:types:" "char" { "id" "SEL" "id" "id" }
324     [
325         CF>string-array NSStringPboardType swap member? [
326             [ drop window-focus gadget-selection ] dip over
327             [ set-pasteboard-string 1 ] [ 2drop 0 ] if
328         ] [ 3drop 0 ] if
329     ]
330 }
331
332 { "readSelectionFromPasteboard:" "char" { "id" "SEL" "id" }
333     [
334         pasteboard-string dup [
335             [ drop window ] dip swap user-input 1
336         ] [ 3drop 0 ] if
337     ]
338 }
339
340 ! Text input
341 { "insertText:" "void" { "id" "SEL" "id" }
342     [ nip CF>string swap window user-input ]
343 }
344
345 { "hasMarkedText" "char" { "id" "SEL" }
346     [ 2drop 0 ]
347 }
348
349 { "markedRange" "NSRange" { "id" "SEL" }
350     [ 2drop 0 0 <NSRange> ]
351 }
352
353 { "selectedRange" "NSRange" { "id" "SEL" }
354     [ 2drop 0 0 <NSRange> ]
355 }
356
357 { "setMarkedText:selectedRange:" "void" { "id" "SEL" "id" "NSRange" }
358     [ 2drop 2drop ]
359 }
360
361 { "unmarkText" "void" { "id" "SEL" }
362     [ 2drop ]
363 }
364
365 { "validAttributesForMarkedText" "id" { "id" "SEL" }
366     [ 2drop NSArray -> array ]
367 }
368
369 { "attributedSubstringFromRange:" "id" { "id" "SEL" "NSRange" }
370     [ 3drop f ]
371 }
372
373 { "characterIndexForPoint:" "NSUInteger" { "id" "SEL" "NSPoint" }
374     [ 3drop 0 ]
375 }
376
377 { "firstRectForCharacterRange:" "NSRect" { "id" "SEL" "NSRange" }
378     [ 3drop 0 0 0 0 <CGRect> ]
379 }
380
381 { "conversationIdentifier" "NSInteger" { "id" "SEL" }
382     [ drop alien-address ]
383 }
384
385 ! Initialization
386 { "updateFactorGadgetSize:" "void" { "id" "SEL" "id" }
387     [ 2drop [ window ] [ view-dim ] bi >>dim drop yield ]
388 }
389
390 { "doCommandBySelector:" "void" { "id" "SEL" "SEL" }
391     [ 3drop ]
392 }
393
394 { "initWithFrame:pixelFormat:" "id" { "id" "SEL" "NSRect" "id" }
395     [
396         [ drop ] 2dip
397         SUPER-> initWithFrame:pixelFormat:
398         dup dup add-resize-observer
399     ]
400 }
401
402 { "dealloc" "void" { "id" "SEL" }
403     [
404         drop
405         [ unregister-window ]
406         [ remove-observer ]
407         [ SUPER-> dealloc ]
408         tri
409     ]
410 } ;
411
412 : sync-refresh-to-screen ( GLView -- )
413     -> openGLContext -> CGLContextObj NSOpenGLCPSwapInterval 1 <int>
414     CGLSetParameter drop ;
415
416 : <FactorView> ( dim pixel-format -- view )
417     [ FactorView ] 2dip <GLView> [ sync-refresh-to-screen ] keep ;
418
419 : save-position ( world window -- )
420     -> frame CGRect-top-left 2array >>window-loc drop ;
421
422 CLASS: {
423     { +superclass+ "NSObject" }
424     { +name+ "FactorWindowDelegate" }
425 }
426
427 { "windowDidMove:" "void" { "id" "SEL" "id" }
428     [
429         2nip -> object [ -> contentView window ] keep save-position
430     ]
431 }
432
433 { "windowDidBecomeKey:" "void" { "id" "SEL" "id" }
434     [
435         2nip -> object -> contentView window focus-world
436     ]
437 }
438
439 { "windowDidResignKey:" "void" { "id" "SEL" "id" }
440     [
441         forget-rollover
442         2nip -> object -> contentView
443         dup -> isInFullScreenMode zero? 
444         [ window unfocus-world ]
445         [ drop ] if
446     ]
447 }
448
449 { "windowShouldClose:" "char" { "id" "SEL" "id" }
450     [
451         3drop 1
452     ]
453 }
454
455 { "windowWillClose:" "void" { "id" "SEL" "id" }
456     [
457         2nip -> object -> contentView window ungraft
458     ]
459 } ;
460
461 : install-window-delegate ( window -- )
462     FactorWindowDelegate install-delegate ;