/* -*-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_WIDGET #define OSGWIDGET_WIDGET #include #include #include #include #include namespace osgWidget { class Window; class WindowManager; // A Widget is a rectangular region that receives events about the state of various input // devices such as the pointer and keyboard. It is aware of it's width, height, and origin but // nothing else. It is the job of higher-level container objects to organize layouts and // the like, and to contextualize the meaning of the widgets "origin" (whether it is absolute // or relative). class OSGWIDGET_EXPORT Widget: public osg::Geometry, public EventInterface, public StyleInterface { public: enum Corner { LOWER_LEFT = 0, LOWER_RIGHT = 1, UPPER_RIGHT = 2, UPPER_LEFT = 3, LL = LOWER_LEFT, LR = LOWER_RIGHT, UR = UPPER_RIGHT, UL = UPPER_LEFT, ALL_CORNERS = 4 }; enum Layer { LAYER_TOP = 100, LAYER_HIGH = 75, LAYER_MIDDLE = 50, LAYER_LOW = 25, LAYER_BG = 0 }; enum VerticalAlignment { VA_CENTER, VA_TOP, VA_BOTTOM }; enum HorizontalAlignment { HA_CENTER, HA_LEFT, HA_RIGHT }; enum CoordinateMode { CM_ABSOLUTE, CM_RELATIVE }; Widget (const std::string& = "", point_type = 0.0f, point_type = 0.0f); Widget (const Widget&, const osg::CopyOp&); META_Object (osgWidget, Widget); virtual ~Widget() { } // This method is called when the widget is added to a Window; this is useful // when the widget needs to do something advanced (like a Label). The parent // is passed as the first argument, although _parent should already be set. virtual void parented(Window*) { } virtual void unparented(Window*) { } // This method is called when the widget's parent Window is added to a // WindowManager object. The base managed method (WHICH YOU MUST REMEMBER // TO CALL IN YOUR DERIVED METHODS!) sets the TexMat properly depending // on what coordinate system you're using. virtual void managed(WindowManager*) { } virtual void unmanaged(WindowManager*) { } // This method is called when the widget is resized or reallocated in any // way. This is useful when the widget manages some internal Drawables that need // to be modified in some way. virtual void positioned() { } void setDimensions( point_type = -1.0f, point_type = -1.0f, point_type = -1.0f, point_type = -1.0f, point_type = -1.0f ); void setPadding (point_type); void setColor (color_type, color_type, color_type, color_type, Corner = ALL_CORNERS); void addColor (color_type, color_type, color_type, color_type, Corner = ALL_CORNERS); void setTexCoord (texcoord_type, texcoord_type, Corner = ALL_CORNERS); void setLayer (Layer l, unsigned int offset = 0); // These are additional texture coordinate setting methods. // This method will use a given origin as the LOWER_LEFT point and texture the // remaining area based on some width and height values. void setTexCoordRegion(point_type, point_type, point_type, point_type); // These are convenience methods for setting up wrapping modes. void setTexCoordWrapHorizontal (); void setTexCoordWrapVertical (); bool setImage (osg::Image*, bool = false, bool = false); template bool setImage(const osg::ref_ptr& image, bool f1 = false, bool f2 = false) { return setImage(image.get(), f1, f2); } bool setImage (const std::string&, bool = false, bool = false); bool setTexture (osg::Texture*, bool = false, bool = false); void addX (point_type); void addY (point_type); void addWidth (point_type); void addHeight (point_type); void addOrigin (point_type, point_type); void addSize (point_type, point_type); point_type getWidth () const; point_type getHeight () const; point_type getX () const; point_type getY () const; point_type getZ () const; point_type getPadHorizontal () const; point_type getPadVertical () const; const Point& getPoint (Corner = ALL_CORNERS) const; const Color& getColor (Corner = ALL_CORNERS) const; const TexCoord& getTexCoord (Corner = ALL_CORNERS) const; Color getImageColorAtXY (point_type x, point_type y) const; XYCoord localXY (double, double) const; bool isPaddingUniform() const; bool isManaged() const { return _isManaged; } bool isStyled() const { return _isStyled; } void setDimensions(const Quad& q, point_type z = -1.0f) { setDimensions(q[0], q[1], q[2], q[3], z); } void setX(point_type x) { setDimensions(x); } void setY(point_type y) { setDimensions(-1.0f, y); } // This method should be use with extreme caution. void setZ(point_type z) { setDimensions(-1.0f, -1.0f, -1.0f, -1.0f, z); } void setWidth(point_type w) { setDimensions(-1.0f, -1.0f, w); } void setHeight(point_type h) { setDimensions(-1.0f, -1.0f, -1.0f, h); } void setOrigin(point_type x, point_type y) { setDimensions(x, y); } void setOrigin(const XYCoord& xy) { setOrigin(xy.x(), xy.y()); } void setSize(point_type w, point_type h) { setDimensions(-1.0f, -1.0f, w, h); } void setSize(const XYCoord& xy) { setSize(xy.x(), xy.y()); } void setColor(const Color& col, Corner p = ALL_CORNERS) { setColor(col.r(), col.g(), col.b(), col.a(), p); } void setTexCoord(const XYCoord& xy, Corner p = ALL_CORNERS) { setTexCoord(xy.x(), xy.y(), p); } void setTexCoordRegion(const XYCoord& xy, point_type w, point_type h) { setTexCoordRegion(xy.x(), xy.y(), w, h); } void setTexCoordRegion(point_type x, point_type y, const XYCoord& wh) { setTexCoordRegion(x, y, wh.x(), wh.y()); } void setTexCoordRegion(const XYCoord& xy, const XYCoord& wh) { setTexCoordRegion(xy.x(), xy.y(), wh.x(), wh.y()); } void addColor(const Color& col, Corner p = ALL_CORNERS) { addColor(col.r(), col.g(), col.b(), col.a(), p); } void addOrigin(const XYCoord& xy) { addOrigin(xy.x(), xy.y()); } void addSize(const XYCoord& xy) { addSize(xy.x(), xy.y()); } void setMinimumSize(point_type width, point_type height) { _minWidth = width; _minHeight = height; } void setMinimumSize(const XYCoord& xy) { setMinimumSize(xy.x(), xy.y()); } void setPadLeft(point_type p) { _padLeft = p; } void setPadRight(point_type p) { _padRight = p; } void setPadTop(point_type p) { _padTop = p; } void setPadBottom(point_type p) { _padBottom = p; } void setAlignHorizontal(HorizontalAlignment h) { _halign = h; } void setAlignVertical(VerticalAlignment v) { _valign = v; } void setCoordinateMode(CoordinateMode cm) { _coordMode = cm; } void setCanFill(bool f) { _canFill = f; } void setCanClone(bool c) { _canClone = c; } WindowManager* getWindowManager() { return _getWindowManager(); } const WindowManager* getWindowManager() const { return _getWindowManager(); } Window* getParent() { return _parent; } const Window* getParent() const { return _parent; } unsigned int getIndex() const { return _index; } XYCoord getOrigin() const { return XYCoord(getX(), getY()); } Color getImageColorAtXY(const XYCoord& xy) const { return getImageColorAtXY(xy.x(), xy.y()); } Color getImageColorAtPointerXY(double x, double y) const { return getImageColorAtXY(localXY(x, y)); } Point getPosition() const { return Point(getX(), getY(), getZ()); } XYCoord getSize() const { return XYCoord(getWidth(), getHeight()); } Quad getDimensions() const { return Quad(getX(), getY(), getWidth(), getHeight()); } point_type getPadLeft() const { return _padLeft; } point_type getPadRight() const { return _padRight; } point_type getPadTop() const { return _padTop; } point_type getPadBottom() const { return _padBottom; } HorizontalAlignment getAlignHorizontal() const { return _halign; } VerticalAlignment getAlignVertical() const { return _valign; } CoordinateMode getCoordinateMode() const { return _coordMode; } bool canFill() const { return _canFill; } bool canClone() const { return _canClone; } // This casts the bool _fill variable to be used in iteratively in functions such // as Window::_accumulate and whatnot. point_type getFillAsNumeric() const { return static_cast(_canFill); } point_type getWidthTotal() const { return getWidth() + getPadHorizontal(); } point_type getHeightTotal() const { return getHeight() + getPadVertical(); } point_type getMinWidth() const { return _minWidth; } point_type getMinHeight() const { return _minHeight; } point_type getMinWidthTotal() const { return _minWidth + getPadHorizontal(); } point_type getMinHeightTotal() const { return _minHeight + getPadVertical(); } unsigned int getLayer() const { return _layer; } protected: point_type _calculateZ(unsigned int) const; PointArray* _verts() { return dynamic_cast(getVertexArray()); } const PointArray* _verts() const { return dynamic_cast(getVertexArray()); } ColorArray* _cols() { return dynamic_cast(getColorArray()); } const ColorArray* _cols() const { return dynamic_cast(getColorArray()); } TexCoordArray* _texs() { return dynamic_cast(getTexCoordArray(0)); } const TexCoordArray* _texs() const { return dynamic_cast(getTexCoordArray(0)); } osg::Texture* _texture() { osg::StateSet* ss = getStateSet(); if(!ss) return 0; return dynamic_cast( ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE) ); } const osg::Texture* _texture() const { const osg::StateSet* ss = getStateSet(); if(!ss) return 0; return dynamic_cast( ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE) ); } osg::Image* _image() { return _getImage(); } const osg::Image* _image() const { return _getImage(); } friend class Window; // TODO: Because of the current class design, I don't think it's possible to // have a ref_ptr here. :( Window* _parent; unsigned int _index; unsigned int _layer; // Padding is the value of pixels of space between whatever the widget is "contianed" // in and the point at which it starts getting placed. point_type _padLeft; point_type _padRight; point_type _padTop; point_type _padBottom; // The alignments are used in conjunction when the widget is NOT set to fill. VerticalAlignment _valign; HorizontalAlignment _halign; // This flag determines how sizing values are interpretted by setDimensions(). CoordinateMode _coordMode; // These are the relative values, which are not stored directly in our verts // array but kept around for calculation later. Quad _relCoords; // This fill flag determines whether or not the widget will resize itself to fill // all available space. bool _canFill; // Set this to false in an implementation to prevent copying. bool _canClone; // This variable is only used by the Window object to determine if it's necessary // to call managed(). bool _isManaged; // This variable is like _isManaged; it is used to store whether the Widget has // been styled yet. bool _isStyled; // Set these variables to be the minimum size of a Widget so that it cannot be // resized any smaller than this. point_type _minWidth; point_type _minHeight; static osg::ref_ptr _norms; WindowManager* _getWindowManager () const; osg::Image* _getImage () const; }; typedef std::list > WidgetList; // A Widget subclass that prints stuff using osg::notify(). :) struct NotifyWidget: public Widget { META_Object(osgWidget, NotifyWidget); NotifyWidget(const std::string& n = "", point_type w = 0.0f, point_type h = 0.0f): Widget(n, w, h) { setEventMask(EVENT_ALL); } NotifyWidget(const NotifyWidget& widget, const osg::CopyOp& co): Widget(widget, co) { } bool focus(const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > focus called" << std::endl; return false; } bool unfocus(const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > unfocus called" << std::endl; return false; } bool mouseEnter(double, double, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > mouseEnter called" << std::endl; return false; } bool mouseOver(double, double, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > mouseOver called" << std::endl; return false; } bool mouseLeave(double, double, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > mouseLeave called" << std::endl; return false; } bool mouseDrag(double, double, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > mouseDrag called" << std::endl; return false; } bool mousePush(double, double, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > mousePush called" << std::endl; return false; } bool mouseRelease(double, double, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > mouseRelease called" << std::endl; return false; } bool mouseScroll(double, double, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > mouseScroll called" << std::endl; return false; } bool keyPress(int, int, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > keyPress called" << std::endl; return false; } bool keyRelease(int, int, const WindowManager*) { osg::notify(osg::NOTICE) << _name << " > keyRelease called" << std::endl; return false; } }; // A Widget that eats all events and returns true. struct NullWidget: public Widget { META_Object(osgWidget, NullWidget); NullWidget(const std::string& n = "", point_type w = 0.0f, point_type h = 0.0f): Widget(n, w, h) { setEventMask(EVENT_ALL); } NullWidget(const NullWidget& widget, const osg::CopyOp& co): Widget(widget, co) { } bool focus(const WindowManager*) { return true; } bool unfocus(const WindowManager*) { return true; } bool mouseEnter(double, double, const WindowManager*) { return true; } bool mouseOver(double, double, const WindowManager*) { return true; } bool mouseLeave(double, double, const WindowManager*) { return true; } bool mouseDrag(double, double, const WindowManager*) { return true; } bool mousePush(double, double, const WindowManager*) { return true; } bool mouseRelease(double, double, const WindowManager*) { return true; } bool mouseScroll(double, double, const WindowManager*) { return true; } bool keyPress(int, int, const WindowManager*) { return true; } bool keyRelease(int, int, const WindowManager*) { return true; } }; } #endif