Gui libary position and size handling

Started by
5 comments, last by Juliean 10 years, 10 months ago

Hello,

while finishing my latest university game project using my engine, I encountered a giant flaw in my gui libary: I was using absolute positioning, which turned out to be quite a pain for writing game guis accounting different resolutions, since I had to calculate these absolute coordinates accordingly to the screen size everywhere I was using the gui. Now I begin changing from absolute to relative screen coordinates (0.0f - 1.0f), but there are some issues with that, too. Right now, the widgets calculate their absolute coordinates from their parents, if there isn't any parent, then from the screen. However, what about a scrollbar, which should have the height of its parent widget, but have a fixed width, regareless of the parents metrics? Or a square button, that might eigther need to be aligned for the height of a toolbar or the height/width of a respective oriented scrollbar. For normal cases, I could just overload a few methods in the respective widget, but what if there is the need for some interaction?

Take the scrollbar for another example. My scrollbar is made out of two buttons and a fixed slider. With the old, absolute positioning system, layouting this was no problem:


Scrollbar::Scrollbar(int height)
{
    // x - y - width - height
    m_pUpperButton = new Button(0, 0, 16, 16);
    m_pSlider = new Slider(0, 16, 16, height-32);
    m_pLowerButton = new Button(0, height-16, 16, 16);
}

Now with the new relative method, I don't have any idea how to unroll this.


Scrollbar::Scrollbar(float height)
{
    // x - y - width - height
    m_pUpperButton = new Button(0.0f, 0.0f, 0.0f, 0.0f); // this button needs to fit the scrollbars width, so:
    m_pUpperButton->SetCapRect(16, 16, 16, 16); // one solution here was to manually cap the size
    m_pSlider = new Slider(0.0f, ???, ???, ???); // but what about the slider? It needs to be sized and positioned according to the buttons
    m_pLowerButton = new Button(0.0f, ???, 0.0f,  0.0f); // again, we could hack-fix the button to be width*width, but we still don't know how to position him
}

So uhm, how is this normally handled in gui libaries? Obviously there is so many combinations of widgets position parameters that eigther need to be relative, absolute, or semi (the slider actually needs to resize with the scrollbar, but keep the -buttonWidth*2 - offset off its height). I can think of some complicated solutions, requiring a dozen setters and bool flags. I'm sure there is an easier way, isn't there? Thanks in advance for any suggestion!

Advertisement

That's why you shouldn't use magic numbers. All sizes should be configurable and stored as your preferences somewhere.

For layouts in Windows, it uses "dialog units" which is based on the average letter size of the default font (may be a specific letter) so if you change your font sizes everything should continue to look acceptable. Using very large fonts can make the layouts look bad though, and not all apps use dialog units which can make the layout look bad or break.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

That's why you shouldn't use magic numbers. All sizes should be configurable and stored as your preferences somewhere.

Yeah, I am well aware of that, unfortunately I didn't get that over in the sample code. "16" really is not a magic number but at least const-hardcoded right now. I'm working on loading everything from XML-files, just thought I'd tackle that problem first. The main problem here, which, regardeless of magic numbers or not remains is this:

Since slider and buttons are independant, so that even when I'm having stored the "scrollbar width", I still can't programm this to being taken into account for the slider - since the slider might be positioned standalone, it needs to basically be positioned relatively in screen coordinates from 0.0f - 1.0f. But only if it is used in correlation with these two buttons, size and position of the slider gets sort of an absolute component - the slider now needs to be sized 1.0f of its parent (scrollbar) size, minus two times the buttons size. I'm concerned about, how this could be implemented the most efficiently, and, most of all, generically? Since the widgets absolute metrics are calculated using their relative position and their parents metrics, like this:


				m_absX = (int)(m_x * m_pParent->GetWidth()) + m_pParent->GetX();
				m_absY = (int)(m_y * m_pParent->GetHeight()) + m_pParent->GetY();
				m_absWidth = (int)(m_width * m_pParent->GetWidth());
				m_absHeight = (int)(m_height * m_pParent->GetHeight());

