1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
"""
--------------------------------------------------------------------------------
widgets.py - S.Fourmanoit <syfou@users.sourceforge.net>, 2005
This shows a simple way to use Python object-orientedness to implement a
simple MVC (Model-View-Control) model, usable with adesklets to implements
easy to use widgets.
The beauty of this code is that, while being compact (the core Widget class
is seventeen lines of code), it gives a way to dynamically create and modify
an arbitrary tree of small graphical elements (widgets) embedding at the
same place all their data and the methods needed to display them.
--------------------------------------------------------------------------------
"""
#-------------------------------------------------------------------------------
class Widget(list):
"""
Simple class creating a generic widget that can have any numbers
of descendants, storable in a tree-like structure. It implements:
- A breadth first iterator, usable to visit a complete widget tree
or subtree in top to bottom, first to last child order (a widget can
also contain non widget-derived objects -- they will simply be skipped
by the irerator).
- A 'static' config class attribute that can be used to store
a configuration shared by all instances of Widget, or
Widget derivated classes.
- An 'execute' function, that can be used as a shortcut to __iter__
to perform arbitrary code execution on a whole widget tree.
Obviously, this is completely independent from adesklets...
"""
__name = None
config = {}
def __init__(self,config=None):
if not config is None:
Widget.config=config
def __iter__(self):
yield self
for elem in list.__iter__(self):
if hasattr(elem,'_Widget__name'):
for child in elem.__iter__():
yield child
def execute(self, func, args=[]):
for widget in self:
widget.__getattribute__(func)(*args)
#-------------------------------------------------------------------------------
# Now, as a demonstration, let's create a few very simple classes derived
# from Widget able to specifically deal with adesklets.
#
# Here, we always create a 'draw' method in every one of them, that can be used
# later on to display the element using 'execute' from the root widget element.
# Real-life widgets would probably create at least two methods for this
# (one writing to foreground and the other one to background),
# that would be used appropriately (or arguments would be used).
#
import adesklets
class Box(Widget):
""" Box widget"""
def __init__(self,coords):
Widget.__init__(self)
self.coords=coords
def draw(self):
adesklets.context_set_color(0,0,0,0)
adesklets.context_set_blend(False)
adesklets.image_fill_rectangle(*self.coords)
adesklets.context_set_blend(True)
adesklets.context_set_color(*self.config['box_color'])
adesklets.image_draw_rectangle(*self.coords)
class Text(Widget):
""" Text label widget"""
def __init__(self,coords, text):
Widget.__init__(self)
self.coords=coords
self.text=text
def draw(self):
font=adesklets.load_font(self.config['text_font'])
adesklets.context_set_font(font)
adesklets.context_set_color(*self.config['text_color'])
adesklets.text_draw(self.coords[0],self.coords[1],self.text)
adesklets.free_font(font)
def size(self):
font=adesklets.load_font(self.config['text_font'])
adesklets.context_set_font(font)
result=adesklets.get_text_size(self.text)
adesklets.free_font(font)
return result
def __str__(self):
return "<Text label at %s, being '%s'>" % (self.coords, self.text)
class BoxedText(Widget):
"""Compound boxed text widget"""
def __init__(self,coords,text):
Widget.__init__(self)
t=Text(coords,text)
self.append(Box(coords + list(t.size())))
self.append(t)
def draw(self):
pass
class Canva(Widget):
"""Root widget"""
def draw(self):
pass
#-------------------------------------------------------------------------------
# Utility functions
#
from signal import pause
from random import randint
def rcoords():
"""Iterator generating pseudo-random (x, y) coordinates in [0,100]"""
while 1:
yield [randint(0,100),randint(0,100)]
#-------------------------------------------------------------------------------
# Main routine
# ============
# Here is the configuration: of course, it could as well be an
# adesklets.ConfigFile class or anything else.
#
config = { 'text_font' : 'DejaVuSans/20', 'text_color' : [0,255,0,200] ,
'box_color': [255,255,255,200] }
# Create dynamically a bunch of randomly positionned widgets
#
canva=Canva(config)
for coords, caption in zip(rcoords(),'Some text to put on screen'.split()):
canva.append(BoxedText(coords,caption))
# Set up adesklets
#
adesklets.window_resize(150,150)
adesklets.window_set_transparency(True)
adesklets.window_reset(adesklets.WINDOW_MANAGED)
adesklets.window_show()
# Now let's draw everything once...
#
canva.execute('draw')
# ... Printout all existing Text widget properties descending from
# our root 'window' desklet, just to show off...
#
for widget in canva:
if widget.__class__ is Text:
print widget
# ... and finally, sleep forever.
#
pause()
#-------------------------------------------------------------------------------
|