1 ! Copyright (C) 2005, 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs classes combinators destructors fonts
4 fry io io.styles kernel locals math.rectangles math.vectors
5 memoize models namespaces sequences sorting splitting strings
6 ui.baseline-alignment ui.clipboards ui.gadgets
7 ui.gadgets.borders ui.gadgets.grid-lines ui.gadgets.grids
8 ui.gadgets.icons ui.gadgets.incremental ui.gadgets.labels
9 ui.gadgets.menus ui.gadgets.packs ui.gadgets.paragraphs
10 ui.gadgets.presentations ui.gadgets.private ui.gadgets.scrollers
11 ui.gadgets.tracks ui.gestures ui.images ui.pens.solid ui.render
13 FROM: io.styles => foreground background ;
14 FROM: ui.gadgets.wrappers => <wrapper> ;
18 output current input last-line prototype scrolls?
19 selection-color caret mark selecting? ;
21 TUPLE: pane-stream pane ;
22 INSTANCE: pane-stream output-stream
24 C: <pane-stream> pane-stream
26 M: pane-stream stream-element-type drop +character+ ;
30 : clear-selection ( pane -- pane )
31 f >>caret f >>mark ; inline
33 : prepare-last-line ( pane -- )
35 [ current>> f track-add ]
36 [ input>> [ 1 track-add ] when* ] bi
39 : init-current ( pane -- pane )
40 dup prototype>> clone >>current ; inline
42 : focus-input ( pane -- )
43 input>> [ request-focus ] when* ;
45 : next-line ( pane -- )
48 [ init-current prepare-last-line ]
51 : pane-caret&mark ( pane -- caret mark )
52 [ caret>> ] [ mark>> ] bi ; inline
54 : selected-subtree ( pane -- seq )
55 [ pane-caret&mark sort-pair ] keep gadget-subtree ;
57 M: pane gadget-selection? pane-caret&mark and ;
59 M: pane gadget-selection ( pane -- string/f )
60 selected-subtree gadget-text ;
62 : init-prototype ( pane -- pane )
63 <shelf> +baseline+ >>align >>prototype ; inline
65 : init-output ( pane -- pane )
66 <incremental> [ >>output ] [ f track-add ] bi ; inline
68 : pane-theme ( pane -- pane )
70 selection-color >>selection-color ; inline
72 : init-last-line ( pane -- pane )
73 horizontal <track> 0 >>fill +baseline+ >>align
74 [ >>last-line ] [ 1 track-add ] bi
75 dup prepare-last-line ; inline
77 M: pane selected-children
78 dup gadget-selection? [
79 [ selected-subtree leaves ]
84 : scroll-pane ( pane -- )
85 dup scrolls?>> [ scroll>bottom ] [ drop ] if ;
87 : smash-line ( current -- gadget )
89 { [ dup empty? ] [ 2drop "" <label> ] }
90 { [ dup length 1 = ] [ nip first ] }
96 [ current>> [ unparent ] [ smash-line ] bi ] [ output>> ] bi
100 : smash-pane ( pane -- gadget ) [ pane-nl ] [ output>> smash-line ] bi ;
102 : pane-lines ( str -- lines )
103 string-lines [ { "" } ] when-empty ;
105 : pane-write ( seq pane -- )
106 [ pane-nl ] [ current>> stream-write ]
107 bi-curry interleave ;
109 : pane-format ( seq style pane -- )
110 [ nip pane-nl ] [ current>> stream-format ]
111 bi-curry bi-curry interleave ;
113 : do-pane-stream ( pane-stream quot -- )
114 [ pane>> ] dip keep scroll-pane ; inline
116 M: pane-stream stream-nl
117 [ pane-nl ] do-pane-stream ;
119 M: pane-stream stream-write1
120 [ current>> stream-write1 ] do-pane-stream ;
122 M: pane-stream stream-write
123 [ [ pane-lines ] dip pane-write ] do-pane-stream ;
125 M: pane-stream stream-format
126 [ [ pane-lines ] 2dip pane-format ] do-pane-stream ;
128 M: pane-stream dispose drop ;
130 M: pane-stream stream-flush drop ;
132 M: pane-stream make-span-stream
133 swap <style-stream> <ignore-close-stream> ;
137 : new-pane ( input class -- pane )
138 [ vertical ] dip new-track
144 init-last-line ; inline
146 : <pane> ( -- pane ) f pane new-pane ;
148 GENERIC: gadget-alt-text ( gadget -- string )
150 M: object gadget-alt-text
151 class-of name>> "( " " )" surround ;
153 GENERIC: write-gadget ( gadget stream -- )
155 M: object write-gadget
156 [ gadget-alt-text ] dip stream-write ;
158 M: filter-writer write-gadget
159 stream>> write-gadget ;
161 M: pane-stream write-gadget ( gadget pane-stream -- )
162 pane>> current>> swap add-gadget drop ;
164 M: style-stream write-gadget
165 stream>> write-gadget ;
167 : print-gadget ( gadget stream -- )
168 [ write-gadget ] [ nip stream-nl ] 2bi ;
170 : gadget. ( gadget -- )
171 output-stream get print-gadget ;
173 : pane-clear ( pane -- )
175 [ output>> clear-incremental ]
176 [ current>> clear-gadget ]
179 : with-pane ( pane quot -- )
180 [ [ scroll>top ] [ pane-clear ] [ <pane-stream> ] tri ] dip
181 with-output-stream* ; inline
183 : make-pane ( quot -- gadget )
184 [ <pane> ] dip [ with-pane ] [ drop smash-pane ] 2bi ; inline
186 TUPLE: pane-control < pane quot ;
188 M: pane-control model-changed ( model pane-control -- )
189 [ value>> ] [ dup quot>> ] bi*
190 '[ _ call( value -- ) ] with-pane ;
192 : <pane-control> ( model quot -- pane )
193 f pane-control new-pane
201 MEMO:: specified-font ( name style size foreground background -- font )
202 ! We memoize here to avoid creating lots of duplicate font objects.
204 name [ >>name ] when*
208 { bold [ t >>bold? ] }
209 { italic [ t >>italic? ] }
210 { bold-italic [ t >>bold? t >>italic? ] }
212 size [ >>size ] when*
213 foreground [ >>foreground ] when*
214 background [ >>background ] when* ;
216 : apply-font-style ( style gadget -- style gadget )
223 } cleave specified-font >>font ;
225 : apply-style ( style gadget key quot -- style gadget )
226 [ pick at ] dip when* ; inline
228 : apply-presentation-style ( style gadget -- style gadget )
229 presented [ <presentation> ] apply-style ;
231 : apply-image-style ( style gadget -- style gadget )
232 image-style [ nip <image-name> <icon> ] apply-style ;
234 : apply-background-style ( style gadget -- style gadget )
235 background [ <solid> >>interior ] apply-style ;
237 : style-label ( style gadget -- gadget )
239 apply-background-style
240 apply-presentation-style
244 : <styled-label> ( style text -- gadget )
245 <label> style-label ;
249 : apply-wrap-style ( style pane -- style pane )
251 2dup <paragraph> >>prototype drop
252 <paragraph> >>current
255 : apply-border-color-style ( style gadget -- style gadget )
256 border-color [ <solid> >>boundary ] apply-style ;
258 : apply-page-color-style ( style gadget -- style gadget )
259 page-color [ <solid> >>interior ] apply-style ;
261 : apply-inset-style ( style gadget -- style gadget )
262 inset [ <border> ] apply-style ;
264 : style-pane ( style pane -- pane )
266 apply-border-color-style
267 apply-page-color-style
268 apply-presentation-style
271 TUPLE: nested-pane-stream < pane-stream style parent ;
273 : new-nested-pane-stream ( style parent class -- stream )
276 swap <pane> apply-wrap-style [ >>style ] [ >>pane ] bi* ; inline
278 : unnest-pane-stream ( stream -- child parent )
279 [ [ style>> ] [ pane>> smash-pane ] bi style-pane ] [ parent>> ] bi ;
281 TUPLE: pane-block-stream < nested-pane-stream ;
283 M: pane-block-stream dispose
284 unnest-pane-stream write-gadget ;
286 M: pane-stream make-block-stream
287 pane-block-stream new-nested-pane-stream ;
291 : apply-table-gap-style ( style grid -- style grid )
292 table-gap [ >>gap ] apply-style ;
294 : apply-table-border-style ( style grid -- style grid )
295 table-border [ <grid-lines> >>boundary ] apply-style ;
297 : styled-grid ( style grid -- grid )
300 apply-table-gap-style
301 apply-table-border-style
304 TUPLE: pane-cell-stream < nested-pane-stream ;
306 M: pane-cell-stream dispose drop ;
308 M: pane-stream make-cell-stream
309 pane-cell-stream new-nested-pane-stream ;
311 M: pane-stream stream-write-table
313 swap [ [ pane>> smash-pane ] map ] map
318 M: pack dispose drop ;
320 M: paragraph dispose drop ;
322 : gadget-write ( string gadget -- )
324 [ 2drop ] [ <label> text-theme add-gadget drop ] if ;
326 M: pack stream-write gadget-write ;
328 : gadget-bl ( style stream -- )
329 swap " " <word-break-gadget> style-label add-gadget drop ;
331 M: paragraph stream-write
333 [ H{ } over gadget-bl ] [ over gadget-write ] interleave
336 : gadget-write1 ( char gadget -- )
337 [ 1string ] dip stream-write ;
339 M: pack stream-write1 gadget-write1 ;
341 M: paragraph stream-write1
343 [ H{ } swap gadget-bl drop ] [ gadget-write1 ] if ;
345 : empty-output? ( string style -- ? )
346 [ empty? ] [ image-style swap key? not ] bi* and ;
348 : gadget-format ( string style stream -- )
349 [ [ empty-output? ] 2keep ] dip
350 '[ _ _ swap <styled-label> _ swap add-gadget drop ] unless ;
352 M: pack stream-format
355 M: paragraph stream-format
356 over { presented image-style } [ swap key? ] with any? [
360 [ gadget-bl ] [ gadget-format ] bi-curry bi-curry
364 : caret>mark ( pane -- )
365 dup caret>> >>mark relayout-1 ;
367 GENERIC: sloppy-pick-up* ( loc gadget -- n )
369 M: pack sloppy-pick-up* ( loc gadget -- n )
370 [ orientation>> ] [ children>> ] bi
371 [ loc>> ] (fast-children-on) ;
373 M: gadget sloppy-pick-up*
374 children>> [ contains-point? ] with find-last drop ;
379 : wet-and-sloppy ( loc gadget n -- newloc newgadget )
380 swap nth-gadget [ loc>> v- ] keep ;
382 : sloppy-pick-up ( loc gadget -- path )
383 2dup sloppy-pick-up* dup
384 [ [ wet-and-sloppy sloppy-pick-up ] keep prefix ]
388 : move-caret ( pane loc -- )
389 over screen-loc v- over sloppy-pick-up >>caret
392 : begin-selection ( pane -- )
394 dup hand-loc get-global move-caret
398 : extend-selection ( pane -- )
402 hand-loc get-global move-caret
404 dup hand-clicked get-global child? [
406 [ hand-clicked set-global ]
407 [ hand-click-loc get-global move-caret ]
412 ] [ dup caret>> gadget-at-path scroll>gadget ] bi
415 : end-selection ( pane -- )
416 dup selecting?>> hand-moved? or
417 [ f >>selecting? ] dip
418 [ [ com-copy-selection ] [ request-focus ] bi ]
419 [ [ relayout-1 ] [ focus-input ] bi ]
422 : select-to-caret ( pane -- )
424 [ dup mark>> [ dup caret>mark ] unless hand-loc get-global move-caret ]
425 [ com-copy-selection ]
429 : pane-menu ( pane -- ) { com-copy } show-commands-menu ;
434 { T{ button-down } [ begin-selection ] }
435 { T{ button-down f { S+ } 1 } [ select-to-caret ] }
436 { T{ button-up f { S+ } 1 } [ end-selection ] }
437 { T{ button-up } [ end-selection ] }
438 { T{ drag { # 1 } } [ extend-selection ] }
439 { copy-action [ com-copy ] }
440 { T{ button-down f f 3 } [ pane-menu ] }
443 GENERIC: content-gadget ( object -- gadget/f )
444 M: object content-gadget drop f ;