You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
662 lines
22 KiB
662 lines
22 KiB
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield |
|
* |
|
* This library is open source and may be redistributed and/or modified under |
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or |
|
* (at your option) any later version. The full license is in LICENSE file |
|
* included with this distribution, and on the openscenegraph.org website. |
|
* |
|
* This library is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* OpenSceneGraph Public License for more details. |
|
*/ |
|
|
|
// Code by: Jeremy Moles (cubicool) 2007-2008 |
|
|
|
#ifndef OSGWIDGET_WINDOW |
|
#define OSGWIDGET_WINDOW |
|
|
|
#include <osg/Scissor> |
|
#include <osg/MatrixTransform> |
|
#include <osg/Geode> |
|
#include <osg/ClipNode> |
|
#include <osgWidget/Types> |
|
#include <osgWidget/Util> |
|
#include <osgWidget/Widget> |
|
|
|
namespace osgWidget { |
|
|
|
// These are helper callbacks you can attach to Windows that will make them moveable, |
|
// rotatable, and scalable respectively. |
|
bool OSGWIDGET_EXPORT callbackWindowMove (Event&); |
|
bool OSGWIDGET_EXPORT callbackWindowRotate (Event&); |
|
bool OSGWIDGET_EXPORT callbackWindowScale (Event&); |
|
|
|
// These are helper callbacks you can attach to Windows to that will make various |
|
// keyboard events behave as you might imagine. |
|
bool OSGWIDGET_EXPORT callbackWindowTabFocus(Event&); |
|
|
|
class OSGWIDGET_EXPORT Window: |
|
public osg::MatrixTransform, |
|
public UIObjectParent<Widget>, |
|
public EventInterface, |
|
public StyleInterface |
|
{ |
|
public: |
|
typedef std::list<osg::observer_ptr<Window> > WindowList; |
|
|
|
struct Sizes |
|
{ |
|
point_type current; |
|
point_type minimum; |
|
|
|
Sizes(point_type c = -1.0f, point_type m = -1.0f): |
|
current(c), |
|
minimum(m) {} |
|
}; |
|
|
|
// TODO: This is a class that puts (embeds) the Window inside of a Widget |
|
// interface, to help assemble Windows with Windows, and what have you. |
|
class OSGWIDGET_EXPORT EmbeddedWindow: public Widget { |
|
osg::ref_ptr<Window> _window; |
|
|
|
public: |
|
META_Object (osgWidget::Window, EmbeddedWindow); |
|
|
|
EmbeddedWindow (const std::string& = "", point_type = 0.0f, point_type = 0.0f); |
|
EmbeddedWindow (const EmbeddedWindow&, const osg::CopyOp&); |
|
|
|
virtual void parented (Window*); |
|
virtual void unparented (Window*); |
|
virtual void managed (WindowManager*); |
|
virtual void unmanaged (WindowManager*); |
|
virtual void positioned (); |
|
|
|
bool setWindow (Window*); |
|
void updateSizeFromWindow (); |
|
|
|
Window* getWindow() { |
|
return _window.get(); |
|
} |
|
|
|
const Window* getWindow() const { |
|
return _window.get(); |
|
} |
|
}; |
|
|
|
// These correspond to special regions honored by the WindowManager. Most Windows |
|
// will want to be NONE, unless they need to exist in the foreground or background |
|
// for some reason. |
|
enum Strata { |
|
STRATA_NONE, |
|
STRATA_BACKGROUND, |
|
STRATA_FOREGROUND |
|
}; |
|
|
|
// If you only want to display a portion of a Window (such as when it is embedded), |
|
// you will need to set the VisibilityMode to WM_PARTIAL. Otherwise, the entire |
|
// Window is visible by default. The final enum, VM_ENTIRE, says that no Scissoring |
|
// should take place at all, and is useful in cases where you want to properly |
|
// scale or rotate Windows. |
|
enum VisibilityMode { |
|
VM_FULL, |
|
VM_PARTIAL, |
|
VM_ENTIRE |
|
}; |
|
|
|
// Anchors are very similar in that they allow us to pre-apply transformations in the |
|
// call to Window::update() that allow us to position a Window somewhere relative |
|
// to the WindowManger's viewable area. However, unlike the ALIGNMENT enums, these |
|
// are totally optional (whereas a Widget must always have some ALIGNMENT value set. |
|
enum VerticalAnchor { |
|
VA_NONE, |
|
VA_CENTER, |
|
VA_TOP, |
|
VA_BOTTOM |
|
}; |
|
|
|
enum HorizontalAnchor { |
|
HA_NONE, |
|
HA_CENTER, |
|
HA_LEFT, |
|
HA_RIGHT |
|
}; |
|
|
|
Window (const std::string& = ""); |
|
Window (const Window&, const osg::CopyOp&); |
|
|
|
bool resize (point_type = 0.0f, point_type = 0.0f); |
|
bool resizeAdd (point_type = 0.0f, point_type = 0.0f); |
|
bool resizePercent (point_type = 0.0f, point_type = 0.0f); |
|
|
|
virtual void update (); |
|
virtual void managed (WindowManager*); |
|
virtual void unmanaged (WindowManager*); |
|
virtual bool addWidget (Widget*); |
|
virtual bool insertWidget (Widget*, unsigned int); |
|
virtual bool removeWidget (Widget*); |
|
virtual bool replaceWidget (Widget*, Widget*); |
|
|
|
// This method wraps our Geode's addDrawable() method and returns the index of |
|
// the newly-added Drawable. |
|
unsigned int addDrawableAndGetIndex (osg::Drawable*); |
|
unsigned int addChildAndGetIndex (osg::Node*); |
|
|
|
bool isVisible () const; |
|
bool isXYWithinVisible (float, float) const; |
|
void setVisibleArea (int = 0, int = 0, int = 0, int = 0); |
|
void addVisibleArea (int = 0, int = 0, int = 0, int = 0); |
|
bool setFocused (const Widget*); |
|
bool setFocused (const std::string&); |
|
bool grabFocus (); |
|
bool setFirstFocusable (); |
|
bool setNextFocusable (); |
|
bool getFocusList (WidgetList&) const; |
|
bool getEmbeddedList (WindowList&) const; |
|
void getParentList (WindowList&) const; |
|
|
|
XYCoord localXY (double, double) const; |
|
XYCoord getAbsoluteOrigin () const; |
|
|
|
// This method wraps the current Window in a EmbeddedWindow object and returns it. |
|
EmbeddedWindow* embed( |
|
const std::string& = "", |
|
Widget::Layer = Widget::LAYER_MIDDLE, |
|
unsigned int = 0 |
|
); |
|
|
|
Widget* getFocused() { |
|
return _focused.get(); |
|
} |
|
|
|
const Widget* getFocused() const { |
|
return _focused.get(); |
|
} |
|
|
|
bool show() { |
|
return _setVisible(true); |
|
} |
|
|
|
bool hide() { |
|
return _setVisible(false); |
|
} |
|
|
|
bool isPointerXYWithinVisible(float x, float y) const { |
|
XYCoord xy = localXY(x, y); |
|
|
|
return isXYWithinVisible(xy.x(), xy.y()); |
|
} |
|
|
|
osg::Geode* getGeode() { |
|
return _geode(); |
|
} |
|
|
|
const osg::Geode* getGeode() const { |
|
return _geode(); |
|
} |
|
|
|
Widget* getBackground() { |
|
return _bg(); |
|
} |
|
|
|
const Widget* getBackground() const { |
|
return _bg(); |
|
} |
|
|
|
WindowManager* getWindowManager() { |
|
return _wm; |
|
} |
|
|
|
const WindowManager* getWindowManager() const { |
|
return _wm; |
|
} |
|
|
|
Window* getParent() { |
|
return _parent; |
|
} |
|
|
|
const Window* getParent() const { |
|
return _parent; |
|
} |
|
|
|
Window* getTopmostParent() { |
|
return _getTopmostParent(); |
|
} |
|
|
|
const Window* getTopmostParent() const { |
|
return _getTopmostParent(); |
|
} |
|
|
|
unsigned int getIndex() const { |
|
return _index; |
|
} |
|
|
|
matrix_type getX() const { |
|
return _x; |
|
} |
|
|
|
matrix_type getY() const { |
|
return _y; |
|
} |
|
|
|
matrix_type getZ() const { |
|
return _z; |
|
} |
|
|
|
point_type getWidth() const { |
|
return _width.current; |
|
} |
|
|
|
point_type getHeight() const { |
|
return _height.current; |
|
} |
|
|
|
point_type getMinWidth() const { |
|
return _width.minimum; |
|
} |
|
|
|
point_type getMinHeight() const { |
|
return _height.minimum; |
|
} |
|
|
|
VerticalAnchor getAnchorVertical() const { |
|
return _vAnchor; |
|
} |
|
|
|
HorizontalAnchor getAnchorHorizontal() const { |
|
return _hAnchor; |
|
} |
|
|
|
XYCoord getOrigin() const { |
|
return XYCoord(_x, _y); |
|
} |
|
|
|
XYCoord getSize() const { |
|
return XYCoord(_width.current, _height.current); |
|
} |
|
|
|
XYCoord getMinSize() const { |
|
return XYCoord(_width.minimum, _height.minimum); |
|
} |
|
|
|
matrix_type getZRange() const { |
|
return _zRange; |
|
} |
|
|
|
Strata getStrata() const { |
|
return _strata; |
|
} |
|
|
|
const Quad& getVisibleArea() const { |
|
return _visibleArea; |
|
} |
|
|
|
VisibilityMode getVisibilityMode() const { |
|
return _vis; |
|
} |
|
|
|
Point getPosition() const { |
|
return Point(_x, _y, _z); |
|
} |
|
|
|
matrix_type getRotate() const { |
|
return _r; |
|
} |
|
|
|
matrix_type getScale() const { |
|
return _s; |
|
} |
|
|
|
matrix_type getScaleDenominator() const { |
|
return _scaleDenom; |
|
} |
|
|
|
void setX(matrix_type x) { |
|
_x = x; |
|
} |
|
|
|
void setY(matrix_type y) { |
|
_y = y; |
|
} |
|
|
|
void setZ(matrix_type z) { |
|
_z = z; |
|
} |
|
|
|
void setZRange(matrix_type zRange) { |
|
_zRange = zRange; |
|
} |
|
|
|
void setPosition(matrix_type x, matrix_type y, matrix_type z) { |
|
_x = x; |
|
_y = y; |
|
_z = z; |
|
} |
|
|
|
void setPosition(const Point& p) { |
|
setPosition(p.x(), p.y(), p.z()); |
|
} |
|
|
|
void setOrigin(matrix_type x, matrix_type y) { |
|
_x = x; |
|
_y = y; |
|
} |
|
|
|
void setOrigin(const XYCoord& xy) { |
|
setOrigin(xy.x(), xy.y()); |
|
} |
|
|
|
void setRotate(matrix_type r) { |
|
_r = r; |
|
} |
|
|
|
void setScale(matrix_type s) { |
|
_s = s; |
|
} |
|
|
|
void setScaleDenominator(matrix_type sd) { |
|
_scaleDenom = sd; |
|
} |
|
|
|
void setAnchorVertical(VerticalAnchor va) { |
|
_vAnchor = va; |
|
} |
|
|
|
void setAnchorHorizontal(HorizontalAnchor ha) { |
|
_hAnchor = ha; |
|
} |
|
|
|
void setStrata(Strata s) { |
|
_strata = s; |
|
} |
|
|
|
void setVisibilityMode(VisibilityMode v) { |
|
_vis = v; |
|
} |
|
|
|
void addX(matrix_type x) { |
|
_x += x; |
|
} |
|
|
|
void addY(matrix_type y) { |
|
_y += y; |
|
} |
|
|
|
void addZ(matrix_type z) { |
|
_z += z; |
|
} |
|
|
|
void addRotate(matrix_type r) { |
|
_r += r; |
|
} |
|
|
|
void addScale(matrix_type s) { |
|
_s += s / (_scaleDenom != 0.0f ? _scaleDenom : 1.0f); |
|
} |
|
|
|
void addOrigin(matrix_type x, matrix_type y) { |
|
_x += x; |
|
_y += y; |
|
} |
|
|
|
void attachMoveCallback() { |
|
addCallback(new Callback(&callbackWindowMove, EVENT_MOUSE_DRAG)); |
|
} |
|
|
|
void attachRotateCallback() { |
|
addCallback(new Callback(&callbackWindowRotate, EVENT_MOUSE_DRAG)); |
|
} |
|
|
|
void attachScaleCallback() { |
|
addCallback(new Callback(&callbackWindowScale, EVENT_MOUSE_DRAG)); |
|
} |
|
|
|
void attachTabFocusCallback() { |
|
addCallback(new Callback(&callbackWindowTabFocus, EVENT_KEY_DOWN)); |
|
} |
|
|
|
typedef point_type (Widget::*Getter)() const; |
|
|
|
protected: |
|
|
|
typedef std::less<point_type> Less; |
|
typedef std::greater<point_type> Greater; |
|
typedef std::plus<point_type> Plus; |
|
|
|
friend class WindowManager; |
|
|
|
// The (optional) Window that this Window is parented inside. |
|
Window* _parent; |
|
|
|
// The WindowManger to which this window is attached. |
|
WindowManager* _wm; |
|
|
|
// The positional index this Node holds within it's parent WindowManager. |
|
unsigned int _index; |
|
|
|
// The X and Y values of the Window (origin). |
|
matrix_type _x; |
|
matrix_type _y; |
|
|
|
// A pair of values representing the currently calculated Z value and the |
|
// depth range for all children to be used during the call to update(). |
|
matrix_type _z; |
|
matrix_type _zRange; |
|
|
|
// This is a special value that can be used to "force" a Window not to be |
|
// focusable and instead always exist in the foreground or background. |
|
Strata _strata; |
|
|
|
// A flag determining whether our visible area is the full Window or rather |
|
// a portion of the Window. |
|
VisibilityMode _vis; |
|
|
|
// A rotation value in degrees. |
|
matrix_type _r; |
|
|
|
// This will also need to adjust geom internally so that picking is correct. |
|
matrix_type _s; |
|
|
|
matrix_type _scaleDenom; |
|
|
|
Sizes _width; |
|
Sizes _height; |
|
|
|
VerticalAnchor _vAnchor; |
|
HorizontalAnchor _hAnchor; |
|
|
|
// Not all windows have widgets that can focus, but if they do this should |
|
// be a pointer to it. |
|
osg::observer_ptr<Widget> _focused; |
|
|
|
// The "visible" area that will define both the glScissor bounds AND will |
|
// be used to make sure our pick is valid. The values herein correspond to |
|
// X, Y, W, and H--in that order. |
|
Quad _visibleArea; |
|
|
|
// This helper method is used by _compare<>() and _accumulate<>(), so ignore this |
|
// function and go see the docs for those instead. This thing is huge and unwieldy |
|
// and not to be triffled with! :) |
|
template<typename T> |
|
point_type _forEachAssignOrApply( |
|
Getter get, |
|
int begin, |
|
int end, |
|
int add, |
|
bool assign |
|
) const { |
|
point_type val = 0.0f; |
|
unsigned int c = begin; |
|
|
|
ConstIterator e = end > 0 ? _objects.begin() + end : _objects.end() + end; |
|
|
|
// I WARNED YOU! If you try and understand what this does your head will |
|
// explode! But let me say a few things: in MSVC you can't add to an iterator |
|
// such that the add will cause it to increment past the end of the container. |
|
// This appears to be safe in GCC, where it will just return the last |
|
// item therein, but causes an assertion error in other compilers. I'm not |
|
// sure if there is a cleaner remedy for this, so what we do for now is keep a |
|
// count variable called "c" that makes sure our iterator's opterator+() |
|
// method is safe to call. |
|
for( |
|
ConstIterator i = _objects.begin() + begin; |
|
i < e; |
|
c += add |
|
) { |
|
point_type v = 0.0f; |
|
|
|
if(i->valid()) v = (i->get()->*get)(); |
|
|
|
// If you want to assign to val, and NOT add a sequence of them... |
|
if(assign) { |
|
if(T()(v, val)) val = v; |
|
} |
|
|
|
// If you want to accumulate a value INTO val... |
|
else val = T()(v, val); |
|
|
|
// Make sure our iterator is safe to increment. Otherwise, set it to |
|
// whatever end is. |
|
// TODO: This isn't 100% accurate, as it does not YET take into account |
|
// our requested end in any way other than implicitly. It should, however, |
|
// work okay for now. |
|
if((c + add) < _objects.size()) i += add; |
|
|
|
else i = e; |
|
} |
|
|
|
return val; |
|
} |
|
|
|
void _setWidthAndHeightUnknownSizeError (const std::string&, point_type); |
|
void _setWidthAndHeightNotPAError (const std::string&, point_type); |
|
void _setWidthAndHeight (); |
|
void _removeFromGeode (Widget*); |
|
|
|
Widget* _getBackground() const; |
|
Window* _getTopmostParent() const; |
|
|
|
// This method will return the T'th value returned by applying the Getter member function |
|
// pointer to each iterator in the range of iterators defined by offset and add. In |
|
// plain language, this helper method will apply some standard Widget::get* function |
|
// to a range of objects in the _objects Vector, and will return the T'th of that. |
|
// The template T can be any functor accepting two point_type values that return |
|
// a bool. For example, this is commonly used with std::less to find the smallest |
|
// width in a range of Widgets. |
|
template<typename T> |
|
point_type _compare( |
|
Getter get, |
|
int begin = 0, |
|
int end = 0, |
|
int add = 1 |
|
) const { |
|
return _forEachAssignOrApply<T>(get, begin, end, add, true); |
|
} |
|
|
|
// This method will return the T'th value accumulated by applying the Getter member |
|
// function to each iterator in the range of iterators defined by offset and add (similar |
|
// to above). For example, this method can be used to apply std::plus to every |
|
// width in a range of Widgets, and return the total. |
|
template<typename T> |
|
point_type _accumulate( |
|
Getter get, |
|
int begin = 0, |
|
int end = 0, |
|
int add = 1 |
|
) const { |
|
return _forEachAssignOrApply<T>(get, begin, end, add, false); |
|
} |
|
|
|
osg::Geode* _geode() { |
|
return dynamic_cast<osg::Geode*>(getChild(0)); |
|
} |
|
|
|
const osg::Geode* _geode() const { |
|
return dynamic_cast<const osg::Geode*>(getChild(0)); |
|
} |
|
|
|
Widget* _bg() { |
|
return _getBackground(); |
|
} |
|
|
|
const Widget* _bg() const { |
|
return _getBackground(); |
|
} |
|
|
|
osg::Scissor* _scissor() { |
|
return dynamic_cast<osg::Scissor*>( |
|
getStateSet()->getAttribute(osg::StateAttribute::SCISSOR) |
|
); |
|
} |
|
|
|
bool _setWidget (Widget*, int = -1); |
|
bool _setVisible (bool); |
|
void _setFocused (Widget*); |
|
void _setStyled (Widget*); |
|
void _setParented (Widget*, bool=false); |
|
void _setManaged (Widget*, bool=false); |
|
|
|
void _positionWidget(Widget*, point_type, point_type); |
|
|
|
// These return the smallest and largest width and height values for the given |
|
// range of Widgets. |
|
point_type _getMinWidgetWidth (int = 0, int = 0, int = 1) const; |
|
point_type _getMinWidgetHeight (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetWidth (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetHeight (int = 0, int = 0, int = 1) const; |
|
|
|
// These return the smallest and largest minWidth and minHeight values for |
|
// the given range of Widgets. |
|
point_type _getMinWidgetMinWidth (int = 0, int = 0, int = 1) const; |
|
point_type _getMinWidgetMinHeight (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetMinWidth (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetMinHeight (int = 0, int = 0, int = 1) const; |
|
|
|
// These return the smallest and largest width and height total (width + pad) |
|
// values for the given range of Widgets. |
|
point_type _getMinWidgetWidthTotal (int = 0, int = 0, int = 1) const; |
|
point_type _getMinWidgetHeightTotal (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetWidthTotal (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetHeightTotal (int = 0, int = 0, int = 1) const; |
|
|
|
// These return the smallest and largest minWidth and minHeight total |
|
// (width + pad) values for the given range of Widgets. |
|
point_type _getMinWidgetMinWidthTotal (int = 0, int = 0, int = 1) const; |
|
point_type _getMinWidgetMinHeightTotal (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetMinWidthTotal (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetMinHeightTotal (int = 0, int = 0, int = 1) const; |
|
|
|
// These return the smallest and largest horizontal and vertical padding |
|
// values for the given range of Widgets. |
|
point_type _getMinWidgetPadHorizontal (int = 0, int = 0, int = 1) const; |
|
point_type _getMinWidgetPadVertical (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetPadHorizontal (int = 0, int = 0, int = 1) const; |
|
point_type _getMaxWidgetPadVertical (int = 0, int = 0, int = 1) const; |
|
|
|
point_type _getNumFill(int = 0, int = 0, int = 1) const; |
|
|
|
// This method is passed the additional values by which width and height should be |
|
// modified as calculed by the parent method, Window::resize. Keep in mind that these |
|
// values can be negative (indicating a potential "shrink" request) or positive (which |
|
// would indicate a "grow" reqeust). |
|
virtual void _resizeImplementation(point_type, point_type) = 0; |
|
|
|
// These are made into implementation functions since getting the width or height |
|
// of a window can potentially be an expensive operation, and we'll want to cache |
|
// results if possible (which is handled transparently by the actualy Window::resize |
|
// method). They return a Sizes struct which contains two members: cur (for current) |
|
// and min (minimum). It's important that the Window know it's minimum possible |
|
// size so that it can ignore invaled requests to resize. |
|
// |
|
// Default versions using BoundingBox calculations are provided, but some Windows |
|
// override this (Table, Box). |
|
virtual Sizes _getWidthImplementation () const; |
|
virtual Sizes _getHeightImplementation () const; |
|
|
|
}; |
|
|
|
typedef Window::WindowList WindowList; |
|
|
|
} |
|
|
|
#endif
|
|
|