hello
i just wanted to share another code snippet. this time: a simple ui builder you
can use if you want to hack something together. if you want to write a little
demo app you want to concentrate on your code not to waste time and lines of
code to get some buttons or labels.
frist of all the disadvantages:
* it's not extensive tested
* no disabled states
* there is no documentation
to my mind the pros:
* very simple to use, so you don't need a documentation
* no external pictures used, everything generated by code
* there are no private variables so it's easy to hack
* only specify whats _really_ necessary (only one pos and one parent per group)
a code example:
<<<<<<<<
def d(string): # just a sample function, so smth.
print string # happens when pressing a btn.
g = Group("Box with Headline", pos=avg.Point2D(10,10), parent=root)
g.add(Button("this is a button", lambda: d("button 1 pressed")))
g.add(Button("this is a button, too", lambda: d("button 2 pressed")))
g.add(Label("this is a Label"))
g.add(CheckBox("a CheckBox!", lambda x: d("CheckBox is %s" % x)))
g.add(Label("Radio Btns"))
g.add(RadioButtons(("radio 0", "radio 1", "radio 2"), lambda x: d(x),
checked=1))
f = g.add(Button("button", lambda: None))
g.add(Button("click me", lambda: setattr(f.text, "text", "not a button" if
f.text.text == 'button' else 'button')))
>>>>>>>>
so that's it. you can also use tabs, for better structure. just run the
attached file to see a full feature list
still to do:
* text field / on screen debug console
* chart
* scrollbar / slider
benedikt
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Simple User Interface
#
# Copyright (C) 2011 Benedikt Seidl
#
# This is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
"""
Simple User Interface
The sui Module is ment for easy to use gui for use with libavg.
"""
from libavg import avg
class C(object):
"""
object used for configuration like width and height of btns or colors.
"""
w = 200
""" width of alll elements """
h = 30
""" height of buttons """
c = 'ffcc00'
""" backgroundcolor of buttons and foregroundcolor for labels """
@classmethod
def smallX(cls, x=0, y=0):
"""returns lists of Integers that are the coordinates of a small
X for use with the CheckBox. Values may be shifted by x,y"""
return map(lambda (a,b): (a+x, b+y),
((4,2),(7,5),(8,5),(11,2),(13,4),(10,7),(10,8),
(13,11),(11,13),(8,10),(7,10),(4,13),(2,11),(5,8),
(5,7),(2,4)))
class Sensitive(avg.DivNode):
"""
Base Class for all Elements that may be Clicked.
Sensitive Classes confert the raw EventHandling in simple two
callbacks: up and down.
"""
def __init__(self, **kw):
super(Sensitive, self).__init__(**kw)
self.eventid = None
self.setEventHandler(avg.CURSORUP, avg.MOUSE, self.eventUp)
self.setEventHandler(avg.CURSORDOWN, avg.MOUSE, self.eventDown)
def up(self):
pass
def down(self):
pass
def eventUp(self, event):
if self.eventid != None:
self.releaseEventCapture(self.eventid)
self.eventid = None
self.up()
def eventDown(self, event):
if self.eventid == None:
self.eventid = event.cursorid
self.setEventCapture(event.cursorid)
self.down()
class Group(avg.DivNode):
"""
may be used to group elements.
this is very usefull, because if you use a group, you only have to
specive the pos and parent of the element once.
>>> g = Group("Name of Group", pos=(10,10), parent=self)
>>> g.add(Button("libavg"), self.libavgClicked)
>>> g.add(Button("python"), self.pythonClicked)
if you need a reference to the element you wand to add you can simple
add and get the reference at once:
>>> mat = g.add(Button("club-mate"), lambda: self.drink("club-mate"))
"""
def __init__(self, name=None, **kw):
"""
if a name is given, a outline will be painted.
if name is None, no outline will be painted, and the elements will
not be indented
"""
super(Group, self).__init__(**kw)
self.showText = (False if name == None else True)
if name != None:
self.text = avg.WordsNode(
parent=self,
pos=(10,0),
text=name)
self.border = avg.PolyLineNode(
parent=self,
pos=((10,10),(0,0),(5,5)))
self.nextElementPos = 20
self.add(None)
else:
self.nextElementPos = 2
def add(self, element):
"""
add any SUI-element here. returns the element addded
"""
if element != None:
self.appendChild(element)
element.pos=((4 if self.showText else 0),self.nextElementPos)
self.nextElementPos += element.height
if self.showText:
height=self.nextElementPos -4
ps = [
(8,5),
(0,5),
(0,5+height),
(C.w+8,5+height),
(C.w+8,5),
(self.text.getMediaSize().x+12,5)]
self.border.pos = ps
return element
@property
def height(self):
return self.nextElementPos + 8
class CheckBox(Sensitive):
def __init__(self, name, callback, checked=False, **kw):
"""
callback needs to accept an boolean argument (if checked or not)
"""
super(CheckBox, self).__init__(**kw)
self.text = avg.WordsNode(
parent=self,
pos=(25,2),
text=name)
avg.RectNode(
parent=self,
pos=(2,2),
size=(15,15))
self.check = avg.PolygonNode(
parent=self,
pos=C.smallX(2,2),
fillopacity=(1 if checked else 0),
opacity=0)
self.height=25
self.width=C.w
self.checked = checked
self.callback = callback
def up(self):
if self.checked:
self.check.fillopacity=0
else:
self.check.fillopacity=1
self.checked = not self.checked
self.callback(self.checked)
class RadioButton(Sensitive):
def __init__(self, name, callback, checked=False, **kw):
super(RadioButton, self).__init__(**kw)
self.text = avg.WordsNode(
parent=self,
pos=(25,2),
text=name)
avg.CircleNode(
parent=self,
pos=(11,11),
r=8)
self.check = avg.CircleNode(
parent=self,
pos=(11,11),
r=4,
fillopacity=(1 if checked else 0),
opacity=0)
self.callback = callback
self.height = 25
def up(self):
self.callback(self, self.text.text)
class RadioButtons(Group):
def __init__(self, names, callback, checked=None, **kw):
"""
checked may be the number or the name of the element that should be
checked by default. if no default is set, the last element is
checked
"""
super(RadioButtons, self).__init__(**kw)
self.callback = callback
for i, name in enumerate(names):
last = self.add(RadioButton(name, self.cb))
if i == checked or checked == name:
last.check.fillopacity = 1
if checked == None:
last.check.fillopacity=1
def cb(self, node, name):
for i in range(self.getNumChildren()):
child = self.getChild(i)
child.check.fillopacity=(1 if child == node else 0)
self.callback(name)
class Button(Sensitive):
def __init__(self, name, callback, **kw):
super(Button, self).__init__(**kw)
self.bg = avg.RectNode(
parent=self,
size=(C.w, C.h),
fillcolor=C.c,
fillopacity=1)
self.text = avg.WordsNode(
parent=self,
width=C.w,
pos=(C.w/2,5),
alignment='center')
self.text.text=name
self.height = 34
self.width = C.w
self.eventid = None
self.callback = callback
def up(self):
self.bg.fillopacity=1
self.callback()
def down(self):
self.bg.fillopacity=0.5
class Tab(Sensitive):
def __init__(self, name, callback, **kw):
super(Tab, self).__init__(**kw)
self.bg = avg.RectNode(
parent=self,
fillcolor=C.c,
fillopacity=0.5)
self.text = avg.WordsNode(
parent=self,
pos=(5,5),
text = name)
self.width = self.text.getMediaSize().x+10
self.bg.size = (self.width,C.h)
self.callback = callback
self.height = 34
def up(self):
self.callback(self)
class Tabs(avg.DivNode):
def __init__(self, tabs, size, **kw):
super(Tabs, self).__init__(**kw)
x = 0
self.tabs = dict()
self.bg = avg.RectNode(
parent=self,
size=size,
pos=(0,30))
self.content = avg.DivNode(
parent=self,
crop=True,
size=size,
pos=(0,30))
self.tabActive = None
for (name, element) in tabs:
node = Tab(name, self.cb, pos=(x,0), parent=self)
self.tabs.update({node:element})
self.content.appendChild(element)
element.active = False
x += node.width + 3
self.tabActive = node
self.cb(self.tabActive)
def cb(self, tab):
self.tabs[self.tabActive].active = False
self.tabActive.bg.fillopacity = 0.5
self.tabActive = tab
self.tabs[self.tabActive].active = True
self.tabActive.bg.fillopacity = 1
class Label(avg.DivNode):
def __init__(self, name, **kw):
super(Label, self).__init__(**kw)
self.text = avg.WordsNode(
parent=self,
size=(C.w, C.h),
pos=(2,5),
color=C.c,
text=name)
self.height = 34
def d(s):
print s
if __name__ == '__main__':
player = avg.Player.get()
player.setMultiSampleSamples(4)
player.loadString("""<avg width="900" height="400"></avg>""")
root = player.getRootNode()
# first of all a stand alone demo button:
Button("name", lambda: None, parent=root, pos=(20,350))
# but you can also use groups, that may have names but don't have to
g = Group("TestingGroup", pos=avg.Point2D(6,3), parent=root)
# if you use groups you don't have to worry about positioning of the
# elements in the group, you just can add them one by one
# labels don't have a callback, but only a text to display
g.add(Label("Zuerst zwei Buttons"))
# a button needs a callback, so give it one
g.add(Button("erster Button", lambda:None))
g.add(Button("zweiter Button", lambda:None))
g.add(Label("dann noch mal zwei Button"))
g.add(Button("erster von den zweiten", lambda:None))
g.add(Button("zweiter von den zweiten", lambda:None))
g.add(Label("ein paar Checkboxen"))
# checkboxes have a callback, too, but they also pass their state
g.add(CheckBox("checkbox eins", lambda x: None))
g.add(CheckBox("checkbox zwei", lambda x: None))
# just make another group, so we don't run out of space
g = Group(pos=avg.Point2D(226,3), parent=root)
g.add(Button("name2", lambda:None))
g.add(Label("Testing Label"))
g.add(Button("name4", lambda:d("name4")))
g.add(CheckBox("Check me!", lambda x: d("check1 %s" % x)))
g.add(CheckBox("and me please, too!", lambda x: d("check2 %s" % x)))
# you can add a True as last parameter for checkboxes, if you want them
# checked by default
g.add(CheckBox("me is checked", lambda x: d("co %s" % x), True))
g.add(Button("name4", lambda:d("name4")))
# now the radio buttons: just a list of names, the state is passed
# by the callback
g.add(RadioButtons(("name1", "name2", "name3"), lambda x: d(x)))
## now a complicated example with tabs
# first a group, without parent and name, but saved to a variable
h = Group(pos=(4,4))
h.add(Label("HHHHHHH"))
h.add(Button("das ist ein Button", lambda:None))
h.add(RadioButtons(("radio1", "radio2", "radio4"), lambda x: d(x)))
# second group
i = Group(pos=(8,4))
k = Group("X-Axis")
# here is a other down side of the "layout manager"
# you have to finish the group bevor adding it to another group
# because if not all elements are added, the height of the sub group
# is not calculated corretly
k.add(Button("+", lambda : d("x+")))
k.add(Button("-", lambda : d("x-")))
i.add(k)
k = Group("Y-Axis")
k.add(Button("+", lambda : d("y+")))
k.add(Button("-", lambda : d("y-")))
i.add(k)
k = Group("Z-Axis")
k.add(Button("+", lambda : d("z+")))
k.add(Button("-", lambda : d("z-")))
i.add(k)
# a more realistic example with some real data
j = Group(pos=(8,4))
j.add(Label("Audio Input"))
j.add(RadioButtons(
("0 - Built-in Microphone", "1 - Built-in Input",
"2 - Built-in Output", "3 - Soundflower (2ch)"),
lambda x: d("setting device: %s" % x.split()[0]),
checked=0))
j.add(Label("Audio Output"))
j.add(RadioButtons(
("0 - Built-in Microphone", "1 - Built-in Input",
"2 - Built-in Output", "3 - Soundflower (2ch)"),
lambda x: d("setting device: %s" % x.split()[0]),
checked=2))
# and finally a avg node
from random import randint
r = avg.PolyLineNode(
pos=[(randint(-10,310), randint(-10,310)) for x in xrange(900)])
# constructing the tabs as easy as possible. a list of tuples,
# containing the name of the tab and the element to show
Tabs([("randompoints", r), ("haa",h), ("iee",i), ("Audio", j)],
pos=(440,20), size=(270,300), parent=root)
player.play()
_______________________________________________
libavg-users mailing list
[email protected]
https://mail.datenhain.de/mailman/listinfo/libavg-users