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 TUPLE: pane-stream pane ;
22 C: <pane-stream> pane-stream
24 M: pane-stream stream-element-type drop +character+ ;
28 : clear-selection ( pane -- pane )
29 f >>caret f >>mark ; inline
31 : prepare-last-line ( pane -- )
33 [ current>> f track-add ]
34 [ input>> [ 1 track-add ] when* ] bi
37 : init-current ( pane -- pane )
38 dup prototype>> clone >>current ; inline
40 : focus-input ( pane -- )
41 input>> [ request-focus ] when* ;
43 : next-line ( pane -- )
46 [ init-current prepare-last-line ]
49 : pane-caret&mark ( pane -- caret mark )
50 [ caret>> ] [ mark>> ] bi ; inline
52 : selected-children ( pane -- seq )
53 [ pane-caret&mark sort-pair ] keep gadget-subtree ;
55 M: pane gadget-selection? pane-caret&mark and ;
57 M: pane gadget-selection ( pane -- string/f )
58 selected-children gadget-text ;
60 : init-prototype ( pane -- pane )
61 <shelf> +baseline+ >>align >>prototype ; inline
63 : init-output ( pane -- pane )
64 <incremental> [ >>output ] [ f track-add ] bi ; inline
66 : pane-theme ( pane -- pane )
68 selection-color >>selection-color ; inline
70 : init-last-line ( pane -- pane )
71 horizontal <track> 0 >>fill +baseline+ >>align
72 [ >>last-line ] [ 1 track-add ] bi
73 dup prepare-last-line ; inline
75 GENERIC: draw-selection ( loc obj -- )
77 : if-fits ( rect quot -- )
78 [ clip get over contains-rect? ] dip [ drop ] if ; inline
80 M: gadget draw-selection ( loc gadget -- )
87 M: node draw-selection ( loc node -- )
88 2dup value>> swap offset-rect [
90 [ value>> loc>> v+ ] keep
91 children>> [ draw-selection ] with each
95 dup gadget-selection? [
96 [ selection-color>> gl-color ]
98 [ loc>> vneg ] keep selected-children
99 [ draw-selection ] with each
103 : scroll-pane ( pane -- )
104 dup scrolls?>> [ scroll>bottom ] [ drop ] if ;
106 : smash-line ( current -- gadget )
108 { [ dup empty? ] [ 2drop "" <label> ] }
109 { [ dup length 1 = ] [ nip first ] }
113 : pane-nl ( pane -- )
115 [ current>> [ unparent ] [ smash-line ] bi ] [ output>> ] bi
119 : ?pane-nl ( pane -- )
120 [ dup current>> children>> empty? [ pane-nl ] [ drop ] if ]
123 : smash-pane ( pane -- gadget ) [ pane-nl ] [ output>> smash-line ] bi ;
125 : pane-write ( seq pane -- )
126 [ pane-nl ] [ current>> stream-write ]
127 bi-curry interleave ;
129 : pane-format ( seq style pane -- )
130 [ nip pane-nl ] [ current>> stream-format ]
131 bi-curry bi-curry interleave ;
133 : do-pane-stream ( pane-stream quot -- )
134 [ pane>> ] dip keep scroll-pane ; inline
136 M: pane-stream stream-nl
137 [ pane-nl ] do-pane-stream ;
139 M: pane-stream stream-write1
140 [ current>> stream-write1 ] do-pane-stream ;
142 M: pane-stream stream-write
143 [ [ string-lines ] dip pane-write ] do-pane-stream ;
145 M: pane-stream stream-format
146 [ [ string-lines ] 2dip pane-format ] do-pane-stream ;
148 M: pane-stream dispose drop ;
150 M: pane-stream stream-flush drop ;
152 M: pane-stream make-span-stream
153 swap <style-stream> <ignore-close-stream> ;
157 : new-pane ( input class -- pane )
158 [ vertical ] dip new-track
164 init-last-line ; inline
166 : <pane> ( -- pane ) f pane new-pane ;
168 GENERIC: write-gadget ( gadget stream -- )
170 M: pane-stream write-gadget ( gadget pane-stream -- )
171 pane>> current>> swap add-gadget drop ;
173 M: style-stream write-gadget
174 stream>> write-gadget ;
176 : print-gadget ( gadget stream -- )
177 [ write-gadget ] [ nip stream-nl ] 2bi ;
179 : gadget. ( gadget -- )
180 output-stream get print-gadget ;
182 : pane-clear ( pane -- )
184 [ output>> clear-incremental ]
185 [ current>> clear-gadget ]
188 : with-pane ( pane quot -- )
189 [ [ scroll>top ] [ pane-clear ] [ <pane-stream> ] tri ] dip
190 with-output-stream* ; inline
192 : make-pane ( quot -- gadget )
193 [ <pane> ] dip [ with-pane ] [ drop smash-pane ] 2bi ; inline
195 TUPLE: pane-control < pane quot ;
197 M: pane-control model-changed ( model pane-control -- )
198 [ value>> ] [ dup quot>> ] bi*
199 '[ _ call( value -- ) ] with-pane ;
201 : <pane-control> ( model quot -- pane )
202 f pane-control new-pane
209 MEMO: specified-font ( assoc -- font )
210 #! We memoize here to avoid creating lots of duplicate font objects.
211 [ monospace-font <font> ] dip
213 [ font-name swap at >>name ]
218 { bold [ t >>bold? ] }
219 { italic [ t >>italic? ] }
220 { bold-italic [ t >>bold? t >>italic? ] }
223 [ font-size swap at >>size ]
224 [ foreground swap at >>foreground ]
225 [ background swap at >>background ]
229 : apply-font-style ( style gadget -- style gadget )
230 { font-name font-style font-size foreground background }
231 pick extract-keys specified-font >>font ;
233 : apply-style ( style gadget key quot -- style gadget )
234 [ pick at ] dip when* ; inline
236 : apply-presentation-style ( style gadget -- style gadget )
237 presented [ <presentation> ] apply-style ;
239 : apply-image-style ( style gadget -- style gadget )
240 image [ nip <image-name> <icon> ] apply-style ;
242 : apply-background-style ( style gadget -- style gadget )
243 background [ <solid> >>interior ] apply-style ;
245 : style-label ( style gadget -- gadget )
247 apply-background-style
248 apply-presentation-style
252 : <styled-label> ( style text -- gadget )
253 <label> style-label ;
257 : apply-wrap-style ( style pane -- style pane )
259 2dup <paragraph> >>prototype drop
260 <paragraph> >>current
263 : apply-border-color-style ( style gadget -- style gadget )
264 border-color [ <solid> >>boundary ] apply-style ;
266 : apply-page-color-style ( style gadget -- style gadget )
267 page-color [ <solid> >>interior ] apply-style ;
269 : apply-border-width-style ( style gadget -- style gadget )
270 border-width [ dup 2array <border> ] apply-style ;
272 : style-pane ( style pane -- pane )
273 apply-border-width-style
274 apply-border-color-style
275 apply-page-color-style
276 apply-presentation-style
279 TUPLE: nested-pane-stream < pane-stream style parent ;
281 : new-nested-pane-stream ( style parent class -- stream )
284 swap <pane> apply-wrap-style [ >>style ] [ >>pane ] bi* ;
287 : unnest-pane-stream ( stream -- child parent )
288 [ [ style>> ] [ pane>> smash-pane ] bi style-pane ] [ parent>> ] bi ;
290 TUPLE: pane-block-stream < nested-pane-stream ;
292 M: pane-block-stream dispose
293 unnest-pane-stream write-gadget ;
295 M: pane-stream make-block-stream
296 pane-block-stream new-nested-pane-stream ;
299 : apply-table-gap-style ( style grid -- style grid )
300 table-gap [ >>gap ] apply-style ;
302 : apply-table-border-style ( style grid -- style grid )
303 table-border [ <grid-lines> >>boundary ]
306 : styled-grid ( style grid -- grid )
309 apply-table-gap-style
310 apply-table-border-style
313 TUPLE: pane-cell-stream < nested-pane-stream ;
315 M: pane-cell-stream dispose drop ;
317 M: pane-stream make-cell-stream
318 pane-cell-stream new-nested-pane-stream ;
320 M: pane-stream stream-write-table
322 swap [ [ pane>> smash-pane ] map ] map
327 M: pack dispose drop ;
329 M: paragraph dispose drop ;
331 : gadget-write ( string gadget -- )
333 [ 2drop ] [ <label> text-theme add-gadget drop ] if ;
335 M: pack stream-write gadget-write ;
337 : gadget-bl ( style stream -- )
338 swap " " <word-break-gadget> style-label add-gadget drop ;
340 M: paragraph stream-write
342 [ H{ } over gadget-bl ] [ over gadget-write ] interleave
345 : gadget-write1 ( char gadget -- )
346 [ 1string ] dip stream-write ;
348 M: pack stream-write1 gadget-write1 ;
350 M: paragraph stream-write1
352 [ H{ } swap gadget-bl drop ] [ gadget-write1 ] if ;
354 : empty-output? ( string style -- ? )
355 [ empty? ] [ image swap key? not ] bi* and ;
357 : gadget-format ( string style stream -- )
358 [ [ empty-output? ] 2keep ] dip
359 '[ _ _ swap <styled-label> _ swap add-gadget drop ] unless ;
361 M: pack stream-format
364 M: paragraph stream-format
365 over { presented image } [ swap key? ] with any? [
369 [ gadget-bl ] [ gadget-format ] bi-curry bi-curry
373 : caret>mark ( pane -- )
374 dup caret>> >>mark relayout-1 ;
376 GENERIC: sloppy-pick-up* ( loc gadget -- n )
378 M: pack sloppy-pick-up* ( loc gadget -- n )
379 [ orientation>> ] [ children>> ] bi (fast-children-on) ;
381 M: gadget sloppy-pick-up*
382 children>> [ contains-point? ] with find-last drop ;
387 : wet-and-sloppy ( loc gadget n -- newloc newgadget )
388 swap nth-gadget [ loc>> v- ] keep ;
390 : sloppy-pick-up ( loc gadget -- path )
391 2dup sloppy-pick-up* dup
392 [ [ wet-and-sloppy sloppy-pick-up ] keep prefix ]
396 : move-caret ( pane loc -- )
397 over screen-loc v- over sloppy-pick-up >>caret
400 : begin-selection ( pane -- )
402 dup hand-loc get move-caret
406 : extend-selection ( pane -- )
410 hand-loc get move-caret
412 dup hand-clicked get child? [
414 [ hand-clicked set-global ]
415 [ hand-click-loc get move-caret ]
420 ] [ dup caret>> gadget-at-path scroll>gadget ] bi
423 : end-selection ( pane -- )
426 [ [ com-copy-selection ] [ request-focus ] bi ]
427 [ [ relayout-1 ] [ focus-input ] bi ]
430 : select-to-caret ( pane -- )
432 [ dup mark>> [ dup caret>mark ] unless hand-loc get move-caret ]
433 [ com-copy-selection ]
437 : pane-menu ( pane -- ) { com-copy } show-commands-menu ;
442 { T{ button-down } [ begin-selection ] }
443 { T{ button-down f { S+ } 1 } [ select-to-caret ] }
444 { T{ button-up f { S+ } 1 } [ end-selection ] }
445 { T{ button-up } [ end-selection ] }
446 { T{ drag } [ extend-selection ] }
447 { copy-action [ com-copy ] }
448 { T{ button-down f f 3 } [ pane-menu ] }