1 ! Copyright (C) 2005, 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs classes colors colors.constants combinators
4 combinators.short-circuit combinators.smart fry kernel locals
5 math.vectors models namespaces sequences ui.commands ui.gadgets
6 ui.gadgets.borders ui.gadgets.labels ui.gadgets.packs
7 ui.gadgets.theme ui.gadgets.tracks ui.gadgets.worlds ui.gestures
8 ui.pens ui.pens.image ui.pens.solid ui.pens.tile ;
9 FROM: models => change-model ;
10 IN: ui.gadgets.buttons
12 TUPLE: button < border pressed? selected? quot tooltip ;
16 : find-button ( gadget -- button )
17 [ button? ] find-parent ;
19 : buttons-down? ( -- ? )
20 hand-buttons get-global empty? not ;
22 : button-rollover? ( button -- ? )
23 hand-gadget get-global child? ;
25 : mouse-clicked? ( gadget -- ? )
26 hand-clicked get-global child? ;
28 : button-pressed? ( button -- ? )
29 { [ mouse-clicked? ] [ button-rollover? ] } 1&&
34 : button-update ( button -- )
35 dup button-pressed? >>pressed? relayout-1 ;
37 : button-enter ( button -- )
38 dup tooltip>> [ over show-status ] when* button-update ;
40 : button-leave ( button -- )
41 [ hide-status ] [ button-update ] bi ;
43 : button-clicked ( button -- )
46 [ button-rollover? ] tri
47 [ dup quot>> call( button -- ) ] [ drop ] if ;
50 { T{ button-up } [ button-clicked ] }
51 { T{ button-down } [ button-update ] }
52 { mouse-leave [ button-leave ] }
53 { mouse-enter [ button-enter ] }
56 : new-button ( label quot class -- button )
57 [ swap >label ] dip new-border swap >>quot ; inline
59 : <button> ( label quot: ( button -- ) -- button )
64 pressed selected pressed-selected ;
66 C: <button-pen> button-pen
68 : lookup-button-pen ( button pen -- button pen )
70 { [ dup { [ pressed?>> ] [ selected?>> ] } 1&& ] [
71 drop pressed-selected>>
73 { [ dup pressed?>> ] [ drop pressed>> ] }
74 { [ dup selected?>> ] [ drop selected>> ] }
75 { [ dup button-rollover? ] [ drop rollover>> ] }
79 M: button-pen draw-interior
80 lookup-button-pen [ draw-interior ] [ drop ] if* ;
82 M: button-pen draw-boundary
83 lookup-button-pen [ draw-boundary ] [ drop ] if* ;
85 M: button-pen pen-pref-dim
88 [ plain>> pen-pref-dim ]
89 [ rollover>> pen-pref-dim ]
90 [ pressed>> pen-pref-dim ]
91 [ selected>> pen-pref-dim ]
93 ] [ vmax ] reduce-outputs ;
95 M: button-pen pen-background
96 lookup-button-pen pen-background ;
98 M: button-pen pen-foreground
99 lookup-button-pen pen-foreground ;
103 : align-left ( button -- button )
104 { 0 1/2 } >>align ; inline
106 : roll-button-theme ( button -- button )
107 f roll-button-rollover-border <solid> dup f f <button-pen> >>boundary
108 f f roll-button-selected-background <solid> f f <button-pen> >>interior
113 : <roll-button> ( label quot: ( button -- ) -- button )
114 <button> roll-button-theme ;
118 : <border-button-state-pen> ( prefix background foreground -- pen )
120 "-left" "-middle" "-right"
121 [ append theme-image ] tri-curry@ tri
124 : <border-button-pen> ( -- pen )
125 "button" transparent button-text-color
126 <border-button-state-pen> dup
127 "button-clicked" transparent button-clicked-text-color
128 <border-button-state-pen> dup dup
131 : border-button-label-theme ( gadget -- )
132 dup label? [ [ clone t >>bold? ] change-font ] when drop ;
134 : border-button-theme ( gadget -- gadget )
135 dup gadget-child border-button-label-theme
136 horizontal >>orientation
137 <border-button-pen> >>interior
138 dup dup interior>> pen-pref-dim >>min-dim
139 { 10 0 } >>size ; inline
143 : <border-button> ( label quot: ( button -- ) -- button )
144 <button> border-button-theme ;
146 TUPLE: repeat-button < button ;
149 { T{ button-down } [ button-clicked ] }
150 { T{ drag } [ button-clicked ] }
151 { T{ button-up } [ button-update ] }
154 : <repeat-button> ( label quot: ( button -- ) -- button )
155 ! Button that calls the quotation every 100ms as long as
156 ! the mouse is held down.
157 repeat-button new-button border-button-theme ;
161 : <checkmark-pen> ( -- pen )
162 "checkbox" theme-image <image-pen>
163 "checkbox" theme-image <image-pen>
164 "checkbox-clicked" theme-image <image-pen>
165 "checkbox-set" theme-image <image-pen>
166 "checkbox-set-clicked" theme-image <image-pen>
169 : <checkmark> ( -- gadget )
171 <checkmark-pen> >>interior
172 dup dup interior>> pen-pref-dim >>dim ;
174 : toggle-model ( model -- )
175 [ not ] change-model ;
179 TUPLE: checkbox < button ;
181 : <checkbox> ( model label -- checkbox )
182 <checkmark> label-on-right
183 [ model>> toggle-model ]
188 M: checkbox model-changed
189 swap value>> >>selected? relayout-1 ;
193 : <radio-pen> ( -- pen )
194 "radio" theme-image <image-pen>
195 "radio" theme-image <image-pen>
196 "radio-clicked" theme-image <image-pen>
197 "radio-set" theme-image <image-pen>
198 "radio-set-clicked" theme-image <image-pen>
201 : <radio-knob> ( -- gadget )
203 <radio-pen> >>interior
204 dup dup interior>> pen-pref-dim >>dim ;
206 TUPLE: radio-control < button value ;
208 : <radio-control> ( value model label -- control )
209 [ [ value>> ] keep set-control-value ]
210 radio-control new-button
215 M: radio-control model-changed
216 2dup [ value>> ] same? >>selected? relayout-1 drop ;
218 :: <radio-controls> ( model assoc parent quot: ( value model label -- gadget ) -- parent )
219 parent assoc [ model swap quot call add-gadget ] assoc-each ; inline
223 : <radio-button> ( value model label -- gadget )
224 <radio-knob> label-on-right <radio-control> ;
226 : <radio-buttons> ( model assoc -- gadget )
228 [ <radio-button> ] <radio-controls>
231 : command-button-quot ( target command -- quot )
232 '[ _ _ invoke-command ] ;
234 : gesture>tooltip ( gesture -- str/f )
235 gesture>string dup [ "Shortcut: " prepend ] when ;
237 :: <command-button> ( target gesture command -- button )
239 target command command-button-quot
240 '[ drop @ ] <border-button>
241 gesture gesture>tooltip >>tooltip ; inline