-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use of a markup language to design the ui #370
Comments
I've also somewhat been experimenting with this because it's a great idea. keeping track of all of the constructors, managers, rects, containers, and anchors somewhat feels overcomplicated once there are more than a few elements. Something like HTML would be perfect. I've somewhat tried to implement it myself, and as of now it does work pretty well for what I've tried
I'd say that it works pretty well and isn't too verbose, but the structure is not final at all This isn't the exact output of the example above, but it's very similar and was rendered with my markup implementation However, there's some problems that I could see arising from creating a markup language though (somewhat ranting)
Everything has its problems though, and markup is definitely doable and would make life 100x easier, so I agree with you. Would like to know what you think about the direction I'm thinking of and if you agree or disagree with any of it. |
Your XML implementation is almost the same as mine, except fot the theme part. About the problems you mentionated:
This is the Python code I use in the project I'm working on: import pygame
import pygame_gui
import os
import xml.etree.ElementTree as xmlET
class XMLStructure:
def __init__(self, xml_path: str, screen, manager) -> None:
self.xml_path = xml_path
self.screen = screen
self.manager = manager
# Allowed gui elements
self.allowed_elements = [
'image', 'button', 'textbox', 'textentryline', 'horizontalslider', 'dropdownmenu', 'panel'
]
# This dictionary contains all the gui elements
self.elements = {}
# Parse the XML file
self.parse()
def parse(self):
tree = xmlET.parse(self.xml_path)
root = tree.getroot()
self.expand(root)
return self.elements
def expand(self, parent):
"""
For every element contained in a tag, create an object and store it in the dictionary
"""
for child in parent:
if child.tag in self.allowed_elements:
self.elements[child.attrib['name']] = self.add_ui_element(child.tag, child.attrib, parent)
self.expand(child)
def add_ui_element(self, tag: str, attrib: dict, parent):
"""
Read the tag name and create the associated gui elements with all the attributes
"""
# In order to use the screen size in the pos and size attributes, without hardcoding it in the files,
# use 'WIDTH' and 'HEIGHT' as placeholders.
# Ex: pos="(WIDTH - 900, 0)"
# If the WIDTH of the screen is 1920 then the resulting tuple will be (1020, 0)
pos = eval(attrib['pos'].replace('WIDTH', str(self.screen[0])).replace('HEIGHT', str(self.screen[1])))
size = eval(attrib['size'].replace('WIDTH', str(self.screen[0])).replace('HEIGHT', str(self.screen[1])))
rect = pygame.Rect(pos, size)
container = None
object_id = None
visible = 1
# Set the container of the current element as the parent tag
if parent.tag in self.allowed_elements:
container = self.elements[parent.attrib['name']]
if 'class' in attrib and 'id' in attrib:
object_id = pygame_gui.core.ObjectID(class_id = '@' + attrib['class'], object_id = '#' + attrib['id'])
if 'visible' in attrib:
visible = int(attrib['visible'])
element = None
if tag == 'image':
element = pygame_gui.elements.UIImage(
relative_rect = rect,
image_surface = pygame.image.load(os.path.join(os.getcwd(), attrib['src'])),
manager = self.manager,
container = container,
object_id = object_id
)
elif tag == 'button':
element = pygame_gui.elements.UIButton(
relative_rect = rect,
text = attrib['text'],
tool_tip_text = attrib['tool_tip_text'],
manager = self.manager,
container = container,
object_id = object_id
)
if len(attrib['tool_tip_text']) == 0:
element.tool_tip_text = None
elif tag == 'textbox':
element = pygame_gui.elements.UITextBox(
relative_rect = rect,
html_text = attrib['html_text'],
manager = self.manager,
container = container,
object_id = object_id
)
elif tag == 'textentryline':
element = pygame_gui.elements.UITextEntryLine(
relative_rect = rect,
manager = self.manager,
object_id = object_id,
container = container
)
if 'white_list' in attrib:
element.set_allowed_characters(attrib['white_list'])
elif tag == 'horizontalslider':
element = pygame_gui.elements.UIHorizontalSlider(
relative_rect = rect,
start_value = float(attrib['start_value']),
value_range = eval(attrib['value_range']),
manager = self.manager,
container = container,
click_increment = float(attrib['click_increment']),
object_id = object_id
)
elif tag == 'dropdownmenu':
element = pygame_gui.elements.UIDropDownMenu(
relative_rect = rect,
options_list = attrib['options_list'].split(';'),
starting_option = attrib['starting_option'],
manager = self.manager,
object_id = object_id,
container = container,
visible = visible
)
elif tag == 'panel':
element = pygame_gui.elements.UIPanel(
relative_rect = rect,
starting_layer_height = int(attrib['starting_layer_height']),
manager = self.manager,
container = container,
object_id = object_id,
visible = visible
)
return element It's not pretty but it works. Keep in mind I wrote this code just to get the things work in my project. I plan to rewrite this code and add more functionalities. |
It's dope to see that we're both on about the same path. Like, literally all of my tag names are the same as yours. I wonder if there's some sort of way to communicate about this library beyond just the issues section because that would be really helpful to just be able to sort things out. |
We can use Telegram or even better Discord, if you are ok with that, I will send you an email. |
Hello! I do not have anything against markup languages (the library already uses json for theming after all), nor them being being used for layout. What you are discussing here sounds a lot like XAML to me, at least that is the version of this concept I am most familiar with. I'm not as convinced of a layout markup's usefulness in an interpreted programming language like python right now, as it is pretty quick in most of my applications so far to make a quick change to the layout in the code and then re-run the program without any lengthy compile times. Then again most of my usage has been pretty simple layouts, and if it does get more complicated then I tend to build a UIElement in the library to make it less complicated. Though perhaps a markup language could be a half-way house to a visual layout editor program? Something which would undoubtably be useful. I will also say that I am always trying to reduce the amount of boilerplate. I recently reduced a simple Button creation to this:
As a test (this works right now in 0.6.6), and am looking to extend these particular changes across the whole project where possible so that you don't always have to pass around So, I would say to your somewhat infectious markup enthusiasm - make sure you are definitely solving for the right problem. If markup is mostly just to eliminate boilerplate stuff when creating elements - lets try and cut straight to eliminating that first. If it more for dynamic refreshing, or a stepping stone towards a visual GUI layout editor then I'm definitely more into it. |
It's funny because a builder was actually what I secretly had in mind, but that's definitely its own project in itself since its such a huge undertaking. Here's like a really alpha prototype view that I just threw together in Inkscape It's just a dream though for now, just a pitch |
Yeah discord should be just fine if you're down, cobyj33#0489 |
I also started working with something similar, using XML-like markup for design the ui with pygame_gui, and i came up with this: @component('''
<Window title="Some Window" top="10" left="10" width="{width}" height="400">
<Button name="button">Click-me!</Button>
</Window>
''')
class DummyUI:
button: pygame_gui.elements.UIButton
def __init__(self, manager) -> None:
self.__build__(manager, width=340) Essentially, a decorator Then, this class can be used like: manager = pygame_gui.UIManager((800, 600))
my_ui = DummyUI(manager)
my_ui.button # points to the <Button name="button"> element For bigger templates, embedding them inside python code could be uglier, so the |
I want to get in on this as well! I wrote a proof of concept HTML file and interpreter using exclusively built-in functions. |
Is your feature request related to a problem? Please describe.
I'm currently working on a project where I need to create an high number of gui elements. The problem is that this way things start to get confusing and I end up with a verbose code.
Describe the solution you'd like
In order to organize better my code, I moved the declarations of the gui elements in a separated XML file. This way is almost like writing a web page in HTML. Plus, using an XML file (or something like that), it could be possible to introduce a dynamic refresh of the elements every time there is a change.
Describe alternatives you've considered
I don't have other ideas, I just wanted to share this concept I implemented (in a doubius way) in my code.
Additional context
I understand that it is a very specific request and so there could be no interest in adding it, but I hope you like the idea.
The text was updated successfully, but these errors were encountered: