Pārlūkot izejas kodu

More work on user manuals

BearishSun 9 gadi atpakaļ
vecāks
revīzija
c4d6554781

BIN
Documentation/Manuals/Native/Images/guiInputBox.png


BIN
Documentation/Manuals/Native/Images/guiListBox.png


BIN
Documentation/Manuals/Native/Images/guiScrollArea.png


BIN
Documentation/Manuals/Native/Images/guiSlider.png


+ 213 - 16
Documentation/Manuals/Native/User/guiElements.md

@@ -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.
 **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}
 ~~~~~~~~~~~~~{.cpp}
 mainPanel->addElement(label);
 mainPanel->addElement(label);
@@ -29,11 +29,22 @@ At this point our GUI element will be displayed.
 
 
 ![Simple GUI](guiBasic.png) 
 ![Simple GUI](guiBasic.png) 
 
 
+# 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
 # Customizing GUI elements
 All GUI elements share a common set of methods you can use to customize their position, size, color and other properties.
 All GUI elements share a common set of methods you can use to customize their position, size, color and other properties.
 
 
 ## Changing position
 ## 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}
 ~~~~~~~~~~~~~{.cpp}
 // Moves the displayed text to coordinates (50, 50)
 // Moves the displayed text to coordinates (50, 50)
@@ -41,14 +52,14 @@ label->setPosition(50, 50);
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
 ## Changing size
 ## 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}
 ~~~~~~~~~~~~~{.cpp}
 // Make the label 30 pixels high, and 100 pixels wide
 // Make the label 30 pixels high, and 100 pixels wide
 label->setSize(100, 30);
 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}
 ~~~~~~~~~~~~~{.cpp}
 // Make the label 30 pixels high, and 100 pixels wide, and position it at (50, 50)
 // 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
 ## 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}
 ~~~~~~~~~~~~~{.cpp}
 // Make the label text green
 // Make the label text green
@@ -64,7 +75,7 @@ label->setTint(Color::Green);
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
 ## Hiding
 ## 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}
 ~~~~~~~~~~~~~{.cpp}
 // Hide the label
 // 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.
 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
 ## 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}
 ~~~~~~~~~~~~~{.cpp}
 GUILabel* label = GUILabel::create(HString(L"Hello!"));
 GUILabel* label = GUILabel::create(HString(L"Hello!"));
 mainPanel->addElement(label);
 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}
 ~~~~~~~~~~~~~{.cpp}
 label->setContent(HString(L"New text!"));
 label->setContent(HString(L"New text!"));
@@ -98,7 +109,7 @@ label->setContent(HString(L"New text!"));
 ## Texture
 ## Texture
 A texture is another basic GUI element that allows no interaction. All it does is display a **SpriteTexture** on the screen.
 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.
  - **SpriteTexture** - Determines which texture to draw.
  - @ref bs::TextureScaleMode "TextureScaleMode" - Determines how to scale the texture in the available area.
  - @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.
  - 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);
 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}
 ~~~~~~~~~~~~~{.cpp}
 GUIButton* textButton = GUIButton::create(textContents);
 GUIButton* textButton = GUIButton::create(textContents);
 GUIButton* imageButton = GUIButton::create(imageContents);
 GUIButton* imageButton = GUIButton::create(imageContents);
@@ -166,7 +177,7 @@ imageButton->onClick.connect(buttonClicked);
 ## Toggle
 ## 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.
 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}
 ~~~~~~~~~~~~~{.cpp}
 GUIToggle* toggle = GUIButton::create(HString());
 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 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}
 ~~~~~~~~~~~~~{.cpp}
 SPtr<GUIToggleGroup> group = GUIToggle::createToggleGroup();
 SPtr<GUIToggleGroup> group = GUIToggle::createToggleGroup();
@@ -208,13 +219,199 @@ toggle->onClick.connect(elementToggled);
 ![GUI toggle](guiToggle.png) 
 ![GUI toggle](guiToggle.png) 
 
 
 ## Input box
 ## 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);
