1 ! Copyright (C) 2005, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays hashtables io kernel namespaces sequences
4 strings quotations math opengl combinators memoize math.vectors
5 sorting splitting assocs classes.tuple models continuations
6 destructors accessors math.rectangles fry fonts ui.pens.solid
7 ui.images ui.gadgets ui.gadgets.private ui.gadgets.borders
8 ui.gadgets.buttons ui.gadgets.labels ui.gadgets.scrollers
9 ui.gadgets.paragraphs ui.gadgets.incremental ui.gadgets.packs
10 ui.gadgets.menus ui.clipboards ui.gestures ui.traverse ui.render
11 ui.text ui.gadgets.presentations ui.gadgets.grids ui.gadgets.tracks
12 ui.gadgets.icons ui.gadgets.grid-lines ui.baseline-alignment
13 colors call io.styles ;
17 output current input last-line prototype scrolls?
18 selection-color caret mark selecting? ;
20 : clear-selection ( pane -- pane )
21 f >>caret f >>mark ; inline
23 : prepare-last-line ( pane -- )
25 [ current>> f track-add ]
26 [ input>> [ 1 track-add ] when* ] bi
29 : init-current ( pane -- pane )
30 dup prototype>> clone >>current ; inline
32 : focus-input ( pane -- )
33 input>> [ request-focus ] when* ;
35 : next-line ( pane -- )
38 [ init-current prepare-last-line ]
41 : pane-caret&mark ( pane -- caret mark )
42 [ caret>> ] [ mark>> ] bi ; inline
44 : selected-children ( pane -- seq )
45 [ pane-caret&mark sort-pair ] keep gadget-subtree ;
47 M: pane gadget-selection? pane-caret&mark and ;
49 M: pane gadget-selection ( pane -- string/f )
50 selected-children gadget-text ;
52 : pane-clear ( pane -- )
54 [ output>> clear-incremental ]
55 [ current>> clear-gadget ]
58 : init-prototype ( pane -- pane )
59 <shelf> +baseline+ >>align >>prototype ; inline
61 : init-output ( pane -- pane )
62 <incremental> [ >>output ] [ f track-add ] bi ; inline
64 : pane-theme ( pane -- pane )
66 selection-color >>selection-color ; inline
68 : init-last-line ( pane -- pane )
70 [ >>last-line ] [ 1 track-add ] bi
71 dup prepare-last-line ; inline
73 : new-pane ( input class -- pane )
74 [ vertical ] dip new-track
80 init-last-line ; inline
82 : <pane> ( -- pane ) f pane new-pane ;
84 GENERIC: draw-selection ( loc obj -- )
86 : if-fits ( rect quot -- )
87 [ clip get over contains-rect? ] dip [ drop ] if ; inline
89 M: gadget draw-selection ( loc gadget -- )
96 M: node draw-selection ( loc node -- )
97 2dup value>> swap offset-rect [
99 [ value>> loc>> v+ ] keep
100 children>> [ draw-selection ] with each
104 dup gadget-selection? [
105 [ selection-color>> gl-color ]
107 [ loc>> vneg ] keep selected-children
108 [ draw-selection ] with each
112 : scroll-pane ( pane -- )
113 dup scrolls?>> [ scroll>bottom ] [ drop ] if ;
115 TUPLE: pane-stream pane ;
117 C: <pane-stream> pane-stream
119 : smash-line ( current -- gadget )
121 { [ dup empty? ] [ 2drop "" <label> ] }
122 { [ dup length 1 = ] [ nip first ] }
126 : smash-pane ( pane -- gadget ) output>> smash-line ;
128 : pane-nl ( pane -- )
130 [ current>> [ unparent ] [ smash-line ] bi ] [ output>> ] bi
134 : pane-write ( seq pane -- )
135 [ pane-nl ] [ current>> stream-write ]
136 bi-curry interleave ;
138 : pane-format ( seq style pane -- )
139 [ nip pane-nl ] [ current>> stream-format ]
140 bi-curry bi-curry interleave ;
142 GENERIC: write-gadget ( gadget stream -- )
144 M: pane-stream write-gadget ( gadget pane-stream -- )
145 pane>> current>> swap add-gadget drop ;
147 M: style-stream write-gadget
148 stream>> write-gadget ;
150 : print-gadget ( gadget stream -- )
151 [ write-gadget ] [ nip stream-nl ] 2bi ;
153 : gadget. ( gadget -- )
154 output-stream get print-gadget ;
157 dup pane>> current>> children>> empty?
158 [ dup stream-nl ] unless drop ;
160 : with-pane ( pane quot -- )
162 over pane-clear [ <pane-stream> ] dip
163 over [ with-output-stream* ] dip ?nl ; inline
165 : make-pane ( quot -- gadget )
166 <pane> [ swap with-pane ] keep smash-pane ; inline
168 TUPLE: pane-control < pane quot ;
170 M: pane-control model-changed ( model pane-control -- )
171 [ value>> ] [ dup quot>> ] bi*
172 '[ _ call( value -- ) ] with-pane ;
174 : <pane-control> ( model quot -- pane )
175 f pane-control new-pane
179 : do-pane-stream ( pane-stream quot -- )
180 [ pane>> ] dip keep scroll-pane ; inline
182 M: pane-stream stream-nl
183 [ pane-nl ] do-pane-stream ;
185 M: pane-stream stream-write1
186 [ current>> stream-write1 ] do-pane-stream ;
188 M: pane-stream stream-write
189 [ [ string-lines ] dip pane-write ] do-pane-stream ;
191 M: pane-stream stream-format
192 [ [ string-lines ] 2dip pane-format ] do-pane-stream ;
194 M: pane-stream dispose drop ;
196 M: pane-stream stream-flush drop ;
198 M: pane-stream make-span-stream
199 swap <style-stream> <ignore-close-stream> ;
203 MEMO: specified-font ( assoc -- font )
204 #! We memoize here to avoid creating lots of duplicate font objects.
205 [ monospace-font <font> ] dip
207 [ font-name swap at >>name ]
212 { bold [ t >>bold? ] }
213 { italic [ t >>italic? ] }
214 { bold-italic [ t >>bold? t >>italic? ] }
217 [ font-size swap at >>size ]
218 [ foreground swap at >>foreground ]
219 [ background swap at >>background ]
223 : apply-font-style ( style gadget -- style gadget )
224 { font-name font-style font-size foreground background }
225 pick extract-keys specified-font >>font ;
227 : apply-style ( style gadget key quot -- style gadget )
228 [ pick at ] dip when* ; inline
230 : apply-presentation-style ( style gadget -- style gadget )
231 presented [ <presentation> ] apply-style ;
233 : apply-image-style ( style gadget -- style gadget )
234 image [ nip <image-name> <icon> ] apply-style ;
236 : apply-background-style ( style gadget -- style gadget )
237 background [ <solid> >>interior ] apply-style ;
239 : style-label ( style gadget -- gadget )
241 apply-background-style
242 apply-presentation-style
246 : <styled-label> ( style text -- gadget )
247 <label> style-label ;
251 : apply-wrap-style ( style pane -- style pane )
253 2dup <paragraph> >>prototype drop
254 <paragraph> >>current
257 : apply-border-color-style ( style gadget -- style gadget )
258 border-color [ <solid> >>boundary ] apply-style ;
260 : apply-page-color-style ( style gadget -- style gadget )
261 page-color [ <solid> >>interior ] apply-style ;
263 : apply-border-width-style ( style gadget -- style gadget )
264 border-width [ dup 2array <border> ] apply-style ;
266 : style-pane ( style pane -- pane )
267 apply-border-width-style
268 apply-border-color-style
269 apply-page-color-style
270 apply-presentation-style
273 TUPLE: nested-pane-stream < pane-stream style parent ;
275 : new-nested-pane-stream ( style parent class -- stream )
278 swap <pane> apply-wrap-style [ >>style ] [ >>pane ] bi* ;
281 : unnest-pane-stream ( stream -- child parent )
284 over pane>> smash-pane style-pane
287 TUPLE: pane-block-stream < nested-pane-stream ;
289 M: pane-block-stream dispose
290 unnest-pane-stream write-gadget ;
292 M: pane-stream make-block-stream
293 pane-block-stream new-nested-pane-stream ;
296 : apply-table-gap-style ( style grid -- style grid )
297 table-gap [ >>gap ] apply-style ;
299 : apply-table-border-style ( style grid -- style grid )
300 table-border [ <grid-lines> >>boundary ]
303 : styled-grid ( style grid -- grid )
306 apply-table-gap-style
307 apply-table-border-style
310 TUPLE: pane-cell-stream < nested-pane-stream ;
312 M: pane-cell-stream dispose ?nl ;
314 M: pane-stream make-cell-stream
315 pane-cell-stream new-nested-pane-stream ;
317 M: pane-stream stream-write-table
319 swap [ [ pane>> smash-pane ] map ] map
324 M: pack dispose drop ;
326 M: paragraph dispose drop ;
328 : gadget-write ( string gadget -- )
330 [ 2drop ] [ <label> text-theme add-gadget drop ] if ;
332 M: pack stream-write gadget-write ;
334 : gadget-bl ( style stream -- )
335 swap " " <word-break-gadget> style-label add-gadget drop ;
337 M: paragraph stream-write
339 [ H{ } over gadget-bl ] [ over gadget-write ] interleave
342 : gadget-write1 ( char gadget -- )
343 [ 1string ] dip stream-write ;
345 M: pack stream-write1 gadget-write1 ;
347 M: paragraph stream-write1
349 [ H{ } swap gadget-bl drop ] [ gadget-write1 ] if ;
351 : empty-output? ( string style -- ? )
352 [ empty? ] [ image swap key? not ] bi* and ;
354 : gadget-format ( string style stream -- )
355 [ [ empty-output? ] 2keep ] dip
356 '[ _ _ swap <styled-label> _ swap add-gadget drop ] unless ;
358 M: pack stream-format
361 M: paragraph stream-format
362 over { presented image } [ swap key? ] with any? [
366 [ gadget-bl ] [ gadget-format ] bi-curry bi-curry
370 : caret>mark ( pane -- )
371 dup caret>> >>mark relayout-1 ;
373 GENERIC: sloppy-pick-up* ( loc gadget -- n )
375 M: pack sloppy-pick-up* ( loc gadget -- n )
376 [ orientation>> ] [ children>> ] bi (fast-children-on) ;
378 M: gadget sloppy-pick-up*
379 children>> [ contains-point? ] with find-last drop ;
384 : wet-and-sloppy ( loc gadget n -- newloc newgadget )
385 swap nth-gadget [ loc>> v- ] keep ;
387 : sloppy-pick-up ( loc gadget -- path )
388 2dup sloppy-pick-up* dup
389 [ [ wet-and-sloppy sloppy-pick-up ] keep prefix ]
393 : move-caret ( pane loc -- )
394 over screen-loc v- over sloppy-pick-up >>caret
397 : begin-selection ( pane -- )
399 dup hand-loc get move-caret
403 : extend-selection ( pane -- )
407 hand-loc get move-caret
409 dup hand-clicked get child? [
411 [ hand-clicked set-global ]
412 [ hand-click-loc get move-caret ]
417 ] [ dup caret>> gadget-at-path scroll>gadget ] bi
420 : end-selection ( pane -- )
423 [ [ com-copy-selection ] [ request-focus ] bi ]
424 [ [ relayout-1 ] [ focus-input ] bi ]
427 : select-to-caret ( pane -- )
429 [ dup mark>> [ dup caret>mark ] unless hand-loc get move-caret ]
430 [ com-copy-selection ]
434 : pane-menu ( pane -- ) { com-copy } show-commands-menu ;
437 { T{ button-down } [ begin-selection ] }
438 { T{ button-down f { S+ } 1 } [ select-to-caret ] }
439 { T{ button-up f { S+ } 1 } [ end-selection ] }
440 { T{ button-up } [ end-selection ] }
441 { T{ drag } [ extend-selection ] }
442 { copy-action [ com-copy ] }
443 { T{ button-down f f 3 } [ pane-menu ] }