This is a file parser for DirectGUI. It uses the ini file format, I’ve mainly wrote this for the community where I’m in, which kind of needs somehow a file standard for those DirectGUI stuff. I’ve did XML before, but that didn’t work out very well (thanks treeform). This parser is useful in some ways:
- It isn’t that much slower as normal python code (currently 4 gui objects require 0.018 seconds for parsing/attaching them to a nodepath)
- This is a slighty more clear then adding some attributes @ the constructor and then using Direct[’ '] or Direct.setPos().
- It’s easy to share UI interfaces with this, when you only need to ship the file and just need 2 lines to implement it into your game.
The features currently are:
- Parsing a file on a specified nodepath (you can parse the same file on more nodepaths, or other way around)
- Reloading while runtime (pretty useful)
- Everything is in the ini file format.
How to use:
- Create a new INI file.
- Create a section with the variable name which should hold the GUI object (you can retrieve this during runtime in the returned dict from GUIParser.parse() or GUIParser.variable)
- Add the items you wish
If you have improvements, bug fixes, comments or anything else, feel free to post it. The parser still isn’t completed and far from optimized, it only allows a few NodePath options now, you should be able some yourself if you need them, or just request them.
Here’s an example showing how to use it.
Python code:
from pandac.PandaModules import loadPrcFileData, KeyboardButton, MouseButton, WindowProperties, TextNode
from direct.gui.DirectGui import *
import direct.directbase.DirectStart
import GUIParser
parser = GUIParser.GUIParser()
dict = parser.parse("test.ini", render2d)
def reload():
parser.reload("test.ini", render2d)
base.accept('r', reload)
run()
GUI File (test.ini):
[button1]
type=DirectButton
pos=(1,0,0)
color=(255,0,0,0.4)
[frame1]
type=DirectEntry
pos=(0.2,0,0)
color=(255,0,0,0.4)
scale=0.2
framecolor=(255,0,0,0.4)
text=Hi
[frame2]
type=DirectEntry
pos=(-0.4,0,0)
text=Hi
text_bg=(255,0,0,0.4)
text_scale=0.5
scale=0.4
[button2]
type=DirectButton
pos=(-1,0,0)
text=Button
Source code:
from direct.gui.DirectGui import *
import ConfigParser
import time
classNames = {
'DirectButton':DirectButton,
'DirectCheckButton':DirectCheckButton,
'DirectRadioButton':DirectRadioButton,
'DirectDialog':DirectDialog,
'DirectFrame':DirectFrame,
'DirectLabel':DirectLabel,
'DirectEntry':DirectEntry,
'DirectOptionMenu':DirectOptionMenu,
'DirectScrolledList':DirectScrolledList,
'DirectWaitBar':DirectWaitBar,
'DirectSlider':DirectSlider,
'DirectScrollBar':DirectScrollBar,
'DirectScrolledFrame':DirectScrolledFrame,
}
class GUIParser(object):
def __init__(self, filename=None, nodepath=None):
"""Constructor of the GUIParser class. It's possible to specify filename/nodepath at instancing"""
self.filename = filename
self.nodepath = nodepath
self.dict = {}
def parse(self, filename=None, nodepath=None):
"""Parses a single file.
If filename and nodepath are specified, they will get used.
If not, we will use the values stored when we got instanced."""
filename = filename or self.filename
nodepath = nodepath or self.nodepath
self.config = ConfigParser.ConfigParser()
self.config.read(filename)
start = time.clock()
for section in self.config.sections():
name = section
type = self.config.get(name, "type")
instance = classNames[type]()
setattr(self, name, instance)
self.dict[name] = instance
for option in self.config.options(section):
self.parseAttribute(name, option, instance)
end = time.clock()
print "Time elapsed = ", end - start, "seconds"
return self.dict
def parseAttribute(self, name, attribute, instance):
"""Parses a single attribute"""
if attribute == 'pos':
instance.setPos(tuple(self.parseTuple(self.config.get(name, attribute))))
if attribute == 'hpr':
instance.setHpr(tuple(self.parseTuple(self.config.get(name, attribute))))
if attribute == 'color':
instance.setColor(tuple(self.parseTuple(self.config.get(name, attribute))))
if attribute == 'scale':
text = self.config.get(name, attribute)
if text.startswith("(") and text.endswith(")"):
instance.setScale(float(self.parseTuple(text)))
else:
instance.setScale(float(self.config.get(name, attribute)))
if attribute == 'frameColor':
instance['frameColor'] = tuple(self.parseTuple(self.config.get(name, attribute)))
if attribute.startswith('text'):
if attribute == 'text':
instance['text'] = self.config.get(name, attribute)
instance.setText()
elif attribute == 'text_bg':
instance['text_bg'] = tuple(self.parseTuple(self.config.get(name, attribute)))
elif attribute == 'text_fg':
instance['text_fg'] = tuple(self.parseTuple(self.config.get(name, attribute)))
elif attribute == 'text_pos':
instance['text_fg'] = tuple(self.parseTuple(self.config.get(name, attribute)))
elif attribute == 'text_scale':
text = self.config.get(name, attribute)
if text.startswith("(") and text.endswith(")"):
instance['text_scale'] = float(self.parseTuple(text))
else:
instance['text_scale'] = float(text)
if attribute == 'dgg':
text = self.config.get(name, attribute)
if text == 'DGG.NORMAL':
instance['state'] = DGG.NORMAL
elif text == 'DGG.DISABLED':
instance['state'] = DGG.DISABLED
if attribute.startswith('image'):
if attribute == 'image':
instance['image'] = self.config.get(name, attribute)
elif attribute == 'image_pos':
instance['image_pos'] = tuple(self.parseTuple(self.config.get(name, attribute)))
elif attribute == 'image_hpr':
instance['image_hpr'] = tuple(self.parseTuple(self.config.get(name, attribute)))
elif attribute == 'image_scale':
text = self.config.get(name, attribute)
if text.startswith("(") and text.endswith(")"):
instance['image_scale'] = float(self.parseTuple(text))
else:
instance['image_scale'] = float(text)
def parseTuple(self, tuple):
"""Parses a tuple from a string, returning a list, where you can use tuple(list) for a tuple again"""
split = tuple[1:-1].split(',')
return [float(x) for x in split]
def destroyObjects(self):
"""Removes all GUI objects from the nodepath"""
for key, value in self.dict.items():
value.destroy()
def reload(self, filename=None, nodepath=None):
"""Reloads all the GUI objects"""
self.destroyObjects()
self.parse(filename, nodepath)
I hope you guys like it, thanks