1 ! Copyright (C) 2008, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays colors fry kernel math
4 math.geometry.rect math.order math.vectors namespaces opengl
5 sequences ui.gadgets ui.gadgets.scrollers ui.gadgets.status-bar
6 ui.gadgets.worlds ui.gadgets.theme ui.gestures ui.render ui.text
7 ui.gadgets.menus models math.ranges sequences combinators ;
10 ! Row rendererer protocol
11 GENERIC: row-columns ( row renderer -- columns )
12 GENERIC: row-value ( row renderer -- object )
14 SINGLETON: trivial-renderer
16 M: trivial-renderer row-columns drop ;
17 M: object row-value drop ;
20 renderer filled-column column-alignment action hook
21 column-widths total-width
22 font text-color selection-color focus-border-color
23 mouse-color column-line-color selection-required?
24 selected-index selected-value
28 : <table> ( rows -- table )
31 trivial-renderer >>renderer
34 f <model> >>selected-value
35 sans-serif-font >>font
36 selection-color >>selection-color
37 focus-border-color >>focus-border-color
38 dark-gray >>column-line-color
44 : line-height ( table -- n )
45 font>> "" text-height ;
49 : table-rows ( table -- rows )
50 [ control-value ] [ renderer>> ] bi '[ _ row-columns ] map ;
52 : (compute-column-widths) ( font rows -- total widths )
54 [ nip first length 0 <repetition> ] 2keep
55 [ [ text-width ] with map vmax ] with each
56 [ [ sum ] [ length 1 [-] table-gap * ] bi + ] keep
59 : compute-column-widths ( table -- total-width column-widths )
60 [ font>> ] [ table-rows ] bi (compute-column-widths) ;
62 : update-cached-widths ( table -- )
63 dup compute-column-widths
64 [ >>total-width ] [ >>column-widths ] bi*
67 : filled-column-width ( table -- n )
68 [ dim>> first ] [ total-width>> ] bi [-] ;
70 : update-filled-column ( table -- )
71 [ filled-column-width ]
73 [ column-widths>> ] tri
75 [ [ + ] change-nth ] [ 3drop ] if ;
78 [ update-cached-widths ] [ update-filled-column ] bi ;
80 : row-rect ( table row -- rect )
81 [ [ line-height ] dip * 0 swap 2array ]
82 [ drop [ dim>> first ] [ line-height ] bi 2array ] 2bi <rect> ;
84 : highlight-row ( table row color quot -- )
85 [ [ row-rect rect-bounds ] dip gl-color ] dip
86 '[ _ @ ] with-translation ; inline
88 : draw-selected-row ( table row -- )
89 over selection-color>> [ gl-fill-rect ] highlight-row ;
91 : draw-focused-row ( table row -- )
93 over focus-border-color>> [ gl-rect ] highlight-row
96 : draw-selected ( table -- )
97 dup selected-index>> dup
98 [ [ draw-selected-row ] [ draw-focused-row ] 2bi ]
102 : draw-moused ( table -- )
103 dup mouse-index>> dup [
104 over mouse-color>> [ gl-rect ] highlight-row
107 : column-offsets ( table -- xs )
108 0 [ table-gap + + ] accumulate nip ;
110 : column-line-offsets ( table -- xs )
112 [ f ] [ rest-slice [ table-gap 2/ - ] map ] if-empty ;
114 : draw-columns ( table -- )
115 [ column-line-color>> gl-color ]
117 [ column-widths>> column-line-offsets ] [ dim>> second ] bi
118 '[ [ 0 2array ] [ _ 2array ] bi gl-line ] each
121 : y>row ( y table -- n )
124 : validate-row ( m table -- n )
125 control-value [ drop f ] [ length 1- min 0 max ] if-empty ;
127 : visible-row ( table quot -- n )
129 [ clip get @ origin get [ second ] bi@ - ] dip
131 ] keep validate-row ; inline
133 : first-visible-row ( table -- n )
134 [ loc>> ] visible-row ;
136 : last-visible-row ( table -- n )
137 [ rect-extent nip ] visible-row 1+ ;
139 : column-loc ( font column width align -- loc )
140 [ [ text-width ] dip swap - ] dip
143 : draw-column ( font column width align -- )
145 [ 2dup ] 2dip column-loc draw-text
146 ] dip table-gap + 0 2array gl-translate ;
148 : draw-row ( columns widths align font -- )
149 '[ [ _ ] 3dip draw-column ] 3each ;
151 : each-slice-index ( from to seq quot -- )
152 [ [ <slice> ] [ drop [a,b) ] 3bi ] dip 2each ; inline
154 : column-alignment ( table -- seq )
155 dup column-alignment>>
156 [ ] [ column-widths>> length 0 <repetition> ] ?if ;
158 : draw-rows ( table -- )
160 [ text-color>> gl-color ]
161 [ first-visible-row ]
170 [ 0 ] dip _ * 2array [
171 _ row-columns _ _ _ draw-row
175 M: table draw-gadget*
176 dup control-value empty? [ drop ] [
188 [ compute-column-widths drop ] keep
189 [ font>> "" text-height ]
190 [ control-value length ]
193 : nth-row ( row table -- value/f ? )
194 over [ control-value nth t ] [ 2drop f f ] if ;
198 : (selected-row) ( table -- value/f ? )
199 [ selected-index>> ] keep nth-row ;
201 : selected-row ( table -- value/f ? )
202 [ (selected-row) ] keep
203 swap [ renderer>> row-value t ] [ 2drop f f ] if ;
207 : update-selected-value ( table -- )
208 [ selected-row drop ] [ selected-value>> ] bi set-model ;
210 : initial-selected-index ( model table -- n/f )
211 [ value>> length 1 >= ] [ selection-required?>> ] bi* and 0 f ? ;
213 : show-row-summary ( table n -- )
215 [ swap [ renderer>> row-value ] keep show-summary ]
219 M: table model-changed
220 [ nip ] [ initial-selected-index ] 2bi {
221 [ >>selected-index drop ]
223 [ drop update-selected-value ]
227 : thin-row-rect ( table row -- rect )
228 row-rect [ { 0 1 } v* ] change-dim ;
230 : (select-row) ( table n -- )
231 [ dup [ [ thin-row-rect ] [ drop ] 2bi scroll>rect ] [ 2drop ] if ]
232 [ >>selected-index relayout-1 ]
235 : mouse-row ( table -- n )
236 [ hand-rel second ] keep y>row ;
238 : table-button-down ( table -- )
240 dup control-value empty? [ drop ] [
241 dup [ mouse-row ] keep validate-row
242 [ >>mouse-index ] [ (select-row) ] bi
247 : row-action ( table -- )
248 dup selected-row [ swap action>> call ] [ 2drop ] if ;
252 : table-button-up ( table -- )
254 [ row-action ] [ update-selected-value ] if ;
256 : select-row ( table n -- )
259 [ drop update-selected-value ]
263 : prev/next-row ( table n -- )
264 [ dup selected-index>> ] dip '[ _ + ] [ 0 ] if* select-row ;
266 : prev-row ( table -- )
269 : next-row ( table -- )
272 : first-row ( table -- )
275 : last-row ( table -- )
276 dup control-value length 1- select-row ;
278 : hide-mouse-help ( table -- )
279 f >>mouse-index [ hide-status ] [ relayout-1 ] bi ;
281 : valid-row? ( row table -- ? )
282 control-value length 1- 0 swap between? ;
284 : if-mouse-row ( table true false -- )
285 [ [ mouse-row ] keep 2dup valid-row? ]
286 [ ] [ '[ nip @ ] ] tri* if ; inline
288 : show-mouse-help ( table -- )
291 [ >>mouse-index relayout-1 ]
294 ] [ hide-mouse-help ] if-mouse-row ;
296 : show-table-menu ( table -- )
298 tuck [ nth-row drop ] [ renderer>> row-value ] [ hook>> ] tri
300 ] [ drop ] if-mouse-row ;
303 { mouse-enter [ show-mouse-help ] }
304 { mouse-leave [ hide-mouse-help ] }
305 { motion [ show-mouse-help ] }
306 { T{ button-down } [ table-button-down ] }
307 { T{ button-down f f 3 } [ show-table-menu ] }
308 { T{ button-up } [ table-button-up ] }
309 { gain-focus [ t >>focused? drop ] }
310 { lose-focus [ f >>focused? drop ] }
311 { T{ drag } [ table-button-down ] }
312 { T{ key-down f f "RET" } [ row-action ] }
313 { T{ key-down f f "UP" } [ prev-row ] }
314 { T{ key-down f f "DOWN" } [ next-row ] }
315 { T{ key-down f f "HOME" } [ first-row ] }
316 { T{ key-down f f "END" } [ last-row ] }