f4fa62337985db6738fb948ca3683d21ec8297cb
[minwii.git] / src / pgu / gui / slider.py
1 """All sliders and scroll bar widgets have the same parameters.
2
3 <pre>Slider(value,min,max,size)</pre>
4 <dl>
5 <dt>value<dd>initial value
6 <dt>min<dd>minimum value
7 <dt>max<dd>maximum value
8 <dt>size<dd>size of bar in pixels
9 </dl>
10 """
11 import pygame
12 from pygame.locals import *
13
14 from const import *
15 import widget
16 import table
17 import basic
18 import pguglobals
19
20 _SLIDER_HORIZONTAL = 0
21 _SLIDER_VERTICAL = 1
22
23 class _slider(widget.Widget):
24 def __init__(self,value,orient,min,max,size,step=1,**params):
25 params.setdefault('cls','slider')
26 widget.Widget.__init__(self,**params)
27 self.min,self.max,self.value,self.orient,self.size,self.step = min,max,value,orient,size,step
28
29
30 def paint(self,s):
31
32 self.value = self.value
33 r = pygame.rect.Rect(0,0,self.style.width,self.style.height)
34 if self.orient == _SLIDER_HORIZONTAL:
35 r.x = (self.value-self.min) * (r.w-self.size) / max(1,self.max-self.min);
36 r.w = self.size;
37 else:
38 r.y = (self.value-self.min) * (r.h-self.size) / max(1,self.max-self.min);
39 r.h = self.size;
40
41 self.bar = r
42
43 pguglobals.app.theme.render(s,self.style.bar,r)
44
45 def event(self,e):
46 used = None
47 r = pygame.rect.Rect(0,0,self.style.width,self.style.height)
48 adj = 0
49 if e.type == ENTER: self.repaint()
50 elif e.type == EXIT: self.repaint()
51 elif e.type == MOUSEBUTTONDOWN:
52 if self.bar.collidepoint(e.pos):
53 self.grab = e.pos[0],e.pos[1]
54 self.grab_value = self.value
55 else:
56 x,y,adj = e.pos[0],e.pos[1],1
57 self.grab = None
58 self.repaint()
59 elif e.type == MOUSEBUTTONUP:
60 #x,y,adj = e.pos[0],e.pos[1],1
61 self.repaint()
62 elif e.type == MOUSEMOTION:
63 if 1 in e.buttons and self.container.myfocus is self:
64 if self.grab != None:
65 rel = e.pos[0]-self.grab[0],e.pos[1]-self.grab[1]
66 if self.orient == _SLIDER_HORIZONTAL:
67 d = (r.w - self.size)
68 if d != 0: self.value = self.grab_value + ((self.max-self.min) * rel[0] / d)
69 else:
70 d = (r.h - self.size)
71 if d != 0: self.value = self.grab_value + ((self.max-self.min) * rel[1] / d)
72 else:
73 x,y,adj = e.pos[0],e.pos[1],1
74
75 elif e.type is KEYDOWN:
76 if self.orient == _SLIDER_HORIZONTAL and e.key == K_LEFT:
77 self.value -= self.step
78 used = True
79 elif self.orient == _SLIDER_HORIZONTAL and e.key == K_RIGHT:
80 self.value += self.step
81 used = True
82 elif self.orient == _SLIDER_VERTICAL and e.key == K_UP:
83 self.value -= self.step
84 used = True
85 elif self.orient == _SLIDER_VERTICAL and e.key == K_DOWN:
86 self.value += self.step
87 used = True
88
89 if adj:
90 if self.orient == _SLIDER_HORIZONTAL:
91 d = self.size/2 - (r.w/(self.max-self.min+1))/2
92 self.value = (x-d) * (self.max-self.min) / (r.w-self.size+1) + self.min
93 else:
94 d = self.size/2 - (r.h/(self.max-self.min+1))/2
95 self.value = (y-d) * (self.max-self.min) / (r.h-self.size+1) + self.min
96
97 self.pcls = ""
98 if self.container.myhover is self: self.pcls = "hover"
99 if (self.container.myfocus is self and 1 in pygame.mouse.get_pressed()): self.pcls = "down"
100
101 return used
102
103
104 def __setattr__(self,k,v):
105 if k == 'value':
106 v = int(v)
107 v = max(v,self.min)
108 v = min(v,self.max)
109 _v = self.__dict__.get(k,NOATTR)
110 self.__dict__[k]=v
111 if k == 'value' and _v != NOATTR and _v != v:
112 self.send(CHANGE)
113 self.repaint()
114
115 if hasattr(self,'size'):
116 sz = min(self.size,max(self.style.width,self.style.height))
117 sz = max(sz,min(self.style.width,self.style.height))
118 self.__dict__['size'] = sz
119
120 if hasattr(self,'max') and hasattr(self,'min'):
121 if self.max < self.min: self.max = self.min
122
123 class VSlider(_slider):
124 """A verticle slider.
125
126 <pre>VSlider(value,min,max,size)</pre>
127 """
128 def __init__(self,value,min,max,size,step=1,**params):
129 params.setdefault('cls','vslider')
130 _slider.__init__(self,value,_SLIDER_VERTICAL,min,max,size,step,**params)
131
132 class HSlider(_slider):
133 """A horizontal slider.
134
135 <pre>HSlider(value,min,max,size)</pre>
136 """
137 def __init__(self,value,min,max,size,step=1,**params):
138 params.setdefault('cls','hslider')
139 _slider.__init__(self,value,_SLIDER_HORIZONTAL,min,max,size,step,**params)
140
141 class HScrollBar(table.Table):
142 """A horizontal scroll bar.
143
144 <pre>HScrollBar(value,min,max,size,step=1)</pre>
145 """
146 def __init__(self,value,min,max,size,step=1,**params):
147 params.setdefault('cls','hscrollbar')
148
149 table.Table.__init__(self,**params)
150
151 self.slider = _slider(value,_SLIDER_HORIZONTAL,min,max,size,step=step,cls=self.cls+'.slider')
152
153 self.minus = basic.Image(self.style.minus)
154 self.minus.connect(MOUSEBUTTONDOWN,self._click,-1)
155 self.slider.connect(CHANGE,self.send,CHANGE)
156
157 self.minus2 = basic.Image(self.style.minus)
158 self.minus2.connect(MOUSEBUTTONDOWN,self._click,-1)
159
160 self.plus = basic.Image(self.style.plus)
161 self.plus.connect(MOUSEBUTTONDOWN,self._click,1)
162
163 self.size = size
164
165 def _click(self,value):
166 self.slider.value += self.slider.step*value
167
168 def resize(self,width=None,height=None):
169 self.clear()
170 self.tr()
171
172 w = self.style.width
173 h = self.slider.style.height
174 ww = 0
175
176 if w > (h*2 + self.minus.style.width+self.plus.style.width):
177 self.td(self.minus)
178 ww += self.minus.style.width
179
180 self.td(self.slider)
181
182 if w > (h*2 + self.minus.style.width+self.minus2.style.width+self.plus.style.width):
183 self.td(self.minus2)
184 ww += self.minus2.style.width
185
186 if w > (h*2 + self.minus.style.width+self.plus.style.width):
187 self.td(self.plus)
188 ww += self.plus.style.width
189
190
191 #HACK: handle theme sizing properly
192 xt,xr,xb,xl = pguglobals.app.theme.getspacing(self.slider)
193 ww += xr+xl
194
195 self.slider.style.width = self.style.width - ww
196 setattr(self.slider,'size',self.size * self.slider.style.width / max(1,self.style.width))
197 return table.Table.resize(self,width,height)
198
199
200 def __setattr__(self,k,v):
201 if k in ('min','max','value','step'):
202 return setattr(self.slider,k,v)
203 self.__dict__[k]=v
204
205 def __getattr__(self,k):
206 if k in ('min','max','value','step'):
207 return getattr(self.slider,k)
208 return table.Table.__getattr__(self,k) #self.__dict__[k]
209
210 class VScrollBar(table.Table):
211 """A vertical scroll bar.
212
213 <pre>VScrollBar(value,min,max,size,step=1)</pre>
214 """
215 def __init__(self,value,min,max,size,step=1,**params):
216 params.setdefault('cls','vscrollbar')
217
218 table.Table.__init__(self,**params)
219
220 self.minus = basic.Image(self.style.minus)
221 self.minus.connect(MOUSEBUTTONDOWN,self._click,-1)
222
223 self.minus2 = basic.Image(self.style.minus)
224 self.minus2.connect(MOUSEBUTTONDOWN,self._click,-1)
225
226 self.plus = basic.Image(self.style.plus)
227 self.plus.connect(MOUSEBUTTONDOWN,self._click,1)
228
229 self.slider = _slider(value,_SLIDER_VERTICAL,min,max,size,step=step,cls=self.cls+'.slider')
230 self.slider.connect(CHANGE,self.send,CHANGE)
231
232 self.size = size
233
234 def _click(self,value):
235 self.slider.value += self.slider.step*value
236
237 def resize(self,width=None,height=None):
238 self.clear()
239
240 h = self.style.height
241 w = self.slider.style.width
242 hh = 0
243
244 if h > (w*2 + self.minus.style.height+self.plus.style.height):
245 self.tr()
246 self.td(self.minus)
247 hh += self.minus.style.height
248
249 self.tr()
250 self.td(self.slider)
251
252 if h > (w*2 + self.minus.style.height+self.minus2.style.height+self.plus.style.height):
253 self.tr()
254 self.td(self.minus2)
255 hh += self.minus2.style.height
256
257 if h > (w*2 + self.minus.style.height+self.plus.style.height):
258 self.tr()
259 self.td(self.plus)
260 hh += self.plus.style.height
261
262
263 #HACK: handle theme sizing properly
264 xt,xr,xb,xl = pguglobals.app.theme.getspacing(self.slider)
265 hh += xt+xb
266
267 self.slider.style.height = self.style.height - hh
268 setattr(self.slider,'size',self.size * self.slider.style.height / max(1,self.style.height))
269 return table.Table.resize(self,width,height)
270
271 def __setattr__(self,k,v):
272 if k in ('min','max','value','step'):
273 return setattr(self.slider,k,v)
274 self.__dict__[k]=v
275
276 def __getattr__(self,k):
277 if k in ('min','max','value','step'):
278 return getattr(self.slider,k)
279 return table.Table.__getattr__(self,k)