|
|
@@ -4,26 +4,26 @@ GUI layouts {#guiLayouts}
|
|
|
In previous chapter we talked about how **GUIPanel** is a special type of a GUI element called a "layout". Layouts serve as containers for GUI elements (including other layouts), and they may also control how are elements within them positioned and sized.
|
|
|
|
|
|
There are three types of layouts:
|
|
|
- - @ref bs::GUIPanel "GUIPanel" - Does no automatic positioning and sizing of child GUI elements, instead user can set positions and sizes manually, as we have already seen. Each panel can be placed at a different depth, allowing GUI elements to overlay eachother.
|
|
|
- - @ref bs::GUILayoutX "GUILayoutX" - Automatically positions and sizes child GUI elements horizontally one next to each other, left to right. User is able to request minimum/maximum allowed size, but is otherwise unable to manually position or exactly size the element.
|
|
|
+ - @ref bs::GUIPanel "GUIPanel" - Does no automatic positioning and sizing of child GUI elements, instead user can set positions and sizes manually, as we have already seen. Each panel can be placed at a different depth, allowing GUI elements to overlay each other.
|
|
|
+ - @ref bs::GUILayoutX "GUILayoutX" - Automatically positions and sizes child GUI elements horizontally one next to each other, left to right. User is able to request minimum/maximum allowed size, but is unable to manually position the element.
|
|
|
- @ref bs::GUILayoutY "GUILayoutY" - Same as **GUILayoutX** only elements are positioned vertically, top to bottom.
|
|
|
|
|
|
You will find that vertical and horizontal layouts come in handy when you need to design GUI that needs to scale across various screen sizes/resolutions. By adding your GUI elements to such layouts instead of manually positioning them, ensures the GUI system can always keep them at optimal position and size, regardless of the available screen area.
|
|
|
|
|
|
# Adding/removing elements
|
|
|
In the previous chapter we have already seen how to add a GUI element to a layout (a panel, more specifically). Here is the entire interface for dealing with element addition/removal, shared by all layout types:
|
|
|
- - @ref bs::GUILayout::addNewElement<Type, Args...> "GUILayout::addNewElement<T>" - Adds a GUI element of the specified type to the end of the layout's element list.
|
|
|
- - @ref bs::GUILayout::insertNewElement<Type, Args...> "GUILayout::insertNewElement<T>" - Inserts a GUI elements of the specified type at a specific position in the layout's element list.
|
|
|
- - @ref bs::GUILayout::removeElement "GUILayout::removeElement" - Removes a GUI element from the layout's element list.
|
|
|
+ - @ref bs::GUILayout::addNewElement<Type, Args...> "GUILayout::addNewElement<T>()" - Creates a new element of type *T* and adds it to the end of the layout's element list.
|
|
|
+ - @ref bs::GUILayout::insertNewElement<Type, Args...> "GUILayout::insertNewElement<T>()" - Creates a new element of type *T* and inserts it at a specific position in the layout's element list.
|
|
|
+ - @ref bs::GUILayout::removeElement "GUILayout::removeElement()" - Removes a GUI element from the layout's element list.
|
|
|
|
|
|
-Here's an example of retrieving the primary GUI panel and adding some elements to it:
|
|
|
+Here's an example of retrieving the GUI widget's primary panel and adding some elements to it:
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
// Assuming "gui" is a GUI widget component
|
|
|
GUIPanel* mainPanel = gui->getPanel();
|
|
|
|
|
|
// Add a horizontal layout that will automatically position child elements
|
|
|
-GUILayoutX layout = mainPanel->addNewElement<GUILayoutX>();
|
|
|
+GUILayoutX* layout = mainPanel->addNewElement<GUILayoutX>();
|
|
|
|
|
|
// Add a text label, and a button to the right of it
|
|
|
layout->addNewElement<GUILabel>(HString(L"This is a button: "));
|
|
|
@@ -31,50 +31,220 @@ layout->addNewElement<GUIButton>(HString(L"Click me"));
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
GUI elements can also be created separately and then added to layouts later using these methods:
|
|
|
- - @ref bs::GUILayout::addElement "GUILayout::addElement" - Adds an existing GUI element at the end of the layout's element list.
|
|
|
- - @ref bs::GUILayout::insertElement "GUILayout::insertElement" - Inserts an existing GUI elements at a specific position in the layout's element list.
|
|
|
+ - @ref bs::GUILayout::addElement "GUILayout::addElement()" - Adds an existing GUI element at the end of the layout's element list.
|
|
|
+ - @ref bs::GUILayout::insertElement "GUILayout::insertElement()" - Inserts an existing GUI elements at a specific position in the layout's element list.
|
|
|
|
|
|
-Same example as above, only written differently:
|
|
|
+Same result as above, only written differently:
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
// Assuming "gui" is a GUI widget component
|
|
|
GUIPanel* mainPanel = gui->getPanel();
|
|
|
|
|
|
// Add a horizontal layout that will automatically position child elements
|
|
|
-GUILayoutX layout = GUILayoutX::create();
|
|
|
-mainPanel->addElement(layout);
|
|
|
+GUILayoutX* layout = mainPanel->addNewElement<GUILayoutX>();
|
|
|
|
|
|
// Add a text label, and a button to the right of it
|
|
|
GUILabel* label = GUILabel::create(HString(L"This is a button: "));
|
|
|
GUIButton* button = GUIButton::create(HString(L"Click me"));
|
|
|
|
|
|
-layout->addNewElement(label);
|
|
|
-layout->addNewElement(button);
|
|
|
+layout->addElement(label);
|
|
|
+layout->addElement(button);
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
The matter which style you use is personal preference.
|
|
|
|
|
|
# Horizontal layout
|
|
|
-// TODO
|
|
|
+Horizontal layouts are represented with the **GUILayoutX** class. Any objects added to such a layout will be positioned automatically, left to right next to other elements in the layout. When a GUI element is in such a layout, you will not be able to manually set the element's position.
|
|
|
|
|
|
-@ref TODO_IMAGE
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Add five GUI buttons laid out horizontally
|
|
|
+GUIPanel* mainPanel = gui->getPanel();
|
|
|
+
|
|
|
+// Add a horizontal layout that will automatically position child elements
|
|
|
+GUILayoutX* layout = mainPanel->addNewElement<GUILayoutX>();
|
|
|
+
|
|
|
+for(int i = 0; i < 5; i++)
|
|
|
+{
|
|
|
+ GUIButton* button = layout->addNewElement<GUIButton>(HString(L"Click me #" + toWString(i)));
|
|
|
+ button->setWidth(90);
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
|
|
|
# Vertical layout
|
|
|
-// TODO
|
|
|
+Vertical layouts are represented with the **GUILayoutY** class. Similarly to horizontal layouts, vertical layouts also perform automatic positioning but top to bottom instead of left to right.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Add five GUI buttons laid out vertically
|
|
|
+GUIPanel* mainPanel = gui->getPanel();
|
|
|
+
|
|
|
+// Add a vertical layout that will automatically position child elements
|
|
|
+GUILayoutY* layout = mainPanel->addNewElement<GUILayoutY>();
|
|
|
+
|
|
|
+for(int i = 0; i < 5; i++)
|
|
|
+{
|
|
|
+ GUIButton* button = layout->addNewElement<GUIButton>(HString(L"Click me #" + toWString(i)));
|
|
|
+ button->setWidth(90);
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
|
|
|
-@ref TODO_IMAGE
|
|
|
+# Customizing automatic layouts
|
|
|
+Even though vertical & horizontal layouts are automatic, Banshee provides a variety of mechanisms that allow you to customize the position and size of GUI elements in such layouts.
|
|
|
|
|
|
-# Customizing
|
|
|
-## Styles
|
|
|
-// TODO - GUIOptions, mention styles
|
|
|
+## Flexible size
|
|
|
+Each GUI element can have a flexible size that determines its minimum & maximum allowed width/height. This is in contrast to the fixed size we were setting in the example above.
|
|
|
+
|
|
|
+When a flexible size is set a GUI layout is allowed to resize the element to best fit the layout area, within the provided size range. Flexible size can be set by calling @ref bs::GUIElement::setFlexibleWidth "GUIElement::setFlexibleWidth()" and @ref bs::GUIElement::setFlexibleHeight "GUIElement::setFlexibleHeight()".
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Add five GUI buttons laid out horizontally, with flexible sizes
|
|
|
+GUIPanel* mainPanel = gui->getPanel();
|
|
|
+
|
|
|
+// Add a horizontal layout
|
|
|
+GUILayoutX* layout = mainPanel->addNewElement<GUILayoutX>();
|
|
|
+
|
|
|
+for(int i = 0; i < 5; i++)
|
|
|
+{
|
|
|
+ GUIButton* button = layout->addNewElement<GUIButton>(HString(L"Click me #" + toWString(i)));
|
|
|
+
|
|
|
+ // Button will be anywhere between 50 and 200 pixels, depending on how much space is there in the layout
|
|
|
+ button->setFlexibleWidth(50, 200);
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+The layout will attempt to choose optimal size to fill out the available space. If elements don't fit, they will be clipped instead.
|
|
|
+
|
|
|
+By default different GUI element types might have either a fixed or a flexible size. This is controlled by their *style*, which we'll talk about later.
|
|
|
+
|
|
|
+
|
|
|
|
|
|
## Spaces
|
|
|
-// TODO
|
|
|
+When a GUI element is a part of a vertical or a horizontal layout, you can no longer control its position manually. This means that calling **GUIElement::setPosition()** will have no effect.
|
|
|
+
|
|
|
+You can however control positioning by some extent by inserting spaces between layout elements. There are two types of spaces: fixed and flexible.
|
|
|
+
|
|
|
+@ref bs::GUIFixedSpace "GUIFixedSpace" - Inserts a space of X pixels at the position in the layout it is added to. As a parameter it takes the number of pixels it will take up. Essentially it acts like an invisible GUI element of a certain width or height.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Add five GUI buttons laid out horizontally, with 10 pixels spacing between them
|
|
|
+GUIPanel* mainPanel = gui->getPanel();
|
|
|
+
|
|
|
+// Add a horizontal layout
|
|
|
+GUILayoutX* layout = mainPanel->addNewElement<GUILayoutX>();
|
|
|
+
|
|
|
+for(int i = 0; i < 5; i++)
|
|
|
+{
|
|
|
+ GUIButton* button = layout->addNewElement<GUIButton>(HString(L"Click me #" + toWString(i)));
|
|
|
+ button->setWidth(90);
|
|
|
+
|
|
|
+ layout->addNewElement<GUIFixedSpace>(10);
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+@ref bs::GUIFlexibleSpace "GUIFlexibleSpace" inserts a space that will resize itself to fill all available area in the layout. If normal GUI elements already fill the layout area then the flexible space will be of size 0. If there are multiple flexible spaces in a layout, the available size will be spread out equally between them.
|
|
|
+
|
|
|
+Flexible spaces can be used for centering and justifying GUI elements.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Add five GUI buttons laid out horizontally, justified so they neatly align with left/right borders of the layout
|
|
|
+GUIPanel* mainPanel = gui->getPanel();
|
|
|
+
|
|
|
+// Add a horizontal layout
|
|
|
+GUILayoutX* layout = mainPanel->addNewElement<GUILayoutX>();
|
|
|
+
|
|
|
+for(int i = 0; i < 5; i++)
|
|
|
+{
|
|
|
+ GUIButton* button = layout->addNewElement<GUIButton>(HString(L"Click me #" + toWString(i)));
|
|
|
+ button->setWidth(90);
|
|
|
+
|
|
|
+ if(i != 4)
|
|
|
+ layout->addNewElement<GUIFlexibleSpace>();
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+## Position and size
|
|
|
+Layouts can be positioned and resized like any other GUI element. All elements inside a layout will be relative to the layout's position, and elements that don't fit within the size of the layout will be clipped. Size of the layout also controls how are flexible sizes determined (either element's or space's).
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Add a horizontal GUI layout, position and size it
|
|
|
+GUIPanel* mainPanel = gui->getPanel();
|
|
|
+
|
|
|
+// Offset the layout to (50, 50) position, and set its size to 150 pixels wide
|
|
|
+// and 25 pixels high
|
|
|
+GUILayoutX* layout = mainPanel->addNewElement<GUILayoutX>();
|
|
|
+layout->setPosition(50, 50);
|
|
|
+layout->setSize(150, 25);
|
|
|
+
|
|
|
+// Add five buttons to the layout
|
|
|
+for(int i = 0; i < 5; i++)
|
|
|
+{
|
|
|
+ GUIButton* button = layout->addNewElement<GUIButton>(HString(L"Click me #" + toWString(i)));
|
|
|
+ button->setWidth(90);
|
|
|
+
|
|
|
+ if(i != 4)
|
|
|
+ layout->addNewElement<GUIFlexibleSpace>();
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
|
|
|
# Compound layouts
|
|
|
-// TODO
|
|
|
+Layouts themselves are treated as GUI elements. This means you can add layouts as children to other layouts, allowing you to create complex looking graphical interfaces. For example lets create a table of four rows and five columns of buttons:
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+GUIPanel* mainPanel = gui->getPanel();
|
|
|
+
|
|
|
+GUILayoutX* columns = mainPanel->addNewElement<GUILayoutX>();
|
|
|
+for (int i = 0; i < 5; i++)
|
|
|
+{
|
|
|
+ GUILayoutY* rows = columns->addNewElement<GUILayoutY>();
|
|
|
|
|
|
-@ref TODO_IMAGE
|
|
|
+ for(int j = 0; j < 4; j++)
|
|
|
+ {
|
|
|
+ GUIButton* button = rows->addNewElement<GUIButton>(HString(L"Click me"));
|
|
|
+ button->setWidth(70);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(i != 4)
|
|
|
+ columns->addNewElement<GUIFlexibleSpace>();
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
|
|
|
# Panels
|
|
|
-// TODO - Depth
|
|
|
+**GUIPanel** is a special type of layout that doesn't perform any automatic positioning. Instead, as we've already seen, it allows you to position and size the elements directly, when you need exact precision over their placement. Elements like spaces or flexible sizes have no effect on GUI elements part of a GUI panel.
|
|
|
+
|
|
|
+Aside from allowing you to control exact placement of elements, they can also be used for overlaying GUI elements on top of each other. When created each GUI panel accepts a depth parameter which controls where is it positioned relative to other panels. Higher depth means the panel will be rendered below those with lower depth.
|
|
|
+
|
|
|
+Lets show an example of using a GUI panel to manually position and size a GUI element, as well as using the depth parameter to show two overlapping GUI elements.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Load texture to use for the underlay
|
|
|
+HTexture tex = gImporter().import<Texture>("BansheLogoRoundSmall.png");
|
|
|
+HSpriteTexture spriteTexture = SpriteTexture::create(tex);
|
|
|
+
|
|
|
+// Render this panel below the main panel
|
|
|
+INT16 depth = 1;
|
|
|
+GUIPanel* background = mainPanel->addNewElement<GUIPanel>(depth);
|
|
|
+
|
|
|
+// Add a background image to the background panel
|
|
|
+GUITexture* guiTexture = background->addNewElement<GUITexture>(spriteTexture);
|
|
|
+guiTexture->setPosition(250, 90);
|
|
|
+guiTexture->setSize(150, 150);
|
|
|
+guiTexture->setTint(Color(1.0f, 1.0f, 1.0f, 0.5f));
|
|
|
+
|
|
|
+// Add a button to the main panel, which renders a depth 0 (default), in front of the background panel
|
|
|
+GUIButton* button = mainPanel->addNewElement<GUIButton>(HString(L"Click me"));
|
|
|
+button->setPosition(280, 190);
|
|
|
+button->setSize(90, 25);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|