]> gitweb.factorcode.org Git - factor.git/blob - basis/ui/gadgets/buttons/buttons.factor
Cleaning up USING: lists for new strict semantics
[factor.git] / basis / ui / gadgets / buttons / buttons.factor
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
9 combinators.smart ;
10 FROM: models => change-model ;
11 IN: ui.gadgets.buttons
12
13 TUPLE: button < border pressed? selected? quot ;
14
15 <PRIVATE
16
17 : find-button ( gadget -- button )
18     [ button? ] find-parent ;
19
20 : buttons-down? ( -- ? )
21     hand-buttons get-global empty? not ;
22
23 : button-rollover? ( button -- ? )
24     hand-gadget get-global child? ;
25
26 : mouse-clicked? ( gadget -- ? )
27     hand-clicked get-global child? ;
28
29 PRIVATE>
30
31 : button-update ( button -- )
32     dup
33     [ mouse-clicked? ] [ button-rollover? ] bi and
34     buttons-down? and
35     >>pressed?
36     relayout-1 ;
37
38 : button-clicked ( button -- )
39     dup button-update
40     dup button-rollover?
41     [ dup quot>> call( button -- ) ] [ drop ] if ;
42
43 button H{
44     { T{ button-up } [ button-clicked ] }
45     { T{ button-down } [ button-update ] }
46     { mouse-leave [ button-update ] }
47     { mouse-enter [ button-update ] }
48 } set-gestures
49
50 : new-button ( label quot class -- button )
51     [ swap >label ] dip new-border swap >>quot ; inline
52
53 : <button> ( label quot -- button )
54     button new-button ;
55
56 TUPLE: button-pen
57 plain rollover
58 pressed selected pressed-selected ;
59
60 C: <button-pen> button-pen
61
62 : button-pen ( button pen -- button pen )
63     over find-button {
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>> ] }
68         [ drop plain>> ]
69     } cond ;
70
71 M: button-pen draw-interior
72     button-pen dup [ draw-interior ] [ 2drop ] if ;
73
74 M: button-pen draw-boundary
75     button-pen dup [ draw-boundary ] [ 2drop ] if ;
76
77 M: button-pen pen-pref-dim
78     [
79         {
80             [ plain>> pen-pref-dim ]
81             [ rollover>> pen-pref-dim ]
82             [ pressed>> pen-pref-dim ]
83             [ selected>> pen-pref-dim ]
84         } 2cleave
85     ] [ vmax ] reduce-outputs ;
86
87 M: button-pen pen-background
88     button-pen pen-background ;
89
90 M: button-pen pen-foreground
91     button-pen pen-foreground ;
92
93 <PRIVATE
94
95 : align-left ( button -- button )
96     { 0 1/2 } >>align ; inline
97
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
101     align-left ; inline
102
103 PRIVATE>
104
105 : <roll-button> ( label quot -- button )
106     <button> roll-button-theme ;
107
108 <PRIVATE
109
110 : <border-button-state-pen> ( prefix background foreground -- pen )
111     [
112         "-left" "-middle" "-right"
113         [ append theme-image ] tri-curry@ tri
114     ] 2dip <tile-pen> ;
115
116 CONSTANT: button-background
117     T{ rgba
118          f
119          0.8901960784313725
120          0.8862745098039215
121          0.8588235294117647
122          1.0
123     }
124
125 CONSTANT: button-clicked-background
126     T{ rgba
127          f
128          0.2156862745098039
129          0.2431372549019608
130          0.2823529411764706
131          1.0
132     }
133     
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
137     <button-pen> ;
138
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
144
145 PRIVATE>
146
147 : <border-button> ( label quot -- button )
148     <button> border-button-theme ;
149
150 TUPLE: repeat-button < button ;
151
152 repeat-button H{
153     { T{ button-down } [ button-clicked ] }
154     { T{ drag } [ button-clicked ] }
155     { T{ button-up } [ button-update ] }
156 } set-gestures
157
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 ;
162
163 <PRIVATE
164
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>
171     <button-pen> ;
172
173 : <checkmark> ( -- gadget )
174     <gadget>
175     <checkmark-pen> >>interior
176     dup dup interior>> pen-pref-dim >>dim ;
177
178 : toggle-model ( model -- )
179     [ not ] change-model ;
180
181 PRIVATE>
182
183 TUPLE: checkbox < button ;
184
185 : <checkbox> ( model label -- checkbox )
186     <checkmark> label-on-right
187     [ model>> toggle-model ]
188     checkbox new-button
189         swap >>model
190         align-left ;
191
192 M: checkbox model-changed
193     swap value>> >>selected? relayout-1 ;
194
195 <PRIVATE
196
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>
203     <button-pen> ;
204
205 : <radio-knob> ( -- gadget )
206     <gadget>
207     <radio-pen> >>interior
208     dup dup interior>> pen-pref-dim >>dim ;
209
210 TUPLE: radio-control < button value ;
211
212 : <radio-control> ( value model label -- control )
213     [ [ value>> ] keep set-control-value ]
214     radio-control new-button
215         swap >>model
216         swap >>value
217         align-left ; inline
218
219 M: radio-control model-changed
220     2dup [ value>> ] bi@ = >>selected? relayout-1 drop ;
221
222 :: <radio-controls> ( parent model assoc quot: ( value model label -- gadget ) -- parent )
223     assoc model [ parent swap quot call add-gadget ] assoc-each ; inline
224
225 PRIVATE>
226
227 : <radio-button> ( value model label -- gadget )
228     <radio-knob> label-on-right <radio-control> ;
229
230 : <radio-buttons> ( model assoc -- gadget )
231     <filled-pile>
232         [ <radio-button> ] <radio-controls>
233         { 5 5 } >>gap ;
234
235 : command-button-quot ( target command -- quot )
236     '[ _ _ invoke-command ] ;
237
238 : <command-button> ( target gesture command -- button )
239     [ command-string swap ] keep command-button-quot
240     '[ drop @ ] <border-button> ;
241
242 : <toolbar> ( target -- toolbar )
243     <shelf>
244         1 >>fill
245         { 5 5 } >>gap
246         swap
247         [ [ "toolbar" ] dip class command-map commands>> ]
248         [ '[ [ _ ] 2dip <command-button> add-gadget ] ]
249         bi assoc-each ;
250
251 : add-toolbar ( track -- track )
252     dup <toolbar> { 3 3 } <border> align-left f track-add ;