]> gitweb.factorcode.org Git - factor.git/blob - extra/ui/cocoa/views/views.factor
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / extra / ui / cocoa / views / views.factor
1 ! Copyright (C) 2006, 2008 Slava Pestov
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien arrays assocs cocoa kernel math cocoa.messages
4 cocoa.subclassing cocoa.classes cocoa.views cocoa.application
5 cocoa.pasteboard cocoa.types cocoa.windows sequences ui
6 ui.gadgets ui.gadgets.worlds ui.gestures core-foundation
7 threads combinators ;
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 ! Rendering
132 { "drawRect:" "void" { "id" "SEL" "id" "NSRect" }
133     [ 3drop window relayout-1 ]
134 }
135
136 ! Events
137 { "acceptsFirstMouse:" "bool" { "id" "SEL" "id" }
138     [ 3drop 1 ]
139 }
140
141 { "mouseEntered:" "void" { "id" "SEL" "id" }
142     [ [ nip send-mouse-moved ] ui-try ]
143 }
144
145 { "mouseExited:" "void" { "id" "SEL" "id" }
146     [ [ 3drop forget-rollover ] ui-try ]
147 }
148
149 { "mouseMoved:" "void" { "id" "SEL" "id" }
150     [ [ nip send-mouse-moved ] ui-try ]
151 }
152
153 { "mouseDragged:" "void" { "id" "SEL" "id" }
154     [ [ nip send-mouse-moved ] ui-try ]
155 }
156
157 { "rightMouseDragged:" "void" { "id" "SEL" "id" }
158     [ [ nip send-mouse-moved ] ui-try ]
159 }
160
161 { "otherMouseDragged:" "void" { "id" "SEL" "id" }
162     [ [ nip send-mouse-moved ] ui-try ]
163 }
164
165 { "mouseDown:" "void" { "id" "SEL" "id" }
166     [ [ nip send-button-down$ ] ui-try ]
167 }
168
169 { "mouseUp:" "void" { "id" "SEL" "id" }
170     [ [ nip send-button-up$ ] ui-try ]
171 }
172
173 { "rightMouseDown:" "void" { "id" "SEL" "id" }
174     [ [ nip send-button-down$ ] ui-try ]
175 }
176
177 { "rightMouseUp:" "void" { "id" "SEL" "id" }
178     [ [ nip send-button-up$ ] ui-try ]
179 }
180
181 { "otherMouseDown:" "void" { "id" "SEL" "id" }
182     [ [ nip send-button-down$ ] ui-try ]
183 }
184
185 { "otherMouseUp:" "void" { "id" "SEL" "id" }
186     [ [ nip send-button-up$ ] ui-try ]
187 }
188
189 { "scrollWheel:" "void" { "id" "SEL" "id" }
190     [ [ nip send-wheel$ ] ui-try ]
191 }
192
193 { "keyDown:" "void" { "id" "SEL" "id" }
194     [ [ nip send-key-down-event ] ui-try ]
195 }
196
197 { "keyUp:" "void" { "id" "SEL" "id" }
198     [ [ nip send-key-up-event ] ui-try ]
199 }
200
201 { "cut:" "id" { "id" "SEL" "id" }
202     [ [ nip T{ cut-action } send-action$ ] ui-try ]
203 }
204
205 { "copy:" "id" { "id" "SEL" "id" }
206     [ [ nip T{ copy-action } send-action$ ] ui-try ]
207 }
208
209 { "paste:" "id" { "id" "SEL" "id" }
210     [ [ nip T{ paste-action } send-action$ ] ui-try ]
211 }
212
213 { "delete:" "id" { "id" "SEL" "id" }
214     [ [ nip T{ delete-action } send-action$ ] ui-try ]
215 }
216
217 { "selectAll:" "id" { "id" "SEL" "id" }
218     [ [ nip T{ select-all-action } send-action$ ] ui-try ]
219 }
220
221 ! Multi-touch gestures: this is undocumented.
222 ! http://cocoadex.com/2008/02/nsevent-modifications-swipe-ro.html
223 { "magnifyWithEvent:" "void" { "id" "SEL" "id" }
224     [
225         nip
226         dup -> deltaZ sgn {
227             {  1 [ T{ zoom-in-action } send-action$ ] }
228             { -1 [ T{ zoom-out-action } send-action$ ] }
229             {  0 [ 2drop ] }
230         } case
231     ]
232 }
233
234 { "swipeWithEvent:" "void" { "id" "SEL" "id" }
235     [
236         nip
237         dup -> deltaX sgn {
238             {  1 [ T{ left-action } send-action$ ] }
239             { -1 [ T{ right-action } send-action$ ] }
240             {  0
241                 [
242                     dup -> deltaY sgn {
243                         {  1 [ T{ up-action } send-action$ ] }
244                         { -1 [ T{ down-action } send-action$ ] }
245                         {  0 [ 2drop ] }
246                     } case
247                 ]
248             }
249         } case
250     ]
251 }
252
253 ! "rotateWithEvent:" "void" { "id" "SEL" "id" }}
254
255 { "acceptsFirstResponder" "bool" { "id" "SEL" }
256     [ 2drop 1 ]
257 }
258
259 ! Services
260 { "validRequestorForSendType:returnType:" "id" { "id" "SEL" "id" "id" }
261     [
262         ! We return either self or nil
263         >r >r over window-focus r> r>
264         valid-service? [ drop ] [ 2drop f ] if
265     ]
266 }
267
268 { "writeSelectionToPasteboard:types:" "bool" { "id" "SEL" "id" "id" }
269     [
270         CF>string-array NSStringPboardType swap member? [
271             >r drop window-focus gadget-selection dup [
272                 r> set-pasteboard-string t
273             ] [
274                 r> 2drop f
275             ] if
276         ] [
277             3drop f
278         ] if
279     ]
280 }
281
282 { "readSelectionFromPasteboard:" "bool" { "id" "SEL" "id" }
283     [
284         pasteboard-string dup [
285             >r drop window-focus r> swap user-input t
286         ] [
287             3drop f
288         ] if
289     ]
290 }
291
292 ! Text input
293 { "insertText:" "void" { "id" "SEL" "id" }
294     [ [ nip send-user-input ] ui-try ]
295 }
296
297 { "hasMarkedText" "bool" { "id" "SEL" }
298     [ 2drop 0 ]
299 }
300
301 { "markedRange" "NSRange" { "id" "SEL" }
302     [ 2drop 0 0 <NSRange> ]
303 }
304
305 { "selectedRange" "NSRange" { "id" "SEL" }
306     [ 2drop 0 0 <NSRange> ]
307 }
308
309 { "setMarkedText:selectedRange:" "void" { "id" "SEL" "id" "NSRange" }
310     [ 2drop 2drop ]
311 }
312
313 { "unmarkText" "void" { "id" "SEL" }
314     [ 2drop ]
315 }
316
317 { "validAttributesForMarkedText" "id" { "id" "SEL" }
318     [ 2drop NSArray -> array ]
319 }
320
321 { "attributedSubstringFromRange:" "id" { "id" "SEL" "NSRange" }
322     [ 3drop f ]
323 }
324
325 { "characterIndexForPoint:" "uint" { "id" "SEL" "NSPoint" }
326     [ 3drop 0 ]
327 }
328
329 { "firstRectForCharacterRange:" "NSRect" { "id" "SEL" "NSRange" }
330     [ 3drop 0 0 0 0 <NSRect> ]
331 }
332
333 { "conversationIdentifier" "long" { "id" "SEL" }
334     [ drop alien-address ]
335 }
336
337 ! Initialization
338 { "updateFactorGadgetSize:" "void" { "id" "SEL" "id" }
339     [
340         [
341             2drop dup view-dim swap window set-gadget-dim yield
342         ] ui-try
343     ]
344 }
345
346 { "initWithFrame:pixelFormat:" "id" { "id" "SEL" "NSRect" "id" }
347     [
348         rot drop
349         SUPER-> initWithFrame:pixelFormat:
350         dup dup add-resize-observer
351     ]
352 }
353
354 { "dealloc" "void" { "id" "SEL" }
355     [
356         drop
357         dup unregister-window
358         dup remove-observer
359         SUPER-> dealloc
360     ]
361 } ;
362
363 : <FactorView> ( world -- view )
364     FactorView over rect-dim <GLView> [ register-window ] keep ;
365
366 CLASS: {
367     { +superclass+ "NSObject" }
368     { +name+ "FactorWindowDelegate" }
369 }
370
371 { "windowDidMove:" "void" { "id" "SEL" "id" }
372     [
373         2nip -> object
374         dup window-content-rect NSRect-x-y 2array
375         swap -> contentView window set-world-loc
376     ]
377 }
378
379 { "windowDidBecomeKey:" "void" { "id" "SEL" "id" }
380     [
381         2nip -> object -> contentView window focus-world
382     ]
383 }
384
385 { "windowDidResignKey:" "void" { "id" "SEL" "id" }
386     [
387         forget-rollover
388         2nip -> object -> contentView window unfocus-world
389     ]
390 }
391
392 { "windowShouldClose:" "bool" { "id" "SEL" "id" }
393     [
394         3drop t
395     ]
396 }
397
398 { "windowWillClose:" "void" { "id" "SEL" "id" }
399     [
400         2nip -> object -> contentView window ungraft
401     ]
402 } ;
403
404 : install-window-delegate ( window -- )
405     FactorWindowDelegate install-delegate ;