[Alpha] TreeGUI

treeform, is the version on the download site really the latest one? The label “alpha-1” confuses me…

No you always get the latest one here:

code.launchpad.net/~starplant/treegui/treegui3

Here is a select list using buttons. Highlighting is not working properly, but other than that it works fine. Anytime I set the style on a button the program crashes in theme.py.

First I had to define a subclass of Button. This was needed so that I can pass the value of the button to a function in my SingleSelectList as a parameter.

class ValueButton(Button):
	def mouseEvent(self,key,x,y):
	    if key == "mouse1" and self.onClick:
	        self.onClick(self.value)
            return True

Here is the SingleSelectList class. If you’ll notice I override the _createInner function and hide the x scrollbar.

class SingleSelectList(ScrollPane):
    value = None
    buttons = []
    def __init__(self,options,*args,**kargs):
        ScrollPane.__init__(self, *args,**kargs)
        
        for i,option in enumerate(options):
            button = ValueButton(option, onClick=self.setSelectedOption, pos=Vec2(10,10+int(i)*25), size=Vec2(75,15))
            button.value = option
            self.add(button)
            self.buttons.append(button)
      
        self.selected = None
                
    def _createInner(self,xextend=3,yextend=3):
        self.inner = self.add(Pane())
        self.inner.width=100000
        self.inner.height=100000
        self.inner.style = None
        
        sbx = ScrollBarX(x=xextend,y="bottom -3",
            height=10,width="100% -20")
        sbx.visable = False
        self.sx = self.add(sbx)
        self.sy = self.add(ScrollBarY(y=yextend,x="right  -3",
            width=10, height="100% -20"))
        
        self.sx._compute = 0
        self.sy._compute = self.yScroll
        self.add = self.inner.add
        self.clear = self.inner.clear
       
    def getSelectedOption(self):
        return self.value
           
    
    def setSelectedOption(self, value):
        i = 0
        
        for button in self.buttons:
            if button.value == value:
                self.selected = i
                self.value = value
                break

            i = i + 1
       
        return True

mouseEvent is more of low level event you should not mess with. Probably should rename it to _event. Other wise highlighting and other stuff might get disabled and if you return True from that function it would consume all the events sent to it.

I should probably create a “ScrollDownPane” because X-bar is rairly useful any ways.

I will try to integrate this into the repo.

EDIT -------

I have put new tut_listview.py ( bazaar.launchpad.net/~starplant/ … istview.py ) with your sample. I am still not sure about using indexes in the list view. Maybe just using option and not care about the “i” would be better. Also getSelectedOption is a getter that’s too simple and maybe should just be a var.

Yeah, I need to break myself of the habit of making get/set functions(when using python), it just feels wrong to not have them.

I have one other thing I’ve been trying to figure out. I’m not sure if this should be solved via treegui, or collisions.

I’m using treegui for all 2d elements in my game, the issue that I’m having is that when I click a 2d element (rendered to render2d), the click interacts with both the 2d element and the 3d world (typically moving my character to a point behind where I have a form displayed).

Is there a way to make treegui elements “solid” so that clicks do not pass through to render as well? Or will I need to handle this using collision bitmasks? (I have collisions working perfectly within render itself)

First post on the forum even if I have been around for some time now.
I want to thank all the panda team and contributors for the awesome work that has been done here and treeform for the TreeGui which simplified my GUI code a lot.

Pharmakon, to answer your question, I did it like this :

if self.gui.hoveringOver:
  return

hoveringOver is set to None when there is nothing under the cursor otherwise it is the component under the mouse.

(and self.gui is the GUI(theme=theme) instance, but I think you had guessed)

Thanks Tlarhices, thats exactly what I was looking for.

I think it would be helpful to add functions add(option) and remove(option) to the SingleSelectList class.

I will post the code I threw together if there is interest.

I was about to start learning Wx for my next project and then I saw this. It seems to be what I was looking for.

I’ll start looking into it in the next week.

JB

Chodaz,

I’d be interested in seeing your changes.

Tlarhices, thats interesting i never though of using the hoveringOver like that. But i guess it works.

Yes i have several improvements i need to integrate from 2aw.

Pharmakon, Just a though but you could use treeGUI to render those other elements as well. I should create a sample for a simple hexbased game with 100% treegui use.

Here is a quick attempt to add the functions I mentioned. I can’t guarantee it will work well. I haven’t had time to test it much.

