import pygame
import pguglobals import style
"""Base class for all PGU graphical objects.
Example - Creating your own Widget:
"""
# The name of the widget (or None if not defined) name = None # The container this widget belongs to container = None # Whether this widget has been painted yet _painted = False # The widget used to paint the background background = None # ... _rect_content = None
"""Widget constructor.
Keyword arguments:
style -- a dict of style parameters. x, y -- position parameters width, height -- size parameters align, valign -- alignment parameters, passed along to style font, color, background -- other common parameters that are passed
along to style
cls -- class name as used by Theme name -- name of widget as used by Form. If set, will call
form.add(self,name) to add the widget to the most recently created Form.
disabled -- True of this widget is disabled. Defaults to False. value -- initial value
""" #object.Object.__init__(self) self.connects = {} params.setdefault('decorate',True) params.setdefault('style',{}) params.setdefault('focusable',True) params.setdefault('disabled',False)
self.focusable = params['focusable'] self.disabled = params['disabled']
s = params['style'] #some of this is a bit "theme-ish" but it is very handy, so these #things don't have to be put directly into the style. for att in ('align','valign','x','y','width','height','color','font','background'):
if att in params: s[att] = params[att]
self.style = style.Style(self,s)
self.cls = 'default' if 'cls' in params: self.cls = params['cls'] if 'name' in params:
import form self.name = params['name'] if form.Form.form:
form.Form.form.add(self) self.form = form.Form.form
if 'value' in params: self.value = params['value'] self.pcls = ""
pguglobals.app.theme.decorate(self,params['decorate'])
"""Focus this Widget.""" if self.container:
- if self.container.myfocus != self: ## by Gal Koren
- self.container.focus(self)
"""Close this widget, if it is currently an open dialog.""" #if getattr(self,'container',None) != None: self.container.close(self) if (not w):
w = self
pguglobals.app.close(w)
"""Returns true if the mouse is hovering over this widget.""" if self.container:
return (self.container.myhover is self)
return False
"""Resize this widget and all sub-widgets, returning the new size.
This should be implemented by a subclass.
""" return (self.style.width, self.style.height)
"""Change the size of this widget."""
if (not self._painted): return
if (not self.container): return
pguglobals.app.chsize() return
#if hasattr(app.App,'app'): # w,h = self.rect.w,self.rect.h # w2,h2 = self.resize() # if w2 != w or h2 != h: # app.App.app.chsize() # else: # self.repaint()
"""Updates the surface and returns a rect list of updated areas
This should be implemented by a subclass.
""" return
"""Render this widget onto the given surface
This should be implemented by a subclass.
""" return
"""Pass focus to next Widget.
Widget order determined by the order they were added to their container.
""" if self.container: self.container.next(self)
"""Pass focus to previous Widget.
Widget order determined by the order they were added to their container.
"""
if self.container: self.container.previous(self)
"""Returns the absolute rect of this widget on the App screen.""" x, y = self.rect.x, self.rect.y cnt = self.container while cnt:
x += cnt.rect.x y += cnt.rect.y if cnt._rect_content:
x += cnt._rect_content.x y += cnt._rect_content.ycnt = cnt.container
return pygame.Rect(x, y, self.rect.w, self.rect.h)
"""Connect a event code to a callback function.
<p>There may be multiple callbacks per event code.</p>
Arguments: code -- event type fnc -- callback function *values -- values to pass to callback.
Please note that callbacks may also have "magicaly" parameters. Such as:
_event -- receive the event _code -- receive the event code _widget -- receive the sending widget
Example:
w = Button("PGU!") w.connect(gui.CLICK,onclick,'PGU Button Clicked')
""" if (not code in self.connects):
self.connects[code] = []
# Wrap the callback function and add it to the list cb = SignalCallback() cb.func = func cb.params = params self.connects[code].append(cb)
# Remove signal handlers from the given event code. If func is specified, # only those handlers will be removed. If func is None, all handlers # will be removed. def disconnect(self, code, func=None):
- if (not code in self.connects):
- return
- if (not func):
- # Remove all signal handlers del self.connects[code]
- else:
# Remove handlers that call 'func' n = 0 callbacks = self.connects[code] while (n < len(callbacks)):
- if (callbacks[n].func == func):
- # Remove this callback del callbacks[n]
- else:
- n += 1
"""Send a code, event callback trigger.""" if (not code in self.connects):
return
# Trigger all connected signal handlers for cb in self.connects[code]:
func = cb.func values = list(cb.params)
nargs = func.func_code.co_argcount names = list(func.func_code.co_varnames)[:nargs] if hasattr(func,'im_class'): names.pop(0)
args = [] magic = {'_event':event,'_code':code,'_widget':self} for name in names:
- if name in magic.keys():
- args.append(magic[name])
- elif len(values):
- args.append(values.pop(0))
- else:
- break
args.extend(values) func(*args)
"""Called when an event is passed to this object.
Please note that if you use an event, returning the value True will stop parent containers from also using the event. (For example, if your widget handles TABs or arrow keys, and you don't want those to also alter the focus.)
This should be implemented by a subclass.
""" return
"""Returns the top-level widget (usually the Desktop) by following the chain of 'container' references.
""" top = self while (top.container):
top = top.container
return top
"""Test if the given point hits this widget. Over-ride this function for more advanced collision testing.
""" return self.rect.collidepoint(pos)