8 import container
, table
10 import basic
, button
, slider
11 from pygame
.font
import Font
13 class SlideBox(container
.Container
):
14 """A scrollable area with no scrollbars.
16 <pre>SlideBox(widget,width,height)</pre>
19 <dt>widget<dd>widget to be able to scroll around
20 <dt>width, height<dd>size of scrollable area
23 <strong>Example</strong>
25 c = SlideBox(w,100,100)
32 def __init__(self
, widget
, width
, height
, **params
):
33 params
.setdefault('width', width
)
34 params
.setdefault('height', height
)
35 container
.Container
.__init
__(self
, **params
)
39 def __setattr__(self
,k
,v
):
41 if hasattr(self
,'widget'):
42 self
.remove(self
.widget
)
48 #if not hasattr(self,'surface'):
49 self
.surface
= pygame
.Surface((self
.max_rect
.w
,self
.max_rect
.h
),0,s
)
50 #self.surface.fill((0,0,0,0))
51 pguglobals
.app
.theme
.render(self
.surface
,self
.style
.background
,pygame
.Rect(0,0,self
.max_rect
.w
,self
.max_rect
.h
))
52 self
.bkgr
= pygame
.Surface((s
.get_width(),s
.get_height()),0,s
)
53 self
.bkgr
.blit(s
,(0,0))
54 container
.Container
.paint(self
,self
.surface
)
55 s
.blit(self
.surface
,(-self
.offset
[0],-self
.offset
[1]))
56 self
._offset
= self
.offset
[:]
59 def paint_for_when_pygame_supports_other_tricks(self
,s
):
60 #this would be ideal if pygame had support for it!
61 #and if pgu also had a paint(self,s,rect) method to paint small parts
62 sr
= (self
.offset
[0],self
.offset
[1],self
.max_rect
.w
,self
.max_rect
.h
)
63 cr
= (-self
.offset
[0],-self
.offset
[1],s
.get_width(),s
.get_height())
66 container
.Container
.paint(self
,s2
)
68 def proxy_paint(self
, s
):
69 container
.Container
.paint(self
, surface
.ProxySurface(parent
=None,
74 rects
= container
.Container
.update(self
,self
.surface
)
77 s_rect
= pygame
.Rect(0,0,s
.get_width(),s
.get_height())
79 if self
.offset
== self
._offset
:
81 r2
= r
.move((-self
.offset
[0],-self
.offset
[1]))
82 if r2
.colliderect(s_rect
):
83 s
.blit(self
.surface
.subsurface(r
),r2
)
86 s
.blit(self
.bkgr
,(0,0))
87 sub
= pygame
.Rect(self
.offset
[0],self
.offset
[1],min(s
.get_width(),self
.max_rect
.w
-self
.offset
[0]),min(s
.get_height(),self
.max_rect
.h
-self
.offset
[1]))
89 # print self.surface.get_width(),self.surface.get_height()
90 # print s.get_width(),s.get_height()
92 # print self.style.width,self.style.height
93 s
.blit(self
.surface
.subsurface(sub
),(0,0))
95 self
._offset
= self
.offset
[:]
98 def proxy_update(self
, s
):
99 rects
= container
.Container
.update(self
, surface
.ProxySurface(parent
=None,
104 for r
in rects
: result
.append(pygame
.Rect(r
).move(self
.offset
))
107 def resize(self
, width
=None, height
=None):
108 container
.Container
.resize(self
)
109 self
.max_rect
= pygame
.Rect(self
.widget
.rect
)
110 #self.max_rect.w = max(self.max_rect.w,self.style.width)
111 #self.max_rect.h = max(self.max_rect.h,self.style.height)
112 return self
.style
.width
,self
.style
.height
113 #self.rect = pygame.Rect(self.rect[0], self.rect[1], self.style.width, self.style.height)
116 if e
.type in [MOUSEBUTTONDOWN
, MOUSEBUTTONUP
, MOUSEMOTION
]:
117 pos
= (e
.pos
[0] + self
.offset
[0], e
.pos
[1] + self
.offset
[1])
118 if self
.max_rect
.collidepoint(pos
):
119 e_params
= {'pos': pos
}
120 if e
.type == MOUSEMOTION
:
121 e_params
['buttons'] = e
.buttons
122 e_params
['rel'] = e
.rel
124 e_params
['button'] = e
.button
125 e
= pygame
.event
.Event(e
.type, e_params
)
126 container
.Container
.event(self
, e
)
128 #class SlideBox(Area):
129 # def __init__(self,*args,**params):
130 # print 'gui.SlideBox','Scheduled to be renamed to Area.'
131 # Area.__init__(self,*args,**params)
133 class ScrollArea(table
.Table
):
134 """A scrollable area with scrollbars.
136 <pre>ScrollArea(widget,width,height,hscrollbar=True)</pre>
139 <dt>widget<dd>widget to be able to scroll around
140 <dt>width, height<dd>size of scrollable area. Set either to 0 to default to size of widget.
141 <dt>hscrollbar<dd>set to False if you do not wish to have a horizontal scrollbar
142 <dt>vscrollbar<dd>set to False if you do not wish to have a vertical scrollbar
143 <dt>step<dd>set to how far clicks on the icons will step
146 def __init__(self
, widget
, width
=0, height
=0, hscrollbar
=True, vscrollbar
=True,step
=24, **params
):
148 params
.setdefault('cls', 'scrollarea')
149 table
.Table
.__init
__(self
, width
=width
,height
=height
,**params
)
151 self
.sbox
= SlideBox(w
, width
=width
, height
=height
, cls
=self
.cls
+".content")
153 self
.vscrollbar
= vscrollbar
154 self
.hscrollbar
= hscrollbar
158 def __setattr__(self
,k
,v
):
163 def resize(self
,width
=None,height
=None):
168 table
.Table
.clear(self
)
169 #print 'resize',self,self._rows
174 widget
.rect
.w
, widget
.rect
.h
= widget
.resize()
175 my_width
,my_height
= self
.style
.width
,self
.style
.height
177 my_width
= widget
.rect
.w
178 self
.hscrollbar
= False
180 my_height
= widget
.rect
.h
181 self
.vscrollbar
= False
183 box
.style
.width
,box
.style
.height
= my_width
,my_height
#self.style.width,self.style.height
185 box
.rect
.w
,box
.rect
.h
= box
.resize()
189 #r = table.Table.resize(self,width,height)
195 # #this old code automatically adds in a scrollbar if needed
196 # #but it doesn't always work
197 # self.vscrollbar = None
198 # if widget.rect.h > box.rect.h:
199 # self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step)
200 # self.td(self.vscrollbar)
201 # self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None)
203 # vs = self.vscrollbar
204 # vs.rect.w,vs.rect.h = vs.resize()
205 # box.style.width = self.style.width - vs.rect.w
208 # self.hscrollbar = None
209 # if widget.rect.w > box.rect.w:
210 # self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step)
211 # self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None)
213 # self.td(self.hscrollbar)
215 # hs = self.hscrollbar
216 # hs.rect.w,hs.rect.h = hs.resize()
217 # box.style.height = self.style.height - hs.rect.h
219 xt
,xr
,xb
,xl
= pguglobals
.app
.theme
.getspacing(box
)
223 self
.vscrollbar
= slider
.VScrollBar(box
.offset
[1],0, 65535, 0,step
=self
.step
)
224 self
.td(self
.vscrollbar
)
225 self
.vscrollbar
.connect(CHANGE
, self
._vscrollbar
_changed
, None)
228 vs
.rect
.w
,vs
.rect
.h
= vs
.resize()
230 box
.style
.width
= self
.style
.width
- (vs
.rect
.w
+ xl
+xr
)
233 self
.hscrollbar
= slider
.HScrollBar(box
.offset
[0], 0,65535, 0,step
=self
.step
)
234 self
.hscrollbar
.connect(CHANGE
, self
._hscrollbar
_changed
, None)
236 self
.td(self
.hscrollbar
)
239 hs
.rect
.w
,hs
.rect
.h
= hs
.resize()
240 if self
.style
.height
:
241 box
.style
.height
= self
.style
.height
- (hs
.rect
.h
+ xt
+ xb
)
246 hs
.max = widget
.rect
.w
- box
.style
.width
247 hs
.style
.width
= box
.style
.width
248 hs
.size
= hs
.style
.width
* box
.style
.width
/ max(1,widget
.rect
.w
)
255 vs
.max = widget
.rect
.h
- box
.style
.height
256 vs
.style
.height
= box
.style
.height
257 vs
.size
= vs
.style
.height
* box
.style
.height
/ max(1,widget
.rect
.h
)
261 #print self.style.width,box.style.width, hs.style.width
263 r
= table
.Table
.resize(self
,width
,height
)
266 def x_resize(self
, width
=None, height
=None):
267 w
,h
= table
.Table
.resize(self
, width
, height
)
269 if self
.widget
.rect
.w
<= self
.sbox
.rect
.w
:
270 self
.hscrollbar
.size
= self
.hscrollbar
.style
.width
272 self
.hscrollbar
.size
= max(20,self
.hscrollbar
.style
.width
* self
.sbox
.rect
.w
/ self
.widget
.rect
.w
)
273 self
._hscrollbar
_changed
(None)
274 if self
.widget
.rect
.h
<= self
.sbox
.rect
.h
:
275 self
.vscrollbar
.size
= self
.vscrollbar
.style
.height
277 self
.vscrollbar
.size
= max(20,self
.vscrollbar
.style
.height
* self
.sbox
.rect
.h
/ self
.widget
.rect
.h
)
278 self
._vscrollbar
_changed
(None)
281 def _vscrollbar_changed(self
, xxx
):
282 #y = (self.widget.rect.h - self.sbox.rect.h) * self.vscrollbar.value / 1000
283 #if y >= 0: self.sbox.offset[1] = -y
284 self
.sbox
.offset
[1] = self
.vscrollbar
.value
287 def _hscrollbar_changed(self
, xxx
):
288 #x = (self.widget.rect.w - self.sbox.rect.w) * self.hscrollbar.value / 1000
289 #if x >= 0: self.sbox.offset[0] = -x
290 self
.sbox
.offset
[0] = self
.hscrollbar
.value
294 def set_vertical_scroll(self
, percents
):
295 #if not self.vscrollbar: return
296 if not hasattr(self
.vscrollbar
,'value'): return
297 self
.vscrollbar
.value
= percents
#min(max(percents*10, 0), 1000)
298 self
._vscrollbar
_changed
(None)
300 def set_horizontal_scroll(self
, percents
):
301 #if not self.hscrollbar: return
302 if not hasattr(self
.hscrollbar
,'value'): return
303 self
.hscrollbar
.value
= percents
#min(max(percents*10, 0), 1000)
304 self
._hscrollbar
_changed
(None)
307 #checking for event recipient
308 if (table
.Table
.event(self
, e
)):
311 #mouse wheel scrolling
313 if not hasattr(self
.vscrollbar
,'value'):
316 if e
.type == pygame
.locals.MOUSEBUTTONDOWN
:
317 if e
.button
== 4: #wheel up
318 self
.vscrollbar
._click
(-1)
320 elif e
.button
== 5: #wheel down
321 self
.vscrollbar
._click
(1)
328 class _List_Item(button
._button
):
329 def __init__(self
,label
=None,image
=None,value
=None,**params
): #TODO label= could conflict with the module label
330 #param image: an imagez.Image object (optional)
331 #param text: a string object
332 params
.setdefault('cls','list.item')
333 button
._button
.__init
__(self
,**params
)
335 self
.value
= value
#(self, value)
338 if type(label
) == str:
339 label
= basic
.Label(label
, cls
=self
.cls
+".label")
342 self
.widget
= container
.Container()
343 self
.widget
.add(image
, 0, 0)
344 #HACK: improper use of .resize()
345 image
.rect
.w
,image
.rect
.h
= image
.resize()
346 self
.widget
.add(label
, image
.rect
.w
, 0)
347 elif image
: self
.widget
= image
348 elif label
: self
.widget
= label
352 def resize(self
,width
=None,height
=None):
353 self
.widget
.rect
.w
,self
.widget
.rect
.h
= self
.widget
.resize()
354 return self
.widget
.rect
.w
,self
.widget
.rect
.h
355 # self.widget._resize()
356 # self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h
359 button
._button
.event(self
,e
)
360 if self
.group
.value
== self
.value
: self
.pcls
= "down"
363 if self
.group
.value
== self
.value
: self
.pcls
= "down"
364 self
.widget
.paint(surface
.subsurface(s
,self
.widget
.rect
))
367 self
.group
.value
= self
.value
368 for w
in self
.group
.widgets
:
369 if w
!= self
: w
.pcls
= ""
373 class List(ScrollArea
):
374 """A list of items in an area.
376 <p>This widget can be a form element, it has a value set to whatever item is selected.</p>
378 <pre>List(width,height)</pre>
380 def _change(self
, value
):
381 self
.value
= self
.group
.value
384 def __init__(self
, width
, height
, **params
):
385 params
.setdefault('cls', 'list')
386 self
.table
= table
.Table(width
=width
)
387 ScrollArea
.__init
__(self
, self
.table
, width
, height
,hscrollbar
=False ,**params
)
393 g
.connect(CHANGE
,self
._change
,None)
394 self
.value
= self
.group
.value
= None
397 self
.remove
= self
._remove
402 <pre>List.clear()</pre>
405 self
.group
= group
.Group()
406 self
.group
.connect(CHANGE
,self
._change
,None)
408 self
.set_vertical_scroll(0)
409 self
.blur(self
.myfocus
)
411 def _docs(self
): #HACK: nasty hack to get the docs in "my way"
412 def add(self
, label
, image
=None, value
=None):
413 """Add an item to the list.
415 <pre>List.add(label,image=None,value=None)</pre>
418 <dt>label<dd>a label for the item
419 <dt>image<dd>an image for the item
420 <dt>value<dd>a value for the item
424 def remove(self
,value
):
425 """Remove an item from the list.
427 <pre>List.remove(value)</pre>
430 <dt>value<dd>a value of an item to remove from the list
434 def _add(self
, label
, image
= None, value
=None):
435 item
= _List_Item(label
,image
=image
,value
=value
)
438 self
.items
.append(item
)
439 item
.group
= self
.group
442 def _remove(self
, item
):
444 if i
.value
== item
: item
= i
445 if item
not in self
.items
: return
447 self
.items
.remove(item
)
448 self
.group
.widgets
.remove(item
)
449 self
.table
.remove_row(item
.style
.row
)
451 #class List(ListArea):
452 # def __init__(self,*args,**params):
453 # print 'gui.List','Scheduled to be renamed to ListArea. API may also be changed in the future.'
454 # ListArea.__init__(self,*args,**params)