|
|
@@ -19,7 +19,7 @@ GUIPanel* mainPanel = gui->getPanel();
|
|
|
|
|
|
**GUIPanel** is a special type of a GUI element called a "layout". We'll discuss layouts in more detail in the next chapter, but for now all you need to know is that they are element containers you can add and remove other GUI elements to/from.
|
|
|
|
|
|
-To add an element to the panel use @ref bs::GUIPanel::addElement "GUIPanel::addElement".
|
|
|
+To add an element to the panel use @ref bs::GUIPanel::addElement "GUIPanel::addElement()".
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
mainPanel->addElement(label);
|
|
|
@@ -29,11 +29,22 @@ At this point our GUI element will be displayed.
|
|
|
|
|
|

|
|
|
|
|
|
+# Destroying GUI elements
|
|
|
+You do not need to manually destroy a GUI element that is registered with a layout (e.g. a **GUIPanel**). Such elements will be destroyed automatically when their parent layout is destroyed. If their parent layout is connected to **GUIWidget** root panel, then all layouts and elements will be destroyed with the widget.
|
|
|
+
|
|
|
+In case you need to manually destroy a GUI element you can call @ref bs::GUIElement::destroy "GUIElement::destroy()".
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+GUIElement::destroy(label);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Such element will also automatically be removed from the parent layout (if any).
|
|
|
+
|
|
|
# Customizing GUI elements
|
|
|
All GUI elements share a common set of methods you can use to customize their position, size, color and other properties.
|
|
|
|
|
|
## Changing position
|
|
|
-You can change the position of a GUI element by calling @ref bs::GUIElement::setPosition "GUIElement::setPosition". The position is in pixels, relative to the top left corner of the render target.
|
|
|
+You can change the position of a GUI element by calling @ref bs::GUIElement::setPosition "GUIElement::setPosition()". The position is in pixels, relative to the top left corner of the render target.
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
// Moves the displayed text to coordinates (50, 50)
|
|
|
@@ -41,14 +52,14 @@ label->setPosition(50, 50);
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
## Changing size
|
|
|
-Element size can be changed by calling @ref bs::GUIElement::setSize "GUIElement::setSize".
|
|
|
+Element size can be changed by calling @ref bs::GUIElement::setSize "GUIElement::setSize()".
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
// Make the label 30 pixels high, and 100 pixels wide
|
|
|
label->setSize(100, 30);
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
-You can also set both position and size at the same time by calling @ref bs::GUIElement::setBounds "GUIElement::setBounds".
|
|
|
+You can also set both position and size at the same time by calling @ref bs::GUIElement::setBounds "GUIElement::setBounds()".
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
// Make the label 30 pixels high, and 100 pixels wide, and position it at (50, 50)
|
|
|
@@ -56,7 +67,7 @@ label->setBounds(Rect2I(50, 50, 100, 30));
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
## Changing color
|
|
|
-You can change the tint of the GUI element with @ref bs::GUIElement::setTint "GUIElement::setTint". By default an all-white tint is used for all elements.
|
|
|
+You can change the tint of the GUI element with @ref bs::GUIElement::setTint "GUIElement::setTint()". By default an all-white tint is used for all elements.
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
// Make the label text green
|
|
|
@@ -64,7 +75,7 @@ label->setTint(Color::Green);
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
## Hiding
|
|
|
-You can temporarily hide an element with @ref bs::GUIElement::setVisible "GUIElement::setVisible". As the name implies hidden element will not be displayed, and cannot be interacted with.
|
|
|
+You can temporarily hide an element with @ref bs::GUIElement::setVisible "GUIElement::setVisible()". As the name implies hidden element will not be displayed, and cannot be interacted with.
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
// Hide the label
|
|
|
@@ -78,14 +89,14 @@ label->setVisible(true);
|
|
|
Banshee provides a large library of existing GUI element types. We'll focus on explaining the most important ones, but you can find an exhaustive list in @ref GUI.
|
|
|
|
|
|
## Label
|
|
|
-A label is the most basic of GUI elements, that allows no user interaction and just displays a textual string. It is created with @ref bs::GUILabel::create "GUILabel::create", which accepts a string as input.
|
|
|
+A label is the most basic of GUI elements, that allows no user interaction and just displays a textual string. It is created with @ref bs::GUILabel::create "GUILabel::create()", which accepts a string as input.
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
GUILabel* label = GUILabel::create(HString(L"Hello!"));
|
|
|
mainPanel->addElement(label);
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
-Once created you can optionally change the displayed text with @ref bs::GUILabel::setContent "GUILabel::setContent".
|
|
|
+Once created you can optionally change the displayed text with @ref bs::GUILabel::setContent "GUILabel::setContent()".
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
label->setContent(HString(L"New text!"));
|
|
|
@@ -98,7 +109,7 @@ label->setContent(HString(L"New text!"));
|
|
|
## Texture
|
|
|
A texture is another basic GUI element that allows no interaction. All it does is display a **SpriteTexture** on the screen.
|
|
|
|
|
|
-To create a GUI texture element, call @ref bs::GUITexture::create "GUITexture::create" which accepts three parameters:
|
|
|
+To create a GUI texture element, call @ref bs::GUITexture::create "GUITexture::create()" which accepts three parameters:
|
|
|
- **SpriteTexture** - Determines which texture to draw.
|
|
|
- @ref bs::TextureScaleMode "TextureScaleMode" - Determines how to scale the texture in the available area.
|
|
|
- Transparency flag - Should transparency be enabled, allowing elements behind the texture to render.
|
|
|
@@ -136,7 +147,7 @@ HSpriteTexture spriteTexture = SpriteTexture::create(tex);
|
|
|
GUIContent imageContents(spriteTexture);
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
-To create a button, call @ref bs::GUIButton::create "GUIButton::create".
|
|
|
+To create a button, call @ref bs::GUIButton::create "GUIButton::create()".
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
GUIButton* textButton = GUIButton::create(textContents);
|
|
|
GUIButton* imageButton = GUIButton::create(imageContents);
|
|
|
@@ -166,7 +177,7 @@ imageButton->onClick.connect(buttonClicked);
|
|
|
## Toggle
|
|
|
Toggle buttons are very similar to normal buttons, with the main difference being that they remain in a toggled state after they have been pressed. Multiple toggle buttons can also be grouped so that only one of them can be toggled at a time. Other than that they share the same interface as **GUIButton**, so we'll focus only on the additional functionality.
|
|
|
|
|
|
-To create an individual toggle button call @ref bs::GUIToggle::create "GUIToggle::create".
|
|
|
+To create an individual toggle button call @ref bs::GUIToggle::create "GUIToggle::create()".
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
GUIToggle* toggle = GUIButton::create(HString());
|
|
|
|
|
|
@@ -175,7 +186,7 @@ mainPanel->addElement(toggle);
|
|
|
|
|
|
To create a set of toggle buttons call **GUIToggle::create** overload with the @ref bs::GUIToggleGroup "GUIToggleGroup" parameter. All toggles sharing the same toggle group will allow only one of the buttons to be active at a time. This allows you to create a "pick one out of many" element.
|
|
|
|
|
|
-To create a toggle group call @ref bs::GUIToggle::createToggleGroup "GUIToggle::createToggleGroup". After that just create the toggle elements as normal, and provide the group as a parameter.
|
|
|
+To create a toggle group call @ref bs::GUIToggle::createToggleGroup "GUIToggle::createToggleGroup()". After that just create the toggle elements as normal, and provide the group as a parameter.
|
|
|
|
|
|
~~~~~~~~~~~~~{.cpp}
|
|
|
SPtr<GUIToggleGroup> group = GUIToggle::createToggleGroup();
|
|
|
@@ -208,13 +219,199 @@ toggle->onClick.connect(elementToggled);
|
|
|

