GUI Layout Management

Started by
2 comments, last by jengerer 12 years, 11 months ago
Hey guys,

This post might be a bit winded, but I'd really appreciate if I could get some guidance on this one.

I've been working on an app/game for a while now, but I keep finding myself having a distaste for how I'm running my GUI framework. The way I have it set up right now is similar to Java Swing, in that I have Components and Containers being the basic classes of the layout, where Containers can have Components within, etc.

The main challenges I'm facing are:

  1. How to be able to position child components in a layout respective to the parent's position. The way I had it done before was that my Container had an UpdatePosition virtual function that Container classes would overwrite. I don't like this method much because some containers, such as ones that lay 50+ children out in a grid, can be pretty heavy operations to run each frame.
  2. Being able to get the absolute position of the components to do things like checking mouse collision. After doing what I mentioned in #1, I tried using D3DXMATRIX to transform the world before each container was drawn. That way, if a component was at position (0, 0) relative to its parent, and its parent was at (30, 30), the component would be drawn at (30, 30). However, when it comes to collision detection, I can't simply use these relative positions.

I was thinking of maybe giving Container a LayoutManager class, which could store the relative position of each child, and then when the container is moved, have it simply add the relative position to the parent's position, but decided to post here and see if maybe I could get some opinions. Anyone done anything similar?

Thanks for getting this far,
Jengerer
Advertisement
I can't know what your app is. If it's GUI app, when it needs collision detection?
If we are talking about GUI layout, I found the concept "sizer" in wxWidgets is quite good and easy to use.
With the very simple basic sizers, such as box sizer (layout in a row or in a column), grid sizer, flexible grid sizer, you can give the container any layout by composite the sizers.
But with the sizer concept, all positions are relative, so maybe not good for collision detection.

https://www.kbasm.com -- My personal website

https://github.com/wqking/eventpp  eventpp -- C++ library for event dispatcher and callback list

https://github.com/cpgf/cpgf  cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.

Layouting 2D objects is not that different from layouting 3D objects, and hence most if nor all of the same strategies can be used. E.g. define a global/view placement to be the transformation of an element. This transformation is usually a position/orientation/scale w.r.t. the view space. When an element is bound to a container, it is done by using a 2nd transformation that describes how the element is related to its container. When the layout of a root element is computed, then the layout parameters directly define the global/view transformation. When the layout of a dependent element is computed, then the layout parameters define the relational transformation which needs to be concatenated with the container's global/view transformation to yield in the own global/view transformation.

This builds up a classic dependency tree: The layout of an element can be updated if and only if the layout of its container (if any) is already up-to-date, and the element can itself be a container. Hence all the typical strategies can be used: Sorting the elements into dependency order, concentrating all updates in a sub-system for efficiency (if possible), using "dirty" tags and propagation to avoid working on unchanged layout, ... Especially the last point may be of interest for issue 1: Only those element(s) that need to be updated are processed. If nothing has changed, than only the root elements (perhaps only 1) are started but they terminate the update immediately.

The 2nd issue is a typical collision detection problem. With the up-to-date global/view transformation at hand, the element's bounding box can be transformed. This can efficiently be done by the same sub-system as above. After transforming the mouse position into the same space, it can iteratively (from "leaves to root", so to say) be compared with the bounding boxes, until an element declares the mouse event for being processed.
I can't know what your app is. If it's GUI app, when it needs collision detection?

I mentioned in the OP that the collision detection I was referring to was with the mouse, sorry if that wasn't clear from my wall of text. :)

The 2nd issue is a typical collision detection problem. With the up-to-date global/view transformation at hand, the element's bounding box can be transformed. This can efficiently be done by the same sub-system as above. After transforming the mouse position into the same space, it can iteratively (from "leaves to root", so to say) be compared with the bounding boxes, until an element declares the mouse event for being processed.

I considered a similar solution after I implemented the world transformation before drawing (so that each child would be drawn relative to the parent), but I didn't really like that each child class of container that handled mouse events would have to manually transform the position before iterating on its children. I mean, it would likely be done by a helper function, but it would still need to be called manually for each child component because their positions relative to the parent would be different.

What do you think of the possible solution I posted at the end of my post? To clarify what I meant, each container would have a layout manager, and when you add objects to the container, it stores the relative positions of all its children, and then if you need to move that parent, it'll simply iterate through the children and add the stored relative positions so that all positions are absolute, but the relative positions remain intact. I mean, I think a matrix multiplication for each texture/object is more expensive than doing two additions for each object, and only when the parent object is moved. Plus, it makes mouse event handling easier because all component positions are absolute.

This topic is closed to new replies.

Advertisement