About Automatic Layouting, and Skinning

Discussion regarding the development of CEGUI itself - as opposed to questions about CEGUI usage that should be in the help forums.

Moderators: CEGUI MVP, CEGUI Team

N0vember
Just popping in
Just popping in
Posts: 5
Joined: Fri Dec 24, 2010 04:05

About Automatic Layouting, and Skinning

Postby N0vember » Fri Dec 24, 2010 15:46

Hello, CrazyEddie and kulik !

I am currently using your library for a project of flexible and networked RPG-oriented game engine, which, thanks to libraries like CEGUI is going quite well.
So first of all let me thank you for your great work ! I'll post a video of my project soon, I promise.

It's been more than I year that I have been sporadically using CEGUI, designing layouts, reading your updates about where you're headed, and I'm starting to get a view of the two only points where I feel CEGUI lacks something. I think these two points are the only thing needed for CEGUI to be considered complete and more than anything, easy to use. Everything else (like the tools) would be a bonus.

These two points are :
- Automatic layouting as a core feature and not as a particular type of window. Absolute positioning (be it ratio-based or pixel-based) should be possible but would be rarely used.
When I say layouting, I'm talking about positionning but also automatic shrinking and expanding.
To illustrate this first point, the thing to ask yourself is : what do you do when you design an interface mockup on paper. You divide the screen rectangles into sub rectangles, and then put constraints on them, depending on what you want to fit inside them. You very rarely care in the exact position of a widget : it generally just fit as a content in a subdivision you defined, with given margins.
Designing a GUI layout in code should feel exactly like this process. I will create a window and then divide it vertically. The subdivisions themselve could have minimum or maximum size constraints. And they should always shrink and expand, in the limit defined by these constraints, to their contents.
The hassle associated to writing any layout would be vastly diminished, and the result would be much more flexible and scalable. The absolute positioning system would still be usable.

I think the current approach of a separate LayoutContainer wouldn't allow this because the system needs to recurse through the whole hierarchy to play nicely, whereas a separate LayoutContainer can't recurse.

If you think the idea is worth any value I would gladly make a more detailed proposal, maybe even a patch ? I don't think the amount of coding involved is enormous, but I think I'll look into it by myself.
Thinking about it, since I need such a system for my project I may even write a patch anyway and see what it's worth

The second point where CEGUI has been giving me headaches is the skinning :
- An easy and straightforward skining system
I think the current system has reached a point of over-flexibility, where you can basically do anything you want in a Look'n'Feel definition, but the cost associated with doing anything is way is way too high, and the responsibilities are interleaved in a confused and confusing manner.

Skining should really be just this : the visual appearance of a window/widget. Skinning and logic should not be mixed, so you could change a skin on the fly on any widget at any time.
A skin should really just be defined by this :
- Top, bottom, left, right borders images
- All four angles images
- A filler image
- A global image
- A font, size, color

And that's it. Defining the look of a widget should take you from 3 to ~10 lines of text, and involve nothing else than the appearance of a window at a given state.
It should be appliable to any widget, whatever the type of this widget : I shouldn't care whether the widget will be a pushbutton or a statictext or whatever when writing a skin : it should be reusable accross many different types.
A skin is not linked to any functional definition. It's not linked to a particular kind of widget. It can be applied to ANY widget.

The current skinning systems contains many other things which I don't think should be part of a skinning system.
- Layouting should be part of layouts, not skin. The current system allows layouting in the look'n'feel : the current framewindow is one widget, whereas it should be really three widgets assembled in a layout, and accessible from code logic.
- The logic between switching different states should not be part of the skin. For example, if a button has three states, which are linked to three different skin (button_normal, button_hover, and button_down), these should be defined separately in a look'n'feel definition.

So, in the end, I guess a Skin definition should be factored out from the current Look'n'feel, to make responsibilities more clear and design more easy and straightforward.
The skin would define general appearances appliable to any widget, whereas the look'n'feel would bind specific skins to specific states.

I understand this is a much more complicated topic than the layouting, so I'm more leaving this as an inspiration if you plan to refactor this part of the library any soon.

So... here they are. The two only frustrations I've encountered from an end-user point of view. The rest is really great
Last edited by N0vember on Fri Dec 24, 2010 17:36, edited 2 times in total.

User avatar
Kulik
CEGUI Team
Posts: 1382
Joined: Mon Jul 26, 2010 18:47
Location: Czech Republic
Contact:

Re: About Automatic Layouting, and Skinning

Postby Kulik » Fri Dec 24, 2010 17:34

