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

Reply via email to