+~~~~~~~~~~~~~
+
+![Input boxes](guiInputBox.png) 
 
 
 ## List box
 ## 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);
+~~~~~~~~~~~~~
+
+![List boxes](guiListBox.png) 
 
 
 ## Slider
 ## 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.
+
+![Vertical and a horizontal slider](guiSlider.png)
 
 
 ## Scroll area
 ## 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.
+
+![Scroll area](guiScrollArea.png)

+ 4 - 4
Documentation/Manuals/Native/User/inputEvents.md

@@ -22,7 +22,7 @@ auto handleButtonDown = [&](const ButtonEvent& event)
 };
 };
 
 
 // Connect the callback to the event
 // Connect the callback to the event
-gInput().onButtonDown.connect(&handleButtonDown);
+gInput().onButtonDown.connect(handleButtonDown);
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
 # Mouse/touch input
 # Mouse/touch input
@@ -46,7 +46,7 @@ auto handlePointerMove = [&](const PointerEvent& event)
 };
 };
 
 
 // Connect the callback to the event
 // Connect the callback to the event
-gInput().onPointerMoved.connect(&handlePointerMove);
+gInput().onPointerMoved.connect(handlePointerMove);
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
 Pointers may also receive specialized button down/up events, similar to *Input::onButtonDown* and *Input::onButtonUp*. They trigger at the same time, but provide *PointerEvent* structure instead of *ButtonEvent* - which may be more useful in certain situations. These methods are:
 Pointers may also receive specialized button down/up events, similar to *Input::onButtonDown* and *Input::onButtonUp*. They trigger at the same time, but provide *PointerEvent* structure instead of *ButtonEvent* - which may be more useful in certain situations. These methods are:
@@ -65,7 +65,7 @@ auto handleDoubleClick = [&](const PointerEvent& event)
 };
 };
 
 
 // Connect the callback to the event
 // Connect the callback to the event
-gInput().onPointerDoubleClick.connect(&handleDoubleClick);
+gInput().onPointerDoubleClick.connect(handleDoubleClick);
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
 # Text input
 # Text input
@@ -81,7 +81,7 @@ auto handleDoubleClick = [&](const TextInputEvent& event)
 };
 };
 
 
 // Connect the callback to the event
 // Connect the callback to the event
-gInput().onCharInput.connect(&handleCharInput);
+gInput().onCharInput.connect(handleCharInput);
 ~~~~~~~~~~~~~
 ~~~~~~~~~~~~~
 
 
 Note that the system will register keyboard buttons as both text input and as normal button presses - it's up to the caller to decide which to process when. If keyboard is used for gameplay then button presses should be used, but if user is actually typing text, then character input is better suited. This is because button events report button codes as physical keyboard keys, yet character input will actually translate those physical key presses into character codes depending on the user's keyboard settings, which ensures non-english keyboard layouts work as intended.
 Note that the system will register keyboard buttons as both text input and as normal button presses - it's up to the caller to decide which to process when. If keyboard is used for gameplay then button presses should be used, but if user is actually typing text, then character input is better suited. This is because button events report button codes as physical keyboard keys, yet character input will actually translate those physical key presses into character codes depending on the user's keyboard settings, which ensures non-english keyboard layouts work as intended.

+ 130 - 0
Documentation/Manuals/Native/User/virtualInput.md

