reactphysics3d/testbed/nanogui/include/nanogui/widget.h

343 lines
13 KiB
C++

/*
nanogui/widget.h -- Base class of all widgets
NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>.
The widget drawing code is based on the NanoVG demo application
by Mikko Mononen.
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE.txt file.
*/
/** \file */
#pragma once
#include <nanogui/object.h>
#include <nanogui/theme.h>
#include <vector>
NAMESPACE_BEGIN(nanogui)
enum class Cursor;// do not put a docstring, this is already documented
/**
* \class Widget widget.h nanogui/widget.h
*
* \brief Base class of all widgets.
*
* \ref Widget is the base class of all widgets in \c nanogui. It can
* also be used as an panel to arrange an arbitrary number of child
* widgets using a layout generator (see \ref Layout).
*/
class NANOGUI_EXPORT Widget : public Object {
public:
/// Construct a new widget with the given parent widget
Widget(Widget *parent);
/// Return the parent widget
Widget *parent() { return mParent; }
/// Return the parent widget
const Widget *parent() const { return mParent; }
/// Set the parent widget
void setParent(Widget *parent) { mParent = parent; }
/// Return the used \ref Layout generator
Layout *layout() { return mLayout; }
/// Return the used \ref Layout generator
const Layout *layout() const { return mLayout.get(); }
/// Set the used \ref Layout generator
void setLayout(Layout *layout) { mLayout = layout; }
/// Return the \ref Theme used to draw this widget
Theme *theme() { return mTheme; }
/// Return the \ref Theme used to draw this widget
const Theme *theme() const { return mTheme.get(); }
/// Set the \ref Theme used to draw this widget
virtual void setTheme(Theme *theme);
/// Return the position relative to the parent widget
const Vector2i &position() const { return mPos; }
/// Set the position relative to the parent widget
void setPosition(const Vector2i &pos) { mPos = pos; }
/// Return the absolute position on screen
Vector2i absolutePosition() const {
return mParent ?
(parent()->absolutePosition() + mPos) : mPos;
}
/// Return the size of the widget
const Vector2i &size() const { return mSize; }
/// set the size of the widget
void setSize(const Vector2i &size) { mSize = size; }
/// Return the width of the widget
int width() const { return mSize.x(); }
/// Set the width of the widget
void setWidth(int width) { mSize.x() = width; }
/// Return the height of the widget
int height() const { return mSize.y(); }
/// Set the height of the widget
void setHeight(int height) { mSize.y() = height; }
/**
* \brief Set the fixed size of this widget
*
* If nonzero, components of the fixed size attribute override any values
* computed by a layout generator associated with this widget. Note that
* just setting the fixed size alone is not enough to actually change its
* size; this is done with a call to \ref setSize or a call to \ref performLayout()
* in the parent widget.
*/
void setFixedSize(const Vector2i &fixedSize) { mFixedSize = fixedSize; }
/// Return the fixed size (see \ref setFixedSize())
const Vector2i &fixedSize() const { return mFixedSize; }
// Return the fixed width (see \ref setFixedSize())
int fixedWidth() const { return mFixedSize.x(); }
// Return the fixed height (see \ref setFixedSize())
int fixedHeight() const { return mFixedSize.y(); }
/// Set the fixed width (see \ref setFixedSize())
void setFixedWidth(int width) { mFixedSize.x() = width; }
/// Set the fixed height (see \ref setFixedSize())
void setFixedHeight(int height) { mFixedSize.y() = height; }
/// Return whether or not the widget is currently visible (assuming all parents are visible)
bool visible() const { return mVisible; }
/// Set whether or not the widget is currently visible (assuming all parents are visible)
void setVisible(bool visible) { mVisible = visible; }
/// Check if this widget is currently visible, taking parent widgets into account
bool visibleRecursive() const {
bool visible = true;
const Widget *widget = this;
while (widget) {
visible &= widget->visible();
widget = widget->parent();
}
return visible;
}
/// Return the number of child widgets
int childCount() const { return (int) mChildren.size(); }
/// Return the list of child widgets of the current widget
const std::vector<Widget *> &children() const { return mChildren; }
/**
* \brief Add a child widget to the current widget at
* the specified index.
*
* This function almost never needs to be called by hand,
* since the constructor of \ref Widget automatically
* adds the current widget to its parent
*/
virtual void addChild(int index, Widget *widget);
/// Convenience function which appends a widget at the end
void addChild(Widget *widget);
/// Remove a child widget by index
void removeChild(int index);
/// Remove a child widget by value
void removeChild(const Widget *widget);
/// Retrieves the child at the specific position
const Widget* childAt(int index) const { return mChildren[index]; }
/// Retrieves the child at the specific position
Widget* childAt(int index) { return mChildren[index]; }
/// Returns the index of a specific child or -1 if not found
int childIndex(Widget* widget) const;
/// Variadic shorthand notation to construct and add a child widget
template<typename WidgetClass, typename... Args>
WidgetClass* add(const Args&... args) {
return new WidgetClass(this, args...);
}
/// Walk up the hierarchy and return the parent window
Window *window();
/// Walk up the hierarchy and return the parent screen
Screen *screen();
/// Associate this widget with an ID value (optional)
void setId(const std::string &id) { mId = id; }
/// Return the ID value associated with this widget, if any
const std::string &id() const { return mId; }
/// Return whether or not this widget is currently enabled
bool enabled() const { return mEnabled; }
/// Set whether or not this widget is currently enabled
void setEnabled(bool enabled) { mEnabled = enabled; }
/// Return whether or not this widget is currently focused
bool focused() const { return mFocused; }
/// Set whether or not this widget is currently focused
void setFocused(bool focused) { mFocused = focused; }
/// Request the focus to be moved to this widget
void requestFocus();
const std::string &tooltip() const { return mTooltip; }
void setTooltip(const std::string &tooltip) { mTooltip = tooltip; }
/// Return current font size. If not set the default of the current theme will be returned
int fontSize() const;
/// Set the font size of this widget
void setFontSize(int fontSize) { mFontSize = fontSize; }
/// Return whether the font size is explicitly specified for this widget
bool hasFontSize() const { return mFontSize > 0; }
/**
* The amount of extra scaling applied to *icon* fonts.
* See \ref nanogui::Widget::mIconExtraScale.
*/
float iconExtraScale() const { return mIconExtraScale; }
/**
* Sets the amount of extra scaling applied to *icon* fonts.
* See \ref nanogui::Widget::mIconExtraScale.
*/
void setIconExtraScale(float scale) { mIconExtraScale = scale; }
/// Return a pointer to the cursor of the widget
Cursor cursor() const { return mCursor; }
/// Set the cursor of the widget
void setCursor(Cursor cursor) { mCursor = cursor; }
/// Check if the widget contains a certain position
bool contains(const Vector2i &p) const {
auto d = (p-mPos).array();
return (d >= 0).all() && (d < mSize.array()).all();
}
/// Determine the widget located at the given position value (recursive)
Widget *findWidget(const Vector2i &p);
/// Handle a mouse button event (default implementation: propagate to children)
virtual bool mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers);
/// Handle a mouse motion event (default implementation: propagate to children)
virtual bool mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers);
/// Handle a mouse drag event (default implementation: do nothing)
virtual bool mouseDragEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers);
/// Handle a mouse enter/leave event (default implementation: record this fact, but do nothing)
virtual bool mouseEnterEvent(const Vector2i &p, bool enter);
/// Handle a mouse scroll event (default implementation: propagate to children)
virtual bool scrollEvent(const Vector2i &p, const Vector2f &rel);
/// Handle a focus change event (default implementation: record the focus status, but do nothing)
virtual bool focusEvent(bool focused);
/// Handle a keyboard event (default implementation: do nothing)
virtual bool keyboardEvent(int key, int scancode, int action, int modifiers);
/// Handle text input (UTF-32 format) (default implementation: do nothing)
virtual bool keyboardCharacterEvent(unsigned int codepoint);
/// Compute the preferred size of the widget
virtual Vector2i preferredSize(NVGcontext *ctx) const;
/// Invoke the associated layout generator to properly place child widgets, if any
virtual void performLayout(NVGcontext *ctx);
/// Draw the widget (and all child widgets)
virtual void draw(NVGcontext *ctx);
/// Save the state of the widget into the given \ref Serializer instance
virtual void save(Serializer &s) const;
/// Restore the state of the widget from the given \ref Serializer instance
virtual bool load(Serializer &s);
protected:
/// Free all resources used by the widget and any children
virtual ~Widget();
/**
* Convenience definition for subclasses to get the full icon scale for this
* class of Widget. It simple returns the value
* ``mTheme->mIconScale * this->mIconExtraScale``.
*
* \remark
* See also: \ref nanogui::Theme::mIconScale and
* \ref nanogui::Widget::mIconExtraScale. This tiered scaling
* strategy may not be appropriate with fonts other than ``entypo.ttf``.
*/
inline float icon_scale() const { return mTheme->mIconScale * mIconExtraScale; }
protected:
Widget *mParent;
ref<Theme> mTheme;
ref<Layout> mLayout;
std::string mId;
Vector2i mPos, mSize, mFixedSize;
std::vector<Widget *> mChildren;
/**
* Whether or not this Widget is currently visible. When a Widget is not
* currently visible, no time is wasted executing its drawing method.
*/
bool mVisible;
/**
* Whether or not this Widget is currently enabled. Various different kinds
* of derived types use this to determine whether or not user input will be
* accepted. For example, when ``mEnabled == false``, the state of a
* CheckBox cannot be changed, or a TextBox will not allow new input.
*/
bool mEnabled;
bool mFocused, mMouseFocus;
std::string mTooltip;
int mFontSize;
/**
* \brief The amount of extra icon scaling used in addition the the theme's
* default icon font scale. Default value is ``1.0``, which implies
* that \ref nanogui::Widget::icon_scale simply returns the value
* of \ref nanogui::Theme::mIconScale.
*
* Most widgets do not need extra scaling, but some (e.g., CheckBox, TextBox)
* need to adjust the Theme's default icon scaling
* (\ref nanogui::Theme::mIconScale) to properly display icons within their
* bounds (upscale, or downscale).
*
* \rst
* .. note::
*
* When using ``nvgFontSize`` for icons in subclasses, make sure to call
* the :func:`nanogui::Widget::icon_scale` function. Expected usage when
* *drawing* icon fonts is something like:
*
* .. code-block:: cpp
*
* virtual void draw(NVGcontext *ctx) {
* // fontSize depends on the kind of Widget. Search for `FontSize`
* // in the Theme class (e.g., standard vs button)
* float ih = fontSize;
* // assuming your Widget has a declared `mIcon`
* if (nvgIsFontIcon(mIcon)) {
* ih *= icon_scale();
* nvgFontFace(ctx, "icons");
* nvgFontSize(ctx, ih);
* /// remaining drawing code (see button.cpp for more)
* }
* }
* \endrst
*/
float mIconExtraScale;
Cursor mCursor;
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
NAMESPACE_END(nanogui)