class SelList(SingleSelectList):
	''' A slightly modified SingleSelectList'''
	def __init__(self,options,*args,**kargs):
		SingleSelectList.__init__(self, options, *args,**kargs)
		self.buttons = []
		self.selectedButton = None
		
	def addOption(self,option):
		i = len(self.buttons)
		button = ValueButton(
				option, 
				i,
				onSelect=self.setSelectedOption, 
				pos = Vec2(10,10+int(i)*25), 
				size = Vec2(self.width-40,15))
		self.add(button)
		self.buttons.append(button)
	
	def delOption(self,option):
		# Rebuild button list so values and positions are all updated
		newButtons = []
		i = 0
		for b in self.buttons:
			self.remove(b)
			if b.text is not option:
				b.value = i
				b.pos = Vec2(10,10+int(i)*25)
				self.add(button)
				newButtons.append(button)
		self.buttons = newButtons

I don’t trust the way I appended the button to the list, using the length of the list to get the new i value but it has worked so far. It may be a better idea to rebuild the list the way I did for delete.

I also had to bring the button list initialization into init.

I also wrote a drop-down selection for the previous treegui version. I am getting around to testing it in this newer version. I will post it as soon as I dig it out and try it.

Thanks Chodaz.

@Treeform,

The sample for creating a simple hexbased game would be cool to see.

In drawText and drawEditText of drawer.py

Replace:

u,v,w,h,e = self.atlas.getChar(name + str(code))

by :

try:
  u,v,w,h,e = self.atlas.getChar(name + str(code))
except KeyError:
  u,v,w,h,e = self.atlas.getChar(name + str(ord("?")))

So when a trying to display a character not present in the font, it will be replaced by an interrogation mark instead of crashing in an ugly way.

Note : If there is no interrogation mark, it will still crash.

Good idea!

I have added support of the full unicode range.
It creates glyphs for all characters in the file and a small change to drawer so it can find them back.

I have made a diff available here :
http://pastebin.com/f4e18a1ef

I have hit what may be a bug or at least a limitation.
If I create a EggAtlasMaker with a size bigger than 2048 (power of 2 or not), the drawer will display garbage. With 3072 I have partial gui objects displayed, with 4096 it is all random picks from the texture.

Does it comes from a bug in the code or is it due to the hardware I am having not being able to cope with textures of more than 2048x2048 ?

Edit : I forgot to say that the code here will add a “missing character” glyph that will be displayed when displaying a character not in the font.

    def getRect(self,name):
        """ 
            return 4 values that correspond to the named rectangle 
        """ 
        try:       
            image = self.images[name]
            return image.x,image.y,image.w,image.h
        except KeyError:
            for key in self.images.keys():
                if key.endswith(name):
                    image = self.images[key]
                    return image.x,image.y,image.w,image.h
            print "can't find",name,"in:",self.images.keys()
            return None

This change in getRect gives the possibility to change the icon set by theme, it was not possible before as the theme name was needed to be given in the icon name like “rtheme/twotone/radio-off.png” now you can give a name not taking into account the theme “twotone/radio-off.png” or even just the file name “radio-off.png”.

Tlarhices, i am still thinking on how to support the full unicode range by regenerating the atlas at run time.

I never like how you referenced icons. But endswith could also cause trouble. Like two icons blue/hud.png and red/hud.ong ; looking for “hud.png” would produce either blue hud or red hud.

I know about the possibilities of name conflict when using endswith, you need to be careful to be as precise as possible when using it.

Another quick fix would be to test against “/”.join(key.split("/")[1:])
This will remove the first folder so it will not work for a complex theme hierarchy.

the init.py of the theme could also look where it is located and give it to the eggatlas so it can search against name and themeFolder+"/"+name

Generating the atlas at run time would mean changing the texture every time a new character is displayed. It is not so much of a problem with most languages, but if you are going to use the code for a verbose chinese version (RPG descriptions of all items in inventory, characters descriptions, magical power descriptions, …), you will need to add a few new character every dialog and fill the texture quite fast.

Would it be possible to have several textures ?
There could be one for icons and graphical things. And one per unicode plane or per unicode language.
You would have a atlas-pic, atlas-english, atlas-chinese, …
And if you create only the english atlas (start the game in english) and a chinese character needs to be displayed (internet game chat for instance) you can pull the missing character to a temporary atlas and start generating atlas-chinese in background for future use.

Using two texture for TreeGUI is hard because you cant alpha sort between two geoms. Some how using multiple texture targets or 3d textures might work.

So it would have to regenerate whole texture each time new Chinese dialogue comes up. Good thing is that regenerating is kind of fast - the slowest part is reading data off disk.