I'm really unsure how to account for something as the absolute position offset needed for the slider in the scrollbar, which still needs to be somewhat dynamical (the scrollbar might resize, which should update this absolute component of the sliders position). Any ideas how to handle this properly?

Handle the resizing in the SetSize (or Resize, or SetLayout, whatever) method of the scrollbar. Call the method from the constructor and call it again when you need to resize the scrollbar.

Resizing a window should recalculate the layout for all the child windows and force the GUI to redraw itself.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley
You are better of at looking how modern HTML and CSS rendering handle different screen space solutions than working in real coordinate systems. Even defining your own and then a transformation to real screen space is going to make your life easier as that way the width of on object can be made constant regardless of resolution size.

The last games I worked on the UI was constructed in world space coordinates and the way a camera looked at it in world space determined how the UI looked on screen. We used a 14:9 aspect ratio to render our orthographic scenes with so that we stayed in the middle of 16:9 or 4:3 which are the major resolutions you should deal with. Corner elements in screen space where anchored of global anchors and they moved with the screen space size and moved elements, they didn't really rescale though. This achieves the independent positioning you are after whilst you can maintain object sizes as well.

But again a UI system all comes down to your requirements and I don't have enough of them to see what you want to do here.

Also bear in mind that I work with artist and designers how actually create the art assets to make up the screen. I deal with the functional side so that the right animations are triggered in the right place and so that they have widgets to work with that bind to the correct data in game.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

Juliean, on 03 Jun 2013 - 13:41, said:
So uhm, how is this normally handled in gui libaries? Obviously there is so many combinations of widgets position parameters that eigther need to be relative, absolute, or semi (the slider actually needs to resize with the scrollbar, but keep the -buttonWidth*2 - offset off its height). I can think of some complicated solutions, requiring a dozen setters and bool flags. I'm sure there is an easier way, isn't there? Thanks in advance for any suggestion!

my gui system uses one vector4 for figuring out positioning, and one for size, then stores this calculated value in a vector2 for it's visible position, and a vector2 for it's visible size.

the first 2 floats represent the percentage distance along the parent ui's(or screen at the top) x/y coordinates(so 0.0 is at the left/top, and 1.0 is position at the right/bottom.) the second 2 are pixel distance's, that are added to the percentage distance, so when i'm calculating the visible position/size of the gui object, the equation looks like this:
Vector2 VisiblePosition = Parent->GetVisiblePosition().xy+Parent->GetVisibleSize().xy*m_Position.xy+m_Position.zw;
Vector2 VisibleSize     = Parent->GetVisibleSize().xy*m_Size.xy+m_Size.zw;
this scales pretty decently across multiple resolutions when used correctly. for example, if i child a vertical scrollbar to a textbox, i can make it always as high as the textbox and always sit on the right side of the textbox, but also give it a fixed size width(or a combination of fixed size, with maybe .2 percent the size of a textbox, or any other combo really).
Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

Thanks for all the suggestions,

I actually ended up with a combination of what all of you suggested. I'm now storing sort of a "padding" as in html, which is an absolute offset for the size and position, like slice4ever suggested. I calculate this value e.g. in the scrollbars resize method, in case the button resizes. Works well so far, hopefully will continue to, I quite like the new way for programming the new gui, safes a lot of work and "spaghetti code".

But again a UI system all comes down to your requirements and I don't have enough of them to see what you want to do here.

You are right, I didn't tell much about my requirements. The thing is, aside from that I want the gui system for both game and editor functionality for future game projects, being able to work data-driven (at least for the design part of the gui), therefore possibly creating a visual gui-editor as Qt has it, somewhere in the near future, I don't really know what my requiremenets are, I sort of develope them along with the game projects. At first I thought absolute positioning was a good thing, while I was working only on the editor, but as I started with the actual game and gui, I discovered this was far too complicated. So given that I want to develope games and tools, I don't really think the orthographic approach you where talking about would work too well, right now I'm using screenspace-transformed sprites, at least for the editor this sounds more reasonable to me...

This topic is closed to new replies.

Advertisement