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