@@ -0,0 +1,130 @@
+Virtual input						{#virtualInput}
+===============
+
+Virtual input is a high-level input system, built on top of existing **Input** functionality shown earlier. The main difference between the two systems is that virtual input abstracts the concept of buttons and axes into virtual objects, instead of referencing them directly.
+
+This allows the application to use virtual buttons and axes without needing to know actual hardware buttons/axes the user is using. This means same virtual buttons can be used for multiple input devices (e.g. keyboard & gamepad), as well as allow the user to manually re-map keys with no additional gameplay logic.
+
+All virtual input is handled through the @ref bs::VirtualInput "VirtualInput" class, accessible through @ref bs::gVirtualInput() "gVirtualInput()". You'll notice it shares a very similar interface with **Input**, with the only difference being how we represent buttons and axes.
+
+Before we explain individual aspects, lets see a quick working example to give you a rough idea:
+~~~~~~~~~~~~~{.cpp}
+// Set up input configuration that maps virtual keys to actual hardware keys
+SPtr<InputConfiguration> inputConfig = gVirtualInput().getConfiguration();
+
+//// Virtual button named "Forward" maps to W and Up arrow keys
+inputConfig->registerButton("Forward", BC_W);
+inputConfig->registerButton("Forward", BC_UP);
+
+// (Somewhere else in the app) Use the virtual key
+VirtualKey forwardKey("Forward");
+
+if(gVirtualInput().isButtonDown(forwardKey))
+	gDebug().logDebug("Moving forward...");
+~~~~~~~~~~~~~
+
+# Input configuration
+Before we can use the virtual input system, we must first create a set of virtual buttons and axes, name them, and map them to actual hardware keys. To do this we require an @ref bs::InputConfiguration "InputConfiguration" object, which can be retrieved from **VirtualInput** by calling @ref bs::VirtualInput::getConfiguration() "VirtualInput::getConfiguration()".
+
+~~~~~~~~~~~~~{.cpp}
+SPtr<InputConfiguration> inputConfig = gVirtualInput().getConfiguration();
+~~~~~~~~~~~~~
+
+# Virtual buttons
+## Registration
+Virtual buttons can be registered by giving them a unique name, and a hardware button code they map to. Any time a particular hardware button is pressed, the virtual button will be reported as pressed as well. New buttons are registered with @ref bs::InputConfiguration::registerButton() "InputConfiguration::registerButton()".
+
+~~~~~~~~~~~~~{.cpp}
+// Register a virtual button named "Forward" that maps to W and Up arrow keys
+inputConfig->registerButton("Forward", BC_W);
+inputConfig->registerButton("Forward", BC_UP);
+~~~~~~~~~~~~~
+
+You can also unregister an existing button by calling @ref bs::InputConfiguration::unregisterButton() "InputConfiguration::unregisterButton()".
+
+~~~~~~~~~~~~~{.cpp}
+inputConfig->unregisterButton("Forward");
+~~~~~~~~~~~~~
+
+These mappings can be registered/unregistered during runtime, meaning you should use this functionality to provide input remapping for your users.
+
+## Usage
+Once your virtual button has been registered you can use it by creating a @ref bs::VirtualButton "VirtualButton" object. This object expects the button name you provided when registering the button.
+
+~~~~~~~~~~~~~{.cpp}
+VirtualButton forwardKey("Forward");
+~~~~~~~~~~~~~
+
+> It is preferable you create virtual buttons during start-up and them save them for later use, instead of creating them every time you use them.
+
+Created button can be used in **VirtualInput** with following events, similar to **Input** events:
+ - @ref bs::VirtualInput::onButtonDown "VirtualInput::onButtonDown" - Triggered whenever a button has been pressed.
+ - @ref bs::VirtualInput::onButtonUp "VirtualInput::onButtonUp" - Triggered whenever a button has been released.
+ - @ref bs::VirtualInput::onButtonHeld "VirtualInput::onButtonHeld" - Triggered every frame while a button is being held.
+ 
+~~~~~~~~~~~~~{.cpp}
+Vector3 position(BsZero);
+
+// Callback method that triggers when any virtual button is being held down
+auto handleButtonHeld = [&](const VirtualButton& btn, UINT32 deviceIdx)
+{
+	// If user holds down W or Up arrow, move forward
+	if (btn == forwardKey)
+		position.z += 5.0f;
+};
+
+// Connect the callback to the event
+gVirtualInput().onButtonHeld.connect(handleButtonHeld);
+~~~~~~~~~~~~~
+
+And you can also use the following polling methods. Again, similar to **Input**:
+ - @ref bs::VirtualInput::isButtonDown "VirtualInput::isButtonDown" - Checks has the button been pressed this frame. Only valid for one frame.
+ - @ref bs::VirtualInput::isButtonHeld "VirtualInput::isButtonHeld" - Checks is the button currently being held. This is valid for the first frame the button is pressed, and for any following frame until it is released.
+ - @ref bs::VirtualInput::isButtonUp "VirtualInput::isButtonUp" - Checks has the button been released this frame. Only valid for one frame.
+
+~~~~~~~~~~~~~{.cpp}
+Vector3 position(BsZero);
+
+// Move 5 units forward for every frame while W or Up arrow is pressed
+if(gVirtualInput().isButtonHeld(forwardKey))
+	position.z += 5.0f;
+~~~~~~~~~~~~~
+
+# Virtual axes
+## Registration
+Virtual axes allow you to map hardware axes (e.g. gamepad analog stick or mouse movement) to virtual axes. They are registered similarily to buttons, though **InputConfiguration** by calling @ref bs::InputConfiguration::registerAxis "InputConfiguration::registerAxis()". 
+
+You are required to give it a unique name, and fill out @ref bs::VIRTUAL_AXIS_DESC "VIRTUAL_AXIS_DESC" structure that describes the axis. The structure allows you to choose which hardware axes to reference, as well as set other properties like sensitivity, inversion or dead zones.
+
+~~~~~~~~~~~~~{.cpp}
+// Map gamepad right stick X axis and mouse X axis to a virtual axis for looking left/right
+VIRTUAL_AXIS_DESC desc;
+desc.type = (int)InputAxis::RightStickX | (int)InputAxis::MouseX;
+
+inputConfig->registerAxis("LookLeftRight", desc);
+~~~~~~~~~~~~~
+
+> Note that unlike with buttons you shouldn't call **VirtualInput::registerAxis** multiple times for the same virtual axis. Instead provide all hardware axes in the **VIRTUAL_AXIS_DESC::type** by ORing them together.
+
+Existing virtual axes can be unmapped by calling @ref bs::InputConfiguration::unregisterAxis "InputConfiguration::unregisterAxis()".
+
+~~~~~~~~~~~~~{.cpp}
+inputConfig->unregisterAxis("LookLeftRight");
+~~~~~~~~~~~~~
+
+## Usage
+Once you wish to use the virtual axis you construct a @ref bs::VirtualAxis "VirtualAxis" object by providing it with the name of the axis.
+~~~~~~~~~~~~~{.cpp}
+VirtualAxis lookLeftRightAxis("LookLeftRight");
+~~~~~~~~~~~~~
+
+Then you can use @ref bs::VirtualInput::getAxisValue() "VirtualInput::getAxisValue()" to retrieve the current value of the axis.
+
+~~~~~~~~~~~~~{.cpp}
+// Rotate the camera left/right depending on the axis
+Degree lookAngle(0.0f);
+
+//...
+
+lookAngle += (Degree)gVirtualInput().getAxisValue(lookLeftRightAxis);
+~~~~~~~~~~~~~

+ 2 - 1
Documentation/Manuals/Native/manuals.md

@@ -29,7 +29,8 @@ Manuals									{#manuals}
  - [Lighting](@ref lights)
  - [Lighting](@ref lights)
 - **Input**
 - **Input**
  - [Input polling](@ref inputPolling) 
  - [Input polling](@ref inputPolling) 
- - [Input events](@ref inputEvents)  
+ - [Input events](@ref inputEvents) 
+ - [Virtual input](@ref virtualInput)
 - **GUI**
 - **GUI**
  - [Sprite textures](@ref spriteTextures)
  - [Sprite textures](@ref spriteTextures)
  - [Basic setup](@ref guiSetup)
  - [Basic setup](@ref guiSetup)