Now that I've talked about how Widgets can be used, its time to discuss how they can be configured.
Positioning:
Widgets are manually positioned by specifying their position and size:
Widget(float x, float y, float width, float height);
At first, it used to be just absolute values, but that turned out to make certain things, specially in-game GUIs harder than they needed to. So I changed position to be relative to their parents values. This however was not good
enough for editor-like GUIs where you want a button with a specific size. So for each of this components, you can specifiy which mode you want:
enum class PositionMode{ REL, SCREEN, REF, ABS};
REL means relative to the parent widgets size. Widgets are positioned at the upper left corner of their parent regardless, but with REL and 0.5 you can make a widget eigther half as big as their parent, or position them in the middle of it.
SCREEN means relative to the screens size.
REF is pretty obsolute by this point. It means relative to a reference size which can be user-configured, and should allow easy rescale of a huge number of widgets, but it didn't turn out to be all the useful in practice.
ABS is used for absolute values, if you i.e. know that a button should be exactly 21 pixels high.
Then there is something I called "Cap metrics":
void SetCapMetrics(int minW, int maxW, int minH, int maxH);
Its the max/min values of how big the widget can be. Its for example used make a window stay over a certain size.
Alignement/Center:
Next, we have alignement:
enum class HorizontalAlign{ LEFT, CENTER, RIGHT};enum class VerticalAlign{ TOP, CENTER, BOTTOM};void SetAlignement(HorizontalAlign hAlign, VerticalAlign vAlign);
Alignement will move the widgets origin in regard of its parent. You could do the same thing manually by setting the x/y accordingly, but this will make it easier to still move the widget even if it should start at the parents lower right.
You can also set the position center of the widget:
void SetCenter(HorizontalAlign hCenter, VerticalAlign vCenter);
Which does exactly what you would expect. Default is upper left, but if you want to position a widget with its middle point at a certain position, thats the way to go.
Padding/Size relation:
Then we have padding:
void SetPadding(int x, int y, int w, int h);
Padding adds (or subtracts) a fixed amount of space from specific sides of the widget. If you want to have a widget that fills its parent, minus 8 pixel on each side, thats the way to go.
For making widgets have a certain size relation, there is also an option:
enum class BorderRelation{ NONE, HEIGHT_FROM_WIDTH, WIDTH_FROM_HEIGHT};void SetBorderRelation(BorderRelation relation, float factor);
Its unfortunately a little clumsy to use in practice, and I'm still looking for a way to improve the terminoly. But if you set BorderRelation to anything other than none with a factor of 1.0, it will result in a quadratic widget. The factor
and the mode determines the exact look, so you can make a widget that is exactly twice as high as its width, and so on...
Functionality:
A widget can have keyboard-focus. It doesn't make much sense for each widget to capture focus on click, so I used a straightforward mechanism to decide how a widget reacts to a potential focus gain:
enum class FocusState{ IGNORE_FOCUS, DELEGATE_FOCUS, KEEP_FOCUS};void SetFocusState(FocusState state);
IGNORE_FOCUS means just that. If a widget is issues a focus gain event, it totally ignores it, resulting in the current focus widget to stay focused.
DELEGATE_FOCUS is the default value and results in the widget delegating the focus gain to its parent. This does not have an immediate result, but depends on the state of the parent.
KEEP_FOCUS will make the widget gain focus, and the current focus widget to loose his.
This flag, in a combination with the child/parent system pretty much allows you to confiqure the focus handling as you would please. Most widgets will simply delegate the focus up to their parent. Imagine a label widget in a textbox.
Others will simply ignore it, like the window icon. And others will want to keep focus, like said textbox. You can also lock the focus on a certain widget:
void SetFocusLocked(bool lockFocus);
However, sometimes it is not enough to just configure the widgets focus behaviour. For an icon on a button, you pretty much want this to also ignore all possible events, so that the button is full responsive. For this, you can disable specific widgets:
void SetEnabled(bool bEnabled);
A disabled widget will still be rendered, but ignore all other events. All childs of an disabled widget are also disabled.
Thats it for this time. Thanks for reading! The next gui-related entry will go in-depth about rendering with all optimizations. Until that time, have a screenshot of what the GUI is currently capable of:
Because next time, I'll start to talk about the entity-component framework that I've been developing.