First of all, merry Christmas or whatever you are celebrating :-)

Second of all, I agree that layouting is very important and that was the reason why I started hacking CEGUI in the first place. Everything else was pretty good. I think the way CEGUI does it now with LayoutContainer widgets is pretty much standard (used in Qt and other libraries). I plan to make a more powerful, fast and flexible Grid LayoutContainer to ease this even more (with spanning, on-the-fly resizes, etc...). What exactly can't you accomplish with this approach? I agree that it feels like an additional layer but IMO it's the best compromise. Making CEGUI::Window even more bloated with extensive layouting features isn't worth it IMO.
Of course I am open to any proposal but I would probably need a specific one, preferably with a use case.

I agree that looknfeel is too powerful for it's own good. However making it less powerful doesn't appeal to me that much. There was a time when I played with the idea of "everything is a widget". Basically I wanted to make CEGUI::Widget very lightweight (position, size and that's it). Then every widget can be composed of child widgets, obsoleting frame components, image components, etc... That would probably be even more powerful and painful to use than the current system though :lol: I think I can make your proposal work by doing something like NovemberLook/MetaWidget looknfeel. The MetaWidget would take properties and show stuff based on that. The only downside is that you would have to repeat them a lot in the layout files. LookNFeel would have to have inheritance to make this really painless. Then you could create Meta skins to ease the pain for specific cases.

N0vember
Just popping in
Just popping in
Posts: 5
Joined: Fri Dec 24, 2010 04:05

Re: About Automatic Layouting, and Skinning

Postby N0vember » Fri Dec 24, 2010 19:04

Oh yeah i forgot, merry christmas you you too !

Kulik wrote:Second of all, I agree that layouting is very important and that was the reason why I started hacking CEGUI in the first place. Everything else was pretty good. I think the way CEGUI does it now with LayoutContainer widgets is pretty much standard (used in Qt and other libraries). I plan to make a more powerful, fast and flexible Grid LayoutContainer to ease this even more (with spanning, on-the-fly resizes, etc...). What exactly can't you accomplish with this approach? I agree that it feels like an additional layer but IMO it's the best compromise. Making CEGUI::Window even more bloated with extensive layouting features isn't worth it IMO.
Of course I am open to any proposal but I would probably need a specific one, preferably with a use case.


What's lacking is the automatic sizing. And ease of use (-> no boilerplate code = setting up a layouted window should demand no more than one or two lines of code)
The examples uses are :
I want to be able to add a subwindow to a window and having it take the whole space available i I don't specify its size.
I want to be able to set its size in one direction, and having it expand automatically in the other direction.
I want the parent window of a LayoutContainer, which has the visuals, to shrink automatically to its contents, and when this happens, all the surrounding layout to adapt itself.
I want to be able to implement a tree/browser widget without hassle, which is the simplest thing to do with an automatic sizing system : it's just a few windows inside another window inside another window : no extra coding/hacking involved.

Especially, I want to be able to write a layout file that looks like this, in pseudocode :

Code: Select all

<Window>
    <LayoutDirection = Vertical>
    <Button name = TitleBar>
         <Text = "Submit a message">
         <ExpandHorizontally = True>
    </Button>
    <Window>
         <LayoutDirection = Horizontal>
         <Window name = ButtonBar>
             <Button> <Text = "Submit"></Button>
             <Button> <Text = "Preview"></Button>
        </Window>
        <Window name = EditBox>
             <TextBox> </TextBox>
             <ExpandHorizontally = True>
        </Window>
    </Window>
</Window>


And get a result that will automatically look like this :
Image

You see the idea here ?
I don't need to set any size or position at any moment because everything layout automatically.
-the titlebar takes expands automatically to the whole width.
-the buttonbar shrink to the size of the buttons, which shrink to the size of their text
-the editbox expands to the size that remains

However, if I did manually set a size, the layout would take it into account as a constraint.

If you look around you, the present website for example, its interface would be really fast to prototype with such a system, but a pain-in-the-ass to prototype with a coordinate or relative positionning system like CEGUI has.

The best way to handle this is to recursively shrink, and/or recursively expand contents, every time a change is notified up the hierarchy.
Even if it's possible to do this recursion (through EventSized) with a hierarchy alterning Windows and LayoutContainers, you would then have twice the number of windows for the same functionality, which would considerably bloat my code example.
Adding one LayoutContainer per Window to achieve a global layouted system seems like a real pain.
My point is also that if done right, no one will ever have use for the traditional window because it's way clunkier.

So maybe the best approach is to just to create a LayoutWindow prototype based on your layouting code, and use a ->addLayoutedChild(LayoutWindow*) which will be used instead of the traditional ->addChildWindow() method.

I'll come back on the skins later :p

N0vember
Just popping in
Just popping in
Posts: 5
Joined: Fri Dec 24, 2010 04:05

Re: About Automatic Layouting, and Skinning

Postby N0vember » Mon Nov 28, 2011 19:57

Double-posting for a good reason.
I have actually implemented the system I proposed to you to integrate it into my engine, and as it mostly works I thought I'd share it.
I just wrote two wrapper classes LayoutContainer and SequenceContainer.
LayoutContainer basically encapsulate the CEGUI Window. It implements the necessary interface needed to be laid out by another window in whatever dimension.
SequenceContainer is a container automatically sequencing any window you add to it. You can still add 'free' windows to it too, independently from the sequenced content.

Advantages :
No Vertical / Horizontal class distinction : a SequenceContainer is a SequenceContainer, and you precise the dimension it should sequence its elements in the constructor
Automatic layouting without setting any position anywhere : you should almost never bother with coordinate positions when dealing with user interface design, and my system is designed accordingly
Expanding handling : Expanding windows automatically take all the place they can in the parent window. Multiple expanding windows divide the space available according to the weight you affect them in the SequenceContainer.
Shrinking handling : Shrinking windows automatically shrink to their sequenced content size.

Here are two videos from my project where you can see it in action. I know my interfaces are not too complicated so it doesn't show the full potential, but it's still proof it works.
I almost never set a position anywhere in the interface code (python wrapped for my convenience)
The dimensions are set for subelements like labels, but ideally they should wrap to the text too by default




This one here shows the only bug I've found so far :


EDIT : I actually just resolved this bug, which was just a clipping issue.
It's due to the fact CEGUI apparently need the child size to be updated after the parent size in order to clip windows correctly, while my system updated the parent window after the child one.

I didn't write GridContainer yet but it should be fairly straightforward : it's just a SequenceContainer in the main direction (column or line) that automatically add SequenceContainer in the other direction

So that's it. If you're interested into getting a look at the code to maybe integrate it I'll gladly share it.

User avatar
Kulik
CEGUI Team
Posts: 1382
Joined: Mon Jul 26, 2010 18:47
Location: Czech Republic
Contact:

Re: About Automatic Layouting, and Skinning

Postby Kulik » Mon Nov 28, 2011 22:06

I am definitely interested in the code. I was planning to do exactly this for CEGUI 0.8 but didn't due to lack of time. Are you willing to bring it up to CEGUI code quality and integrate it to CEGUI 0.8?

I named the inner wrapper class LayoutCell and the outer class LayoutContainer.

N0vember
Just popping in
Just popping in
Posts: 5
Joined: Fri Dec 24, 2010 04:05

Re: About Automatic Layouting, and Skinning

Postby N0vember » Tue Nov 29, 2011 21:44

Well I'm sorry but right now don't have much time to integrate it to CEGUI myself : I designed it as a wrapper and I will continue to use it as-is for the time being.
Here's the code I use, with a few points as a disclaimer :
1. I'm using aggregation and not inheritance because in my design ALL widgets are LayoutContainers, so I wrap all windows whatever their type, because subclassing each type would have been a nightmare
The consequence is, to integrate it the way it was meant to into CEGUI the LayoutContainer code should become base Window code (it would be simplified in the process by the way since aggregating complicates things a little bit)

2. There is quite an overlap between what my LayoutContainer does and what a CEGUI::Window already does, i.e. some of the data is duplicated (size, position, margins). I did it because it allowed to me to write a clean, simple and easy to read system as opposed to a mess.

So, here are the files. I quickly edited them to make the namespace CEGUI so I may have forgotten something somewhere, but it should work as-is
http://dl.dropbox.com/u/46683967/LayoutContainer.cpp
http://dl.dropbox.com/u/46683967/LayoutContainer.h
http://dl.dropbox.com/u/46683967/SequenceContainer.cpp
http://dl.dropbox.com/u/46683967/SequenceContainer.h

User avatar
Kulik
CEGUI Team
Posts: 1382
Joined: Mon Jul 26, 2010 18:47
Location: Czech Republic
Contact:

Re: About Automatic Layouting, and Skinning

Postby Kulik » Sun Dec 04, 2011 14:17

The code can't go in as is and since you won't volunteer I think the chances are slim :-(

Maybe 0.9


Return to “CEGUI Library Development Discussion”

Who is online

Users browsing this forum: No registered users and 15 guests