"""
"""
import os
import pguglobals
from const import *
import surface
import container, table
import group
import basic, button, slider
class SlideBox(container.Container):
"""A scrollable area with no scrollbars.
SlideBox(widget,width,height)
- widget
- widget to be able to scroll around
- width, height
- size of scrollable area
Example
c = SlideBox(w,100,100)
c.offset = (10,10)
c.repaint()
"""
def __init__(self, widget, width, height, **params):
params.setdefault('width', width)
params.setdefault('height', height)
container.Container.__init__(self, **params)
self.offset = [0, 0]
self.widget = widget
def __setattr__(self,k,v):
if k == 'widget':
if hasattr(self,'widget'):
self.remove(self.widget)
self.add(v,0,0)
self.__dict__[k] = v
def paint(self, s):
#if not hasattr(self,'surface'):
self.surface = pygame.Surface((self.max_rect.w,self.max_rect.h),0,s)
#self.surface.fill((0,0,0,0))
pguglobals.app.theme.render(self.surface,self.style.background,pygame.Rect(0,0,self.max_rect.w,self.max_rect.h))
self.bkgr = pygame.Surface((s.get_width(),s.get_height()),0,s)
self.bkgr.blit(s,(0,0))
container.Container.paint(self,self.surface)
s.blit(self.surface,(-self.offset[0],-self.offset[1]))
self._offset = self.offset[:]
return
def paint_for_when_pygame_supports_other_tricks(self,s):
#this would be ideal if pygame had support for it!
#and if pgu also had a paint(self,s,rect) method to paint small parts
sr = (self.offset[0],self.offset[1],self.max_rect.w,self.max_rect.h)
cr = (-self.offset[0],-self.offset[1],s.get_width(),s.get_height())
s2 = s.subsurface(sr)
s2.set_clip(cr)
container.Container.paint(self,s2)
def proxy_paint(self, s):
container.Container.paint(self, surface.ProxySurface(parent=None,
rect=self.max_rect,
real_surface=s,
offset=self.offset))
def update(self, s):
rects = container.Container.update(self,self.surface)
rets = []
s_rect = pygame.Rect(0,0,s.get_width(),s.get_height())
if self.offset == self._offset:
for r in rects:
r2 = r.move((-self.offset[0],-self.offset[1]))
if r2.colliderect(s_rect):
s.blit(self.surface.subsurface(r),r2)
rets.append(r2)
else:
s.blit(self.bkgr,(0,0))
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]))
# print sub
# print self.surface.get_width(),self.surface.get_height()
# print s.get_width(),s.get_height()
# print self.offset
# print self.style.width,self.style.height
s.blit(self.surface.subsurface(sub),(0,0))
rets.append(s_rect)
self._offset = self.offset[:]
return rets
def proxy_update(self, s):
rects = container.Container.update(self, surface.ProxySurface(parent=None,
rect=self.max_rect,
real_surface=s,
offset=self.offset))
result = []
for r in rects: result.append(pygame.Rect(r).move(self.offset))
return result
def resize(self, width=None, height=None):
container.Container.resize(self)
self.max_rect = pygame.Rect(self.widget.rect)
#self.max_rect.w = max(self.max_rect.w,self.style.width)
#self.max_rect.h = max(self.max_rect.h,self.style.height)
return self.style.width,self.style.height
#self.rect = pygame.Rect(self.rect[0], self.rect[1], self.style.width, self.style.height)
def event(self, e):
if e.type in [MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION]:
pos = (e.pos[0] + self.offset[0], e.pos[1] + self.offset[1])
if self.max_rect.collidepoint(pos):
e_params = {'pos': pos }
if e.type == MOUSEMOTION:
e_params['buttons'] = e.buttons
e_params['rel'] = e.rel
else:
e_params['button'] = e.button
e = pygame.event.Event(e.type, e_params)
container.Container.event(self, e)
#class SlideBox(Area):
# def __init__(self,*args,**params):
# print 'gui.SlideBox','Scheduled to be renamed to Area.'
# Area.__init__(self,*args,**params)
class ScrollArea(table.Table):
"""A scrollable area with scrollbars.
ScrollArea(widget,width,height,hscrollbar=True)
- widget
- widget to be able to scroll around
- width, height
- size of scrollable area. Set either to 0 to default to size of widget.
- hscrollbar
- set to False if you do not wish to have a horizontal scrollbar
- vscrollbar
- set to False if you do not wish to have a vertical scrollbar
- step
- set to how far clicks on the icons will step
"""
def __init__(self, widget, width=0, height=0, hscrollbar=True, vscrollbar=True,step=24, **params):
w= widget
params.setdefault('cls', 'scrollarea')
table.Table.__init__(self, width=width,height=height,**params)
self.sbox = SlideBox(w, width=width, height=height, cls=self.cls+".content")
self.widget = w
self.vscrollbar = vscrollbar
self.hscrollbar = hscrollbar
self.step = step
def __setattr__(self,k,v):
if k == 'widget':
self.sbox.widget = v
self.__dict__[k] = v
def resize(self,width=None,height=None):
widget = self.widget
box = self.sbox
#self.clear()
table.Table.clear(self)
#print 'resize',self,self._rows
self.tr()
self.td(box)
widget.rect.w, widget.rect.h = widget.resize()
my_width,my_height = self.style.width,self.style.height
if not my_width:
my_width = widget.rect.w
self.hscrollbar = False
if not my_height:
my_height = widget.rect.h
self.vscrollbar = False
box.style.width,box.style.height = my_width,my_height #self.style.width,self.style.height
box.rect.w,box.rect.h = box.resize()
#print widget.rect
#print box.rect
#r = table.Table.resize(self,width,height)
#print r
#return r
#print box.offset
# #this old code automatically adds in a scrollbar if needed
# #but it doesn't always work
# self.vscrollbar = None
# if widget.rect.h > box.rect.h:
# self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step)
# self.td(self.vscrollbar)
# self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None)
#
# vs = self.vscrollbar
# vs.rect.w,vs.rect.h = vs.resize()
# box.style.width = self.style.width - vs.rect.w
#
#
# self.hscrollbar = None
# if widget.rect.w > box.rect.w:
# self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step)
# self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None)
# self.tr()
# self.td(self.hscrollbar)
#
# hs = self.hscrollbar
# hs.rect.w,hs.rect.h = hs.resize()
# box.style.height = self.style.height - hs.rect.h
xt,xr,xb,xl = pguglobals.app.theme.getspacing(box)
if self.vscrollbar:
self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step)
self.td(self.vscrollbar)
self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None)
vs = self.vscrollbar
vs.rect.w,vs.rect.h = vs.resize()
if self.style.width:
box.style.width = self.style.width - (vs.rect.w + xl+xr)
if self.hscrollbar:
self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step)
self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None)
self.tr()
self.td(self.hscrollbar)
hs = self.hscrollbar
hs.rect.w,hs.rect.h = hs.resize()
if self.style.height:
box.style.height = self.style.height - (hs.rect.h + xt + xb)
if self.hscrollbar:
hs = self.hscrollbar
hs.min = 0
hs.max = widget.rect.w - box.style.width
hs.style.width = box.style.width
hs.size = hs.style.width * box.style.width / max(1,widget.rect.w)
else:
box.offset[0] = 0
if self.vscrollbar:
vs = self.vscrollbar
vs.min = 0
vs.max = widget.rect.h - box.style.height
vs.style.height = box.style.height
vs.size = vs.style.height * box.style.height / max(1,widget.rect.h)
else:
box.offset[1] = 0
#print self.style.width,box.style.width, hs.style.width
r = table.Table.resize(self,width,height)
return r
def x_resize(self, width=None, height=None):
w,h = table.Table.resize(self, width, height)
if self.hscrollbar:
if self.widget.rect.w <= self.sbox.rect.w:
self.hscrollbar.size = self.hscrollbar.style.width
else:
self.hscrollbar.size = max(20,self.hscrollbar.style.width * self.sbox.rect.w / self.widget.rect.w)
self._hscrollbar_changed(None)
if self.widget.rect.h <= self.sbox.rect.h:
self.vscrollbar.size = self.vscrollbar.style.height
else:
self.vscrollbar.size = max(20,self.vscrollbar.style.height * self.sbox.rect.h / self.widget.rect.h)
self._vscrollbar_changed(None)
return w,h
def _vscrollbar_changed(self, xxx):
#y = (self.widget.rect.h - self.sbox.rect.h) * self.vscrollbar.value / 1000
#if y >= 0: self.sbox.offset[1] = -y
self.sbox.offset[1] = self.vscrollbar.value
self.sbox.reupdate()
def _hscrollbar_changed(self, xxx):
#x = (self.widget.rect.w - self.sbox.rect.w) * self.hscrollbar.value / 1000
#if x >= 0: self.sbox.offset[0] = -x
self.sbox.offset[0] = self.hscrollbar.value
self.sbox.reupdate()
def set_vertical_scroll(self, percents):
#if not self.vscrollbar: return
if not hasattr(self.vscrollbar,'value'): return
self.vscrollbar.value = percents #min(max(percents*10, 0), 1000)
self._vscrollbar_changed(None)
def set_horizontal_scroll(self, percents):
#if not self.hscrollbar: return
if not hasattr(self.hscrollbar,'value'): return
self.hscrollbar.value = percents #min(max(percents*10, 0), 1000)
self._hscrollbar_changed(None)
class _List_Item(button._button):
def __init__(self,label=None,image=None,value=None,**params): #TODO label= could conflict with the module label
#param image: an imagez.Image object (optional)
#param text: a string object
params.setdefault('cls','list.item')
button._button.__init__(self,**params)
self.group = None
self.value = value #(self, value)
self.widget = None
if type(label) == str:
label = basic.Label(label, cls=self.cls+".label")
if image and label:
self.widget = container.Container()
self.widget.add(image, 0, 0)
#HACK: improper use of .resize()
image.rect.w,image.rect.h = image.resize()
self.widget.add(label, image.rect.w, 0)
elif image: self.widget = image
elif label: self.widget = label
self.pcls = ""
def resize(self,width=None,height=None):
self.widget.rect.w,self.widget.rect.h = self.widget.resize()
return self.widget.rect.w,self.widget.rect.h
# self.widget._resize()
# self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h
def event(self,e):
button._button.event(self,e)
if self.group.value == self.value: self.pcls = "down"
def paint(self,s):
if self.group.value == self.value: self.pcls = "down"
self.widget.paint(surface.subsurface(s,self.widget.rect))
def click(self):
self.group.value = self.value
for w in self.group.widgets:
if w != self: w.pcls = ""
class List(ScrollArea):
"""A list of items in an area.
This widget can be a form element, it has a value set to whatever item is selected.
List(width,height)
"""
def _change(self, value):
self.value = self.group.value
self.send(CHANGE)
def __init__(self, width, height, **params):
params.setdefault('cls', 'list')
self.table = table.Table(width=width)
ScrollArea.__init__(self, self.table, width, height,hscrollbar=False ,**params)
self.items = []
g = group.Group()
self.group = g
g.connect(CHANGE,self._change,None)
self.value = self.group.value = None
self.add = self._add
self.remove = self._remove
def clear(self):
"""Clear the list.
List.clear()
"""
self.items = []
self.group = group.Group()
self.group.connect(CHANGE,self._change,None)
self.table.clear()
self.set_vertical_scroll(0)
self.blur(self.myfocus)
def _docs(self): #HACK: nasty hack to get the docs in "my way"
def add(self, label, image=None, value=None):
"""Add an item to the list.
List.add(label,image=None,value=None)
- label
- a label for the item
- image
- an image for the item
- value
- a value for the item
"""
def remove(self,value):
"""Remove an item from the list.
List.remove(value)
- value
- a value of an item to remove from the list
"""
def _add(self, label, image = None, value=None):
item = _List_Item(label,image=image,value=value)
self.table.tr()
self.table.add(item)
self.items.append(item)
item.group = self.group
item.group.add(item)
def _remove(self, item):
for i in self.items:
if i.value == item: item = i
if item not in self.items: return
item.blur()
self.items.remove(item)
self.group.widgets.remove(item)
self.table.remove_row(item.style.row)
#class List(ListArea):
# def __init__(self,*args,**params):
# print 'gui.List','Scheduled to be renamed to ListArea. API may also be changed in the future.'
# ListArea.__init__(self,*args,**params)