TGUI/include/TGUI/Layout.hpp

442 lines
23 KiB
C++

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus' Graphical User Interface
// Copyright (C) 2012-2018 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef TGUI_LAYOUT_HPP
#define TGUI_LAYOUT_HPP
#include <TGUI/Config.hpp>
#include <TGUI/Vector2f.hpp>
#include <type_traits>
#include <functional>
#include <memory>
#include <string>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace tgui
{
class Gui;
class Widget;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Class to store the left, top, width or height of a widget
///
/// You don't have to create an instance of this class, numbers are implicitly cast to this class.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class TGUI_API Layout
{
public:
/// The operation which the layout has to perform to find its value
enum class Operation
{
Value,
Plus,
Minus,
Multiplies,
Divides,
BindingLeft,
BindingTop,
BindingWidth,
BindingHeight,
BindingString
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Default constructor
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout() = default;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Constructor to implicitly construct from numeric constant
///
/// @param constant Value of the layout
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
Layout(T constant) :
m_value{static_cast<float>(constant)}
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Constructs the layout based on a string which will be parsed to determine the value of the layout
///
/// @param expression String to parse
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout(const char* expression) :
Layout{std::string{expression}}
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Constructs the layout based on a string which will be parsed to determine the value of the layout
///
/// @param expression String to parse
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout(std::string expression);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/// @brief Constructs a layout with a binding to a widget
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
explicit Layout(Operation operation, Widget* boundWidget);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/// @brief Constructs the layout with a mathematical operation between two other layouts
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
explicit Layout(Operation operation, std::unique_ptr<Layout> leftOperand, std::unique_ptr<Layout> rightOperand);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Copy constructor
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout(const Layout& other);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Move constructor
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout(Layout&& other);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Copy assignment operator
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout& operator=(const Layout& other);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Move assignment operator
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout& operator=(Layout&& other);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Destructor
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
~Layout();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Return the cached value of the layout
///
/// @return Value of the layout
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float getValue() const
{
return m_value;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/// @brief Converts the layout to a string representation
///
/// @return String representation of layout
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string toString() const;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/// @brief Provides the layout access to the widget (and its parent) which allows searching potentially referred widgets
/// and sets a callback function so that the widget can be alerted when the value of the widget changes.
///
/// The xAxis parameter tells the layout whether it contains the left/width or top/height value.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void connectWidget(Widget* widget, bool xAxis, std::function<void()> valueChangedCallbackHandler);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/// @brief If the layout has bound a widget and the widget gets destroyed, this function is called
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void unbindWidget();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/// @brief Recalculate the value of the layout based on the operation it contains and tell the parent layout to
/// do the same when the value of the layout has changed.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void recalculateValue();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// If a widget is bound, inform it that the layout no longer binds it
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void unbindLayout();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Resets the parent pointers of the left and right operands if they exist and tell the bound widget that this layout
// requires information about changes to its position or size when the operation requires a widget to be bound.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void resetPointers();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check whether sublayouts contain a string that refers to a widget which should be bound.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void parseBindingStringRecursive(Widget* widget, bool xAxis);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Find the widget corresponding to the given name and bind it if found
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void parseBindingString(const std::string& expression, Widget* widget, bool xAxis);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private:
float m_value = 0;
Layout* m_parent = nullptr;
Operation m_operation = Operation::Value;
std::unique_ptr<Layout> m_leftOperand = nullptr; // The left operand of the operation in case the operation is a math operation
std::unique_ptr<Layout> m_rightOperand = nullptr; // The left operand of the operation in case the operation is a math operation
Widget* m_boundWidget = nullptr; // The widget on which this layout depends in case the operation is a binding
std::string m_boundString; // String referring to a widget on which this layout depends in case the layout was created from a string and contains a binding operation
std::function<void()> m_connectedWidgetCallback = nullptr; // Function to call when the value of the layout changes in case the layout and sublayouts are not all constants
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Class to store the position or size of a widget
///
/// You don't have to explicitly create an instance of this class, sf::Vector2f and tgui::Vector2f are implicitly converted.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class TGUI_API Layout2d
{
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Default constructor to implicitly construct from a tgui::Vector2f.
///
/// @param constant Value of the layout
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout2d(Vector2f constant = {0, 0}) :
x{constant.x},
y{constant.y}
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Default constructor to implicitly construct from a sf::Vector2f.
///
/// @param constant Value of the layout
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout2d(sf::Vector2f constant) :
x{constant.x},
y{constant.y}
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Constructor to create the Layout2d from two Layout classes
///
/// @param layoutX x component
/// @param layoutY y component
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout2d(Layout layoutX, Layout layoutY) :
x{std::move(layoutX)},
y{std::move(layoutY)}
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Constructs the Layout2d based on a string which will be parsed to determine the value of the layouts
///
/// @param expression String to parse
///
/// The expression will be passed to both the x and y layouts.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout2d(const char* expression) :
x{expression},
y{expression}
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Constructs the Layout2d based on a string which will be parsed to determine the value of the layouts
///
/// @param expression String to parse
///
/// The expression will be passed to both the x and y layouts.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Layout2d(const std::string& expression) :
x{expression},
y{expression}
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Returns the cached value of the layout
///
/// @return Value of the layout
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Vector2f getValue() const
{
return {x.getValue(), y.getValue()};
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @internal
/// @brief Converts the layout to a string representation
///
/// @return String representation of layout
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::string toString() const
{
return "(" + x.toString() + ", " + y.toString() + ")";
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public:
Layout x;
Layout y;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Unary minus operator for the Layout class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout operator-(Layout right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief + operator for the Layout class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout operator+(Layout left, Layout right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief - operator for the Layout class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout operator-(Layout left, Layout right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief * operator for the Layout class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout operator*(Layout left, Layout right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief / operator for the Layout class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout operator/(Layout left, Layout right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Unary minus operator for the Layout2d class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout2d operator-(Layout2d right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief + operator for the Layout2d class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout2d operator+(Layout2d left, Layout2d right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief - operator for the Layout2d class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout2d operator-(Layout2d left, Layout2d right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief * operator for the Layout2d class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout2d operator*(Layout2d left, const Layout& right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief * operator for the Layout2d class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout2d operator*(const Layout& left, Layout2d right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief / operator for the Layout2d class
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TGUI_API Layout2d operator/(Layout2d left, const Layout& right);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline namespace bind_functions
{
/// @brief Bind to the x position of the widget
TGUI_API Layout bindLeft(std::shared_ptr<Widget> widget);
/// @brief Bind to the y position of the widget
TGUI_API Layout bindTop(std::shared_ptr<Widget> widget);
/// @brief Bind to the width of the widget
TGUI_API Layout bindWidth(std::shared_ptr<Widget> widget);
/// @brief Bind to the height of the widget
TGUI_API Layout bindHeight(std::shared_ptr<Widget> widget);
/// @brief Bind to the right position of the widget
TGUI_API Layout bindRight(std::shared_ptr<Widget> widget);
/// @brief Bind to the bottom of the widget
TGUI_API Layout bindBottom(std::shared_ptr<Widget> widget);
/// @brief Bind to the position of the widget
TGUI_API Layout2d bindPosition(std::shared_ptr<Widget> widget);
/// @brief Bind to the size of the widget
TGUI_API Layout2d bindSize(std::shared_ptr<Widget> widget);
/// @brief Bind to the width of the gui view
TGUI_API Layout bindWidth(Gui& gui);
/// @brief Bind to the height of the gui view
TGUI_API Layout bindHeight(Gui& gui);
/// @brief Bind to the size of the gui view
TGUI_API Layout2d bindSize(Gui& gui);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif // TGUI_LAYOUT_HPP