plus de décalage entre exécution des noteon/off et leur log.
[minwii.git] / src / pgu / gui / button.py
1 """
2 """
3
4 from pygame.locals import *
5
6 from const import *
7 import widget, surface
8 import basic
9
10 class _button(widget.Widget):
11 def __init__(self,**params):
12 widget.Widget.__init__(self,**params)
13 self.state = 0
14
15 def event(self,e):
16 if e.type == ENTER: self.repaint()
17 elif e.type == EXIT: self.repaint()
18 elif e.type == FOCUS: self.repaint()
19 elif e.type == BLUR: self.repaint()
20 elif e.type == KEYDOWN:
21 if e.key == K_SPACE or e.key == K_RETURN:
22 self.state = 1
23 self.repaint()
24 elif e.type == MOUSEBUTTONDOWN:
25 self.state = 1
26 self.repaint()
27 elif e.type == KEYUP:
28 if self.state == 1:
29 sub = pygame.event.Event(CLICK,{'pos':(0,0),'button':1})
30 #self.send(sub.type,sub)
31 self._event(sub)
32
33 self.state = 0
34 self.repaint()
35 elif e.type == MOUSEBUTTONUP:
36 self.state = 0
37 self.repaint()
38 elif e.type == CLICK:
39 self.click()
40
41 self.pcls = ""
42 if self.state == 0 and self.container.myhover is self:
43 self.pcls = "hover"
44 if self.state == 1 and self.container.myhover is self:
45 self.pcls = "down"
46
47 def click(self):
48 pass
49
50
51 class Button(_button):
52 """A button, buttons can be clicked, they are usually used to set up callbacks.
53
54 <pre>Button(value=None)</pre>
55
56 <dl>
57 <dt>value<dd>either a widget or a string
58 </dl>
59
60 <strong>Example</strong>
61 <code>
62 w = gui.Button("Click Me")
63 w.connect(gui.CLICK,fnc,value)
64 </code>
65 """
66 def __init__(self,value=None,**params):
67 params.setdefault('cls','button')
68 _button.__init__(self,**params)
69 self.value = value
70
71 def __setattr__(self,k,v):
72 if k == 'value' and type(v) == str: v = basic.Label(v,cls=self.cls+".label")
73 _v = self.__dict__.get(k,NOATTR)
74 self.__dict__[k]=v
75 if k == 'value' and v != None:
76 pass
77
78 if k == 'value' and _v != NOATTR and _v != None and _v != v:
79 self.send(CHANGE)
80 self.chsize()
81
82 def resize(self,width=None,height=None):
83 self.value.rect.x,self.value.rect.y = 0,0
84 self.value.rect.w,self.value.rect.h = self.value.resize(width,height)
85 return self.value.rect.w,self.value.rect.h
86 #
87 # self.value._resize()
88 # self.rect.w,self.rect.h = self.value.rect_margin.w,self.value.rect_margin.h
89 #
90 # if self.style.width: self.rect.w = max(self.rect.w,self.style.width)
91 # if self.style.height: self.rect.w = max(self.rect.w,self.style.height)
92 #
93 # xt,xr,xb,xl = self.value.getspacing()
94 #
95 # self.value._resize(self.rect.w-(xl+xr),self.rect.h-(xt+xb))
96 #
97 def paint(self,s):
98 self.value.pcls = self.pcls
99 self.value.paint(surface.subsurface(s,self.value.rect))
100
101 class Switch(_button):
102 """A switch can have two states, True or False.
103
104 <pre>Switch(value=False)</pre>
105
106 <dl>
107 <dt>value<dd>initial value, (True, False)
108 </dl>
109
110 <strong>Example</strong>
111 <code>
112 w = gui.Switch(True)
113 w.connect(gui.CHANGE,fnc,value)
114 </code>
115 """
116 def __init__(self,value=False,**params):
117 params.setdefault('cls','switch')
118 _button.__init__(self,**params)
119 self.value = value
120
121 img = self.style.off
122 self.style.width = img.get_width()
123 self.style.height = img.get_height()
124
125 def paint(self,s):
126 #self.pcls = ""
127 #if self.container.myhover is self: self.pcls = "hover"
128 if self.value: img = self.style.on
129 else: img = self.style.off
130 s.blit(img,(0,0))
131
132 def __setattr__(self,k,v):
133 _v = self.__dict__.get(k,NOATTR)
134 self.__dict__[k]=v
135 if k == 'value' and _v != NOATTR and _v != v:
136 self.send(CHANGE)
137 self.repaint()
138
139 def click(self):
140 self.value = not self.value
141
142 class Checkbox(_button):
143 """Within a Group of Checkbox widgets several may be selected at a time.
144
145 <pre>Checkbox(group,value=None)</pre>
146
147 <dl>
148 <dt>group<dd>a gui.Group for the Checkbox to belong to
149 <dt>value<dd>the value
150 </dl>
151
152 <strong>Example</strong>
153 <code>
154 g = gui.Group(name='colors',value=['r','b'])
155
156 t = gui.Table()
157 t.tr()
158 t.td(gui.Label('Red'))
159 t.td(gui.Checkbox(g,'r'))
160 t.tr()
161 t.td(gui.Label('Green'))
162 t.td(gui.Checkbox(g,'g'))
163 t.tr()
164 t.td(gui.Label('Blue'))
165 t.td(gui.Checkbox(g,'b'))
166 </code>
167 """
168
169 def __init__(self,group,value=None,**params):
170 params.setdefault('cls','checkbox')
171 _button.__init__(self,**params)
172 self.group = group
173 self.group.add(self)
174 if self.group.value == None:
175 self.group.value = []
176 self.value = value
177
178 img = self.style.off
179 self.style.width = img.get_width()
180 self.style.height = img.get_height()
181
182 def paint(self,s):
183 #self.pcls = ""
184 #if self.container.myhover is self: self.pcls = "hover"
185 if self.value in self.group.value: img = self.style.on
186 else: img = self.style.off
187
188 s.blit(img,(0,0))
189
190 def click(self):
191 if self.value in self.group.value:
192 self.group.value.remove(self.value)
193 else:
194 self.group.value.append(self.value)
195 self.group._change()
196
197 class Radio(_button):
198 """Within a Group of Radio widgets only one may be selected at a time.
199
200 <pre>Radio(group,value=None)</pre>
201
202 <dl>
203 <dt>group<dd>a gui.Group for the Radio to belong to
204 <dt>value<dd>the value
205 </dl>
206
207 <strong>Example</strong>
208 <code>
209 g = gui.Group(name='colors',value='g')
210
211 t = gui.Table()
212 t.tr()
213 t.td(gui.Label('Red'))
214 t.td(gui.Radio(g,'r'))
215 t.tr()
216 t.td(gui.Label('Green'))
217 t.td(gui.Radio(g,'g'))
218 t.tr()
219 t.td(gui.Label('Blue'))
220 t.td(gui.Radio(g,'b'))
221 </code>
222 """
223
224
225 def __init__(self,group=None,value=None,**params):
226 params.setdefault('cls','radio')
227 _button.__init__(self,**params)
228 self.group = group
229 self.group.add(self)
230 self.value = value
231
232 img = self.style.off
233 self.style.width = img.get_width()
234 self.style.height = img.get_height()
235
236 def paint(self,s):
237 #self.pcls = ""
238 #if self.container.myhover is self: self.pcls = "hover"
239 if self.group.value == self.value: img = self.style.on
240 else: img = self.style.off
241 s.blit(img,(0,0))
242
243 def click(self):
244 self.group.value = self.value
245
246 class Tool(_button):
247 """Within a Group of Tool widgets only one may be selected at a time.
248
249 <pre>Tool(group,widget=None,value=None)</pre>
250
251 <dl>
252 <dt>group<dd>a gui.Group for the Tool to belong to
253 <dt>widget<dd>a widget to appear on the Tool (similar to a Button)
254 <dt>value<dd>the value
255 </dl>
256
257 <strong>Example</strong>
258 <code>
259 g = gui.Group(name='colors',value='g')
260
261 t = gui.Table()
262 t.tr()
263 t.td(gui.Tool(g,'Red','r'))
264 t.tr()
265 t.td(gui.Tool(g,'Green','g'))
266 t.tr()
267 t.td(gui.Tool(g,'Blue','b'))
268 </code>
269 """
270
271 def __init__(self,group,widget=None,value=None,**params): #TODO widget= could conflict with module widget
272 params.setdefault('cls','tool')
273 _button.__init__(self,**params)
274 self.group = group
275 self.group.add(self)
276 self.value = value
277
278 if widget:
279 self.setwidget(widget)
280
281 if self.group.value == self.value: self.pcls = "down"
282
283 def setwidget(self,w):
284 self.widget = w
285
286 def resize(self,width=None,height=None):
287 self.widget.rect.w,self.widget.rect.h = self.widget.resize()
288 #self.widget._resize()
289 #self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h
290
291 return self.widget.rect.w,self.widget.rect.h
292
293 def event(self,e):
294 _button.event(self,e)
295 if self.group.value == self.value: self.pcls = "down"
296
297 def paint(self,s):
298 if self.group.value == self.value: self.pcls = "down"
299 self.widget.paint(surface.subsurface(s,self.widget.rect))
300
301 def click(self):
302 self.group.value = self.value
303 for w in self.group.widgets:
304 if w != self: w.pcls = ""
305
306
307 class Icon(_button):
308 """TODO - might be deprecated
309 """
310 def __init__(self,cls,**params):
311 params['cls'] = cls
312 _button.__init__(self,**params)
313 s = self.style.image
314 self.style.width = s.get_width()
315 self.style.height = s.get_height()
316 self.state = 0
317
318 def paint(self,s):
319 #self.pcls = ""
320 #if self.state == 0 and hasattr(self.container,'myhover') and self.container.myhover is self: self.pcls = "hover"
321 #if self.state == 1 and hasattr(self.container,'myhover') and self.container.myhover is self: self.pcls = "down"
322 s.blit(self.style.image,(0,0))
323
324 class Link(_button):
325 """A link, links can be clicked, they are usually used to set up callbacks.
326 Basically the same as the button widget, just text only with a different cls. Made for
327 convenience.
328
329 <pre>Link(value=None)</pre>
330
331 <dl>
332 <dt>value<dd>a string
333 </dl>
334
335 <strong>Example</strong>
336 <code>
337 w = gui.Link("Click Me")
338 w.connect(gui.CLICK,fnc,value)
339 </code>
340 """
341 def __init__(self,value,**params):
342 params.setdefault('focusable',True)
343 params.setdefault('cls','link')
344 _button.__init__(self,**params)
345 self.value = value
346 self.font = self.style.font
347 self.style.width, self.style.height = self.font.size(self.value)
348
349 def paint(self,s):
350 s.blit(self.font.render(self.value, 1, self.style.color),(0,0))
351