1 ! Copyright (C) 2005, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays kernel math models namespaces sequences
4 strings quotations assocs combinators classes colors colors.constants
5 classes.tuple opengl opengl.gl math.vectors ui.commands ui.gadgets
6 ui.gadgets.borders ui.gadgets.labels ui.gadgets.tracks
7 ui.gadgets.packs ui.gadgets.worlds ui.gestures ui.pens ui.pens.solid
8 ui.pens.image ui.pens.tile math.rectangles locals fry
10 FROM: models => change-model ;
11 IN: ui.gadgets.buttons
13 TUPLE: button < border pressed? selected? quot ;
17 : find-button ( gadget -- button )
18 [ button? ] find-parent ;
20 : buttons-down? ( -- ? )
21 hand-buttons get-global empty? not ;
23 : button-rollover? ( button -- ? )
24 hand-gadget get-global child? ;
26 : mouse-clicked? ( gadget -- ? )
27 hand-clicked get-global child? ;
31 : button-update ( button -- )
33 [ mouse-clicked? ] [ button-rollover? ] bi and
38 : button-clicked ( button -- )
41 [ dup quot>> call( button -- ) ] [ drop ] if ;
44 { T{ button-up } [ button-clicked ] }
45 { T{ button-down } [ button-update ] }
46 { mouse-leave [ button-update ] }
47 { mouse-enter [ button-update ] }
50 : new-button ( label quot class -- button )
51 [ swap >label ] dip new-border swap >>quot ; inline
53 : <button> ( label quot -- button )
58 pressed selected pressed-selected ;
60 C: <button-pen> button-pen
62 : button-pen ( button pen -- button pen )
64 { [ dup [ pressed?>> ] [ selected?>> ] bi and ] [ drop pressed-selected>> ] }
65 { [ dup pressed?>> ] [ drop pressed>> ] }
66 { [ dup selected?>> ] [ drop selected>> ] }
67 { [ dup button-rollover? ] [ drop rollover>> ] }
71 M: button-pen draw-interior
72 button-pen dup [ draw-interior ] [ 2drop ] if ;
74 M: button-pen draw-boundary
75 button-pen dup [ draw-boundary ] [ 2drop ] if ;
77 M: button-pen pen-pref-dim
80 [ plain>> pen-pref-dim ]
81 [ rollover>> pen-pref-dim ]
82 [ pressed>> pen-pref-dim ]
83 [ selected>> pen-pref-dim ]
85 ] [ vmax ] reduce-outputs ;
87 M: button-pen pen-background
88 button-pen pen-background ;
90 M: button-pen pen-foreground
91 button-pen pen-foreground ;
95 : align-left ( button -- button )
96 { 0 1/2 } >>align ; inline
98 : roll-button-theme ( button -- button )
99 f COLOR: black <solid> dup f f <button-pen> >>boundary
100 f f COLOR: dark-gray <solid> f f <button-pen> >>interior
105 : <roll-button> ( label quot -- button )
106 <button> roll-button-theme ;
110 : <border-button-state-pen> ( prefix background foreground -- pen )
112 "-left" "-middle" "-right"
113 [ append theme-image ] tri-curry@ tri
116 CONSTANT: button-background
125 CONSTANT: button-clicked-background
134 : <border-button-pen> ( -- pen )
135 "button" button-background COLOR: black <border-button-state-pen> dup
136 "button-clicked" button-clicked-background COLOR: white <border-button-state-pen> dup dup
139 : border-button-theme ( gadget -- gadget )
140 horizontal >>orientation
141 <border-button-pen> >>interior
142 dup dup interior>> pen-pref-dim >>min-dim
143 { 10 0 } >>size ; inline
147 : <border-button> ( label quot -- button )
148 <button> border-button-theme ;
150 TUPLE: repeat-button < button ;
153 { T{ button-down } [ button-clicked ] }
154 { T{ drag } [ button-clicked ] }
155 { T{ button-up } [ button-update ] }
158 : <repeat-button> ( label quot -- button )
159 #! Button that calls the quotation every 100ms as long as
160 #! the mouse is held down.
161 repeat-button new-button border-button-theme ;
165 : <checkmark-pen> ( -- pen )
166 "checkbox" theme-image <image-pen>
167 "checkbox" theme-image <image-pen>
168 "checkbox-clicked" theme-image <image-pen>
169 "checkbox-set" theme-image <image-pen>
170 "checkbox-set-clicked" theme-image <image-pen>
173 : <checkmark> ( -- gadget )
175 <checkmark-pen> >>interior
176 dup dup interior>> pen-pref-dim >>dim ;
178 : toggle-model ( model -- )
179 [ not ] change-model ;
183 TUPLE: checkbox < button ;
185 : <checkbox> ( model label -- checkbox )
186 <checkmark> label-on-right
187 [ model>> toggle-model ]
192 M: checkbox model-changed
193 swap value>> >>selected? relayout-1 ;
197 : <radio-pen> ( -- pen )
198 "radio" theme-image <image-pen>
199 "radio" theme-image <image-pen>
200 "radio-clicked" theme-image <image-pen>
201 "radio-set" theme-image <image-pen>
202 "radio-set-clicked" theme-image <image-pen>
205 : <radio-knob> ( -- gadget )
207 <radio-pen> >>interior
208 dup dup interior>> pen-pref-dim >>dim ;
210 TUPLE: radio-control < button value ;
212 : <radio-control> ( value model label -- control )
213 [ [ value>> ] keep set-control-value ]
214 radio-control new-button
219 M: radio-control model-changed
220 2dup [ value>> ] bi@ = >>selected? relayout-1 drop ;
222 :: <radio-controls> ( parent model assoc quot: ( value model label -- gadget ) -- parent )
223 assoc model [ parent swap quot call add-gadget ] assoc-each ; inline
227 : <radio-button> ( value model label -- gadget )
228 <radio-knob> label-on-right <radio-control> ;
230 : <radio-buttons> ( model assoc -- gadget )
232 [ <radio-button> ] <radio-controls>
235 : command-button-quot ( target command -- quot )
236 '[ _ _ invoke-command ] ;
238 : <command-button> ( target gesture command -- button )
239 [ command-string swap ] keep command-button-quot
240 '[ drop @ ] <border-button> ;
242 : <toolbar> ( target -- toolbar )
247 [ [ "toolbar" ] dip class command-map commands>> ]
248 [ '[ [ _ ] 2dip <command-button> add-gadget ] ]
251 : add-toolbar ( track -- track )
252 dup <toolbar> { 3 3 } <border> align-left f track-add ;