|
|
|
|
|
|
## Input box
|
|
|
-// TODO
|
|
|
+Input boxes allow user to type into them using the keyboard. They can be single-line (default) or multi-line. To create them call @ref bs::GUIInputBox::create "GUIInputBox::create()" where the first parameter specifies whether the input box is single- or multi-line.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+GUIInputBox* singleLineInput = GUIInputBox::create();
|
|
|
+GUIInputBox* multiLineInput = GUIInputBox::create(true);
|
|
|
+
|
|
|
+mainPanel->addElement(singleLineInput);
|
|
|
+mainPanel->addElement(multiLineInput);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Once created you can retrieve the text currently in the input box by calling @ref bs::GUIInputBox::getText "GUIInputBox::getText()".
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+WString userInput = singleLineInput->getText();
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+You can also programatically set text in the box with @ref bs::GUIInputBox::setText "GUIInputBox::setText()".
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+multiLineInput->setText(L"Type in me!");
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+If you wish to get notified as the user is inputting text you can use the @ref bs::GUIInputBox::onValueChanged "GUIInputBox::onValueChanged" event. It will be called whenever the user types a new character (or deletes an existing one).
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+auto respondToInput = [](const WString& text)
|
|
|
+{
|
|
|
+ gDebug().logDebug("New input box value: " + toString(text));
|
|
|
+};
|
|
|
+
|
|
|
+multiLineInput->onValueChanged.connect(respondToInput);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Sometimes you might want to limit what is user allowed to input (for example, just numbers). In that case you can use @ref bs::GUIInputBox::setFilter "GUIInputBox::setFilter()" to set a custom filter callback. The callback accepts a potential input, and returns true if it will be accepted.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+auto intFilter = [](const WString& str)
|
|
|
+{
|
|
|
+ // Use regex to match only integers
|
|
|
+ return std::regex_match(str, std::wregex(L"-?(\\d+)?"));
|
|
|
+};
|
|
|
+
|
|
|
+// This input box now accepts only integers
|
|
|
+singleLineInput->setFilter(intFilter);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
|
|
|
## List box
|
|
|
-// TODO
|
|
|
+List boxes allow you to provide multiple elements the user can pick between. They can allow selection of just a single element (default), or allow multi-selection. List boxes are created by calling @ref bs::GUIListBox::create "GUIListBox::create()" where the first argument represents a list of entries to display on the list, while the second argument specifies whether the list should allow multi-selection or not.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+Vector<HString> listElements =
|
|
|
+{
|
|
|
+ HString(L"Orange"),
|
|
|
+ HString(L"Apple"),
|
|
|
+ HString(L"Banana"),
|
|
|
+ HString(L"Strawberry")
|
|
|
+};
|
|
|
+
|
|
|
+// Create a single-select list with four elements
|
|
|
+GUIListBox* listBox = GUIListBox::create(listElements);
|
|
|
+
|
|
|
+// Create a multi-select list with four elements
|
|
|
+GUIListBox* multiSelectListBox = GUIListBox::create(listElements, true);
|
|
|
+
|
|
|
+mainPanel->addElement(listBox);
|
|
|
+mainPanel->addElement(multiSelectListBox);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Once created, you can retrieve the current selection by calling @ref bs::GUIListBox::getElementStates() "GUIListBox::getElementStates()". This will return a list of booleans that specify if an element at the specified index (corresponding to the initial index of the element when passed to **GUIListBox::create()**) is selected.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+auto selection = multiSelectListBox->getElementStates();
|
|
|
+UINT32 idx = 0;
|
|
|
+for(auto& isSelected : selection)
|
|
|
+{
|
|
|
+ if (isSelected)
|
|
|
+ {
|
|
|
+ WString selectedValue = listElements[idx].getValue();
|
|
|
+ gDebug().logDebug("Element " + toString(selectedValue) + " is selected");
|
|
|
+ }
|
|
|
+
|
|
|
+ idx++;
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+You can also get notified immediately as the selection is changing by subscribing to the @ref bs::GUIListBox::onSelectionToggled "GUIListBox::onSelectionToggled" event. It will report an index of the element that was interacted with, as well a boolean whether the element was just selected or deselected.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+auto selectionToggled = [=](UINT32 idx, bool enabled)
|
|
|
+{
|
|
|
+ WString selectedValue = listElements[idx].getValue();
|
|
|
+
|
|
|
+ if (enabled)
|
|
|
+ gDebug().logDebug("User selected " + toString(selectedValue));
|
|
|
+ else
|
|
|
+ gDebug().logDebug("User deselected " + toString(selectedValue));
|
|
|
+};
|
|
|
+
|
|
|
+listBox->onSelectionToggled.connect(selectionToggled);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
|
|
|
## Slider
|
|
|
-// TODO
|
|
|
+Sliders allow the user to select a numeric value by dragging a slider. Sliders can be vertical or horizontal, represented by @ref bs::GUISliderVert "GUISliderVert" and @ref bs::GUISliderHorz "GUISliderHorz" classes, respectively. They both share the same interface.
|
|
|
+
|
|
|
+To create a slider call either @ref bs::GUISliderVert::create "GUISliderVert::create()" or @ref bs::GUISliderHorz::create() "GUISliderHorz::create()".
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Vertical slider
|
|
|
+GUISliderVert* sliderVert = GUISliderVert::create();
|
|
|
+
|
|
|
+// Horizontal slider
|
|
|
+GUISliderHorz* sliderHorz = GUISliderHorz::create();
|
|
|
+
|
|
|
+mainPanel->addElement(sliderVert);
|
|
|
+mainPanel->addElement(sliderHorz);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Once created you can retrieve the current position of the slider by calling @ref bs::GUISlider::getPercent "GUISlider::getPercent()". This will always return a value in range [0, 1] where 0 represents top/left, and 1 represent bottom/right positions.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+float curSliderPosition = sliderHorz->getPercent();
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+You can also get notified immediately when whe slider handle moves by subscribing to the @ref bs::GUISlider::onChanged "GUISlider::onChanged" event.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+auto sliderPositionChanged = [](float percent)
|
|
|
+{
|
|
|
+ gDebug().logDebug("Current slider position: " + toString(percent));
|
|
|
+};
|
|
|
+
|
|
|
+sliderHorz->onChanged.connect(sliderPositionChanged);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+By default the slider maps to the range [0, 1], but you can also specify a custom range by calling @ref bs::GUISlider::setRange "GUISlider::setRange()".
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Set range from 0 to 360 (e.g. degrees)
|
|
|
+sliderHorz->setRange(0.0f, 360.0f);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Note that even after setting the range **GUISlider::getPercent()** will still return the value in range [0, 1]. Use @ref bs::GUISlider::getValue "GUISlider::getValue()" to get the value in the actual range specified.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+float curSliderValue = sliderHorz->getValue();
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Finally, you can specify a minimum step between two increments of the slider by calling @ref bs::GUISlider::setStep "GUISlider::setStep()". Without a minimum increment the slider can be moved as well as user's input & screen precision allows.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Allow a maximum of 36 increments (increment by 10 degrees)
|
|
|
+sliderHorz->setStep(10.0f / 360.0f);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Note the step is specified in [0, 1] range.
|
|
|
+
|
|
|
+
|
|
|
|
|
|
## Scroll area
|
|
|
-// TODO
|
|
|
+Scroll areas serve as containers for other GUI elements. They can contain more elements that would normally be able to fit in the visible area by providing scrollbars when necessary. Create a scroll area by calling @ref bs::GUIScrollArea::create "GUIScrollArea::create()".
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+GUIScrollArea* scrollArea = GUIScrollArea::create();
|
|
|
+
|
|
|
+// Scroll area's don't have default size, we must specify one. This is where the contents will be displayed.
|
|
|
+scrollArea->setSize(100, 150);
|
|
|
+
|
|
|
+mainPanel->addElement(scrollArea);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+When creating them you can individually control when should vertical or horizontal scroll-bars show up using the @ref bs::ScrollBarType "ScrollBarType".
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Show vertical scrollbar only when contents don't fit in the scroll-bar area, and never show the horizontal scrollbar
|
|
|
+GUIScrollArea* anotherScrollArea = GUIScrollArea::create(ScrollBarType::ShowIfDoesntFit, ScrollBarType::NeverShow);
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Once scroll area is created it will provide you with a layout, similar to how **GUIWidget::getPanel()** works. Call @ref bs::GUIScrollArea::getLayout() "GUIScrollArea::getLayout()" to retrieve the layout, and then attach GUI elements to it normally.
|
|
|
+
|
|
|
+~~~~~~~~~~~~~{.cpp}
|
|
|
+// Add a bunch of elements to the scroll area
|
|
|
+GUILayout& layout = scrollArea->getLayout();
|
|
|
+for(UINT32 i = 0; i < 20; i++)
|
|
|
+{
|
|
|
+ GUIButton* button = GUIButton::create(HString(L"Entry #" + toWString(i)));
|
|
|
+ layout.addElement(button);
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~
|
|
|
+
|
|
|
+We'll go more in depth about layouts in the next chapter.
|
|
|
+
|
|
|
+
|