From 9748fdd60505dd67403e81e5dfff1fc5fcb981c9 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 28 Nov 2008 14:35:33 +0000 Subject: [PATCH] From Jeremy Moles, updates to osgWidget Merged my Robert Osfield from OpenSceneGraph-osgWidget-dev. --- include/osgWidget/Box | 23 +- include/osgWidget/Canvas | 8 +- include/osgWidget/EventInterface | 48 ++- include/osgWidget/Export | 4 +- include/osgWidget/Frame | 178 ++++++--- include/osgWidget/Input | 12 +- include/osgWidget/Label | 5 +- include/osgWidget/Lua | 3 +- include/osgWidget/Python | 3 +- include/osgWidget/ScriptEngine | 3 +- include/osgWidget/StyleInterface | 3 +- include/osgWidget/StyleManager | 3 +- include/osgWidget/Table | 3 +- include/osgWidget/Types | 8 +- include/osgWidget/UIObjectParent | 4 +- include/osgWidget/Util | 25 +- include/osgWidget/Version | 3 +- include/osgWidget/ViewerEventHandlers | 38 +- include/osgWidget/Widget | 54 +-- include/osgWidget/Window | 36 +- include/osgWidget/WindowManager | 38 +- src/osgWidget/Box.cpp | 3 +- src/osgWidget/Canvas.cpp | 11 +- src/osgWidget/Frame.cpp | 545 +++++++++++++++++++++----- src/osgWidget/Input.cpp | 60 +-- src/osgWidget/Label.cpp | 64 +-- src/osgWidget/Lua.cpp | 1 - src/osgWidget/Python.cpp | 3 +- src/osgWidget/StyleManager.cpp | 1 - src/osgWidget/Table.cpp | 1 - src/osgWidget/Util.cpp | 107 +---- src/osgWidget/ViewerEventHandlers.cpp | 82 +++- src/osgWidget/Widget.cpp | 147 +++---- src/osgWidget/Window.cpp | 235 +++++++---- src/osgWidget/WindowManager.cpp | 111 ++++-- 35 files changed, 1234 insertions(+), 639 deletions(-) diff --git a/include/osgWidget/Box b/include/osgWidget/Box index be6146f7b..553a98a69 100644 --- a/include/osgWidget/Box +++ b/include/osgWidget/Box @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Box 46 2008-04-30 16:11:51Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_BOX #define OSGWIDGET_BOX @@ -21,17 +20,26 @@ namespace osgWidget { +//! The Box object is a Window subclass that can be configured to uniformly (or +//! non-uniformly) position it's children either vertically or horizontally. It +//! is the most basic Window implementation, though there is some difficulty when +//! positioning children such that each child object ends up pixel-aligned. class OSGWIDGET_EXPORT Box: public Window { public: - enum BOX_TYPE { + + //! An enum corresponding to the type of Box alignment. + enum BoxType { VERTICAL, HORIZONTAL }; - META_Object (osgWidget, Box); - - Box (const std::string& = "", BOX_TYPE = HORIZONTAL, bool = false); + META_Object(osgWidget, Box); + + //! The main constructor; takes the string name, the BoxType orientation, and a + //! boolean indicating whether or not all of the Box regions should be uniformly + //! sized. + Box (const std::string& = "", BoxType = HORIZONTAL, bool = false); Box (const Box&, const osg::CopyOp&); protected: @@ -43,10 +51,9 @@ class OSGWIDGET_EXPORT Box: public Window private: - BOX_TYPE _boxType; + BoxType _boxType; bool _uniform; unsigned int _lastAdd; - }; } diff --git a/include/osgWidget/Canvas b/include/osgWidget/Canvas index dd11f7c2c..a447f5e1f 100644 --- a/include/osgWidget/Canvas +++ b/include/osgWidget/Canvas @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Canvas 66 2008-07-14 21:54:09Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_CANVAS #define OSGWIDGET_CANVAS @@ -24,12 +23,13 @@ namespace osgWidget { class OSGWIDGET_EXPORT Canvas: public Window { public: - META_Object (osgWidget, Canvas); + + META_Object(osgWidget, Canvas); Canvas (const std::string& = ""); Canvas (const Canvas&, const osg::CopyOp&); - // This would conflict with the normal addWidget if there were default values. :( + //! Adds a Widget at the given XY coordinate. virtual bool addWidget(Widget*, point_type, point_type); protected: diff --git a/include/osgWidget/EventInterface b/include/osgWidget/EventInterface index f5af4b019..fa274035a 100644 --- a/include/osgWidget/EventInterface +++ b/include/osgWidget/EventInterface @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: EventInterface 64 2008-06-30 21:32:00Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_EVENT_INTERFACE #define OSGWIDGET_EVENT_INTERFACE @@ -67,15 +66,15 @@ class OSGWIDGET_EXPORT Event int keyMask; Event(WindowManager* wm, EventType _type = EVENT_NONE): - _wm (wm), - _window (0), - _widget (0), - _data (0), type (_type), x (0.0f), y (0.0f), key (-1), - keyMask (-1) { + keyMask (-1), + _wm (wm), + _window (0), + _widget (0), + _data (0) { } Event& makeType(EventType _type) { @@ -203,13 +202,19 @@ class FunctionCallback: public CallbackInterface }; // The highlevel functor. -class OSGWIDGET_EXPORT Callback +class OSGWIDGET_EXPORT Callback: public osg::Referenced { public: - - Callback():_type(EVENT_NONE),_data(0) {} - Callback(const Callback& rhs):_type(rhs._type),_data(rhs._data),_callback(rhs._callback) {} - + Callback(): _type(EVENT_NONE), _data(0), _callback(0) {} + Callback(const Callback& rhs): osg::Referenced(rhs), _type(rhs._type), _data(rhs._data), _callback(rhs._callback) {} + + // The more traditional style of OSG Callbacks. + Callback(EventType type, void* data=0): + _type (type), + _data (data), + _callback (0) { + } + // Creates a Callback that is bound to a member function. template Callback(bool (T::*function)(Event&), T* obj, EventType type, void* data=0): @@ -226,7 +231,11 @@ class OSGWIDGET_EXPORT Callback _callback (new FunctionCallback(functor)) { } - bool operator()(Event& ev) { + virtual ~Callback() {} + + virtual bool operator()(Event& ev) { + if(!_callback) return false; + return (*_callback)(ev); } @@ -241,9 +250,10 @@ class OSGWIDGET_EXPORT Callback const void* getData() const { return _data; } + protected: EventType _type; - void* _data; + void* _data; // We use a ref_ptr here so that we don't have to worry about memory. osg::ref_ptr _callback; @@ -301,7 +311,7 @@ class OSGWIDGET_EXPORT EventInterface return _eventMask; } - void addCallback(const Callback& cb) { + void addCallback(Callback* cb) { _callbacks.push_back(cb); } @@ -312,10 +322,10 @@ class OSGWIDGET_EXPORT EventInterface // This is the OLD method; testing a new method below. // if(i->getType() == ev.type && (*i)(ev)) return true; - if(i->getType() == ev.type) { - ev.setData(i->getData()); + if(i->get()->getType() & ev.type) { + ev.setData(i->get()->getData()); - if((*i)(ev)) return true; + if((*i->get())(ev)) return true; } } @@ -387,7 +397,7 @@ class OSGWIDGET_EXPORT EventInterface bool canKeyUp () const { return (_eventMask & EVENT_KEY_UP) != 0; } private: - typedef std::list CallbackList; + typedef std::list > CallbackList; unsigned int _eventMask; CallbackList _callbacks; diff --git a/include/osgWidget/Export b/include/osgWidget/Export index 29b879f2e..4d181de14 100644 --- a/include/osgWidget/Export +++ b/include/osgWidget/Export @@ -11,6 +11,8 @@ * OpenSceneGraph Public License for more details. */ +// Code by: Jeremy Moles (cubicool) 2007-2008 + #ifndef OSGWIDGET_EXPORT_ #define OSGWIDGET_EXPORT_ 1 @@ -41,7 +43,7 @@ \namespace osgWidget -The osgWidget library is a NodeKit that extends the core scene graph to support 3D GUI widget set. +The osgWidget library is a NodeKit that extends the core scene graph to support a 2D (and eventually 3D) GUI widget set. */ #endif diff --git a/include/osgWidget/Frame b/include/osgWidget/Frame index 91b2cfb2c..a0f05d886 100644 --- a/include/osgWidget/Frame +++ b/include/osgWidget/Frame @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Frame 59 2008-05-15 20:55:31Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_FRAME #define OSGWIDGET_FRAME @@ -21,11 +20,46 @@ namespace osgWidget { +/* +Lets take a moment and explain how Frame texturing works. When you create a Frame, you use +a specially designed texture that is "chopped" up horizontally by the Frame code into 8 equal +regions. Each region is then textured to a corresponding portion of the Frame, in the +following order: + + +---+---+---+---+---+---+---+---+ + | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | + +---+---+---+---+---+---+---+---+ + + 1. Upper-Left corner. + 2. Top border (rotated 90 degrees CCW). + 3. Upper-Right corner. + 4. Left border. + 5. Right border. + 6. Bottom-Left corner. + 7. Bottom border (rotated 90 degrees CCW). + 8. Bottom-Right corner. + +Now, these should be pretty self-explanatory if you visualize a frame as a 3x3 "table" +(which is exactly what it is), but note how regions 2 and 7 are rotated counter-clockwise. +We do this for a VERY important reason: we want to enable texture repeat on the border +regions, so that when the frame is resized the borders cleanly paint the texture over +the entire are (and don't stretch it). However, it is impossible in OpenGL to repeat a +sub-region of a texture without including either the vertical or horizontal bounds, so the +artist is required to rotate the region during their rendering so that our code can properly +rotate it back internally and have it repeat in the desired way. + +This method of texturing a Frame object is inspired by World of Warcraft "edge files", and it +is both efficient and easy-to-use--once you understand the basics. If you're still confused, +take a look at this URL, or any of the example themes: + + http://www.wowwiki.com/EdgeFiles +*/ + class OSGWIDGET_EXPORT Frame: public Table { public: - enum CORNER + enum CornerType { CORNER_LOWER_LEFT, CORNER_LOWER_RIGHT, @@ -33,7 +67,7 @@ class OSGWIDGET_EXPORT Frame: public Table CORNER_UPPER_RIGHT }; - enum BORDER + enum BorderType { BORDER_LEFT, BORDER_RIGHT, @@ -41,109 +75,127 @@ class OSGWIDGET_EXPORT Frame: public Table BORDER_BOTTOM }; - static std::string cornerToString (CORNER); - static std::string borderToString (BORDER); + enum FrameOptions + { + FRAME_RESIZE = 1, + FRAME_MOVE = 2, + FRAME_TEXTURE = 4, + FRAME_ALL = FRAME_RESIZE | FRAME_MOVE | FRAME_TEXTURE + }; + + static std::string cornerTypeToString (CornerType); + static std::string borderTypeToString (BorderType); class OSGWIDGET_EXPORT Corner: public Widget { public: - META_Object (osgWidget, Corner); + META_Object(osgWidget, Corner); - Corner (CORNER = CORNER_LOWER_LEFT, point_type = 0.0f, point_type = 0.0f); + Corner (CornerType = CORNER_LOWER_LEFT, point_type = 0.0f, point_type = 0.0f); Corner (const Corner&, const osg::CopyOp&); - bool mouseDrag(double, double, WindowManager*); + virtual void parented (Window*); + virtual bool mouseDrag (double, double, WindowManager*); - CORNER getCorner() const { + CornerType getCornerType() const + { return _corner; } - void setCorner(CORNER corner) { + void setCornerType(CornerType corner) + { _corner = corner; } - void setCornerAndName(CORNER corner) { + void setCornerTypeAndName(CornerType corner) + { _corner = corner; - _name = cornerToString(corner); + _name = cornerTypeToString(corner); } protected: - CORNER _corner; + + CornerType _corner; }; class OSGWIDGET_EXPORT Border: public Widget { public: - META_Object (osgWidget, Border); + META_Object(osgWidget, Border); - Border (BORDER = BORDER_LEFT, point_type = 0.0f, point_type = 0.0f); + Border (BorderType = BORDER_LEFT, point_type = 0.0f, point_type = 0.0f); Border (const Border&, const osg::CopyOp&); - bool mouseDrag(double, double, WindowManager*); + virtual void parented (Window*); + virtual void positioned (); + virtual bool mouseDrag (double, double, WindowManager*); - BORDER getBorder() const { + BorderType getBorderType() const + { return _border; } - void setBorder(BORDER border) { + void setBorderType(BorderType border) + { _border = border; } - void setBorderAndName(BORDER border) { + void setBorderTypeAndName(BorderType border) + { _border = border; - _name = borderToString(border); + _name = borderTypeToString(border); } protected: - BORDER _border; - + BorderType _border; }; - META_Object (osgWidget, Frame); + META_Object(osgWidget, Frame); - Frame (const std::string& = ""); + Frame (const std::string& = "", unsigned int = 0); Frame (const Frame&, const osg::CopyOp&); - virtual void managed(WindowManager*); - static Frame* createSimpleFrame( const std::string&, point_type, point_type, point_type, point_type, - Frame* = 0 + unsigned int = 0, + Frame* = 0 ); static Frame* createSimpleFrameWithSingleTexture( const std::string&, + osg::Image*, + point_type, + point_type, + unsigned int = 0, + Frame* = 0 + ); + + static Frame* createSimpleFrameFromTheme( const std::string&, + osg::Image*, point_type, point_type, - point_type, - point_type, - point_type, - point_type, - Frame* = 0 + unsigned int = 0, + Frame* = 0 ); void createSimpleFrame(point_type cw, point_type ch, point_type w, point_type h) { - createSimpleFrame(_name, cw, ch, w, h, this); + createSimpleFrame(_name, cw, ch, w, h, 0, this); } void createSimpleFrameWithSingleTexture( - const std::string& tex, - point_type tw, - point_type th, - point_type cw, - point_type ch, - point_type w, - point_type h + osg::Image* image, + point_type w, + point_type h ) { - createSimpleFrameWithSingleTexture(_name, tex, tw, th, cw, ch, w, h, this); + createSimpleFrameWithSingleTexture(_name, image, w, h, 0, this); } bool setWindow(Window*); @@ -152,19 +204,49 @@ class OSGWIDGET_EXPORT Frame: public Table const EmbeddedWindow* getEmbeddedWindow() const { return dynamic_cast(getByRowCol(1, 1)); } - Corner* getCorner(CORNER c) { return dynamic_cast(_getCorner(c)); } + Corner* getCorner(CornerType c) { return dynamic_cast(_getCorner(c)); } - const Corner* getCorner(CORNER c) const { return dynamic_cast(_getCorner(c)); } + const Corner* getCorner(CornerType c) const { return dynamic_cast(_getCorner(c)); } - Border* getBorder(BORDER b) { return dynamic_cast(_getBorder(b)); } + Border* getBorder(BorderType b) { return dynamic_cast(_getBorder(b)); } - const Border* getBorder(BORDER b) const { return dynamic_cast(_getBorder(b)); } + const Border* getBorder(BorderType b) const { return dynamic_cast(_getBorder(b)); } + + // This method resizes the internal EmbeddedWindow object and then properly resizes + // the reset of the Frame based on the sizes of the Corners, Borders, etc. + bool resizeFrame(point_type, point_type); + + unsigned int getFlags() const + { + return _flags; + } + + void setFlags(unsigned int flags) + { + _flags = flags; + } + + bool canResize() const + { + return (_flags & FRAME_RESIZE) != 0; + } + + bool canMove() const + { + return (_flags & FRAME_MOVE) != 0; + } + + bool canTexture() const + { + return (_flags & FRAME_TEXTURE) != 0; + } protected: - Widget* _getCorner (CORNER) const; - Widget* _getBorder (BORDER) const; + Widget* _getCorner (CornerType) const; + Widget* _getBorder (BorderType) const; + unsigned int _flags; }; } diff --git a/include/osgWidget/Input b/include/osgWidget/Input index 40cd92d43..621fda2ae 100644 --- a/include/osgWidget/Input +++ b/include/osgWidget/Input @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Input 45 2008-04-23 16:46:11Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_INPUT #define OSGWIDGET_INPUT @@ -21,9 +20,15 @@ namespace osgWidget { +// This is a string of values we use to try and determine the best Y +// descent value (yoffset); you're welcome to use what works best for +// your font. +const std::string DESCENT_STRING("qpl"); + class OSGWIDGET_EXPORT Input: public Label { public: + Input(const std::string& = "", const std::string& = "", unsigned int = 20); virtual void parented (Window*); @@ -34,7 +39,8 @@ class OSGWIDGET_EXPORT Input: public Label virtual bool keyUp (int, int, WindowManager*); virtual bool keyDown (int, int, WindowManager*); - void setCursor(Widget*); + void setCursor (Widget*); + unsigned int calculateBestYOffset (const std::string& = "qgl"); void setXOffset(point_type xo) { _xoff = xo; diff --git a/include/osgWidget/Label b/include/osgWidget/Label index 0305c8845..0cf5e40e6 100644 --- a/include/osgWidget/Label +++ b/include/osgWidget/Label @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Label 59 2008-05-15 20:55:31Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_LABEL #define OSGWIDGET_LABEL @@ -34,10 +33,8 @@ class OSGWIDGET_EXPORT Label: public Widget virtual void parented (Window*); virtual void unparented (Window*); - virtual void managed (WindowManager*); virtual void positioned (); - void update (); void setLabel (const std::string&); void setFont (const std::string&); void setFontSize (unsigned int); diff --git a/include/osgWidget/Lua b/include/osgWidget/Lua index 4f7e46aa6..678d81787 100644 --- a/include/osgWidget/Lua +++ b/include/osgWidget/Lua @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Lua 2 2008-01-24 16:11:26Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_LUA #define OSGWIDGET_LUA diff --git a/include/osgWidget/Python b/include/osgWidget/Python index 7a738d2cd..a5a457986 100644 --- a/include/osgWidget/Python +++ b/include/osgWidget/Python @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Python 2 2008-01-24 16:11:26Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_PYTHON #define OSGWIDGET_PYTHON diff --git a/include/osgWidget/ScriptEngine b/include/osgWidget/ScriptEngine index aa4326c9e..12b8cd20f 100644 --- a/include/osgWidget/ScriptEngine +++ b/include/osgWidget/ScriptEngine @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: ScriptEngine 2 2008-01-24 16:11:26Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_SCRIPT_ENGINE #define OSGWIDGET_SCRIPT_ENGINE diff --git a/include/osgWidget/StyleInterface b/include/osgWidget/StyleInterface index 0ca3568cd..ed5136860 100644 --- a/include/osgWidget/StyleInterface +++ b/include/osgWidget/StyleInterface @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: StyleInterface 63 2008-06-30 19:18:37Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_STYLE_INTERFACE #define OSGWIDGET_STYLE_INTERFACE diff --git a/include/osgWidget/StyleManager b/include/osgWidget/StyleManager index edea6a0a4..b864c5012 100644 --- a/include/osgWidget/StyleManager +++ b/include/osgWidget/StyleManager @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: StyleManager 61 2008-06-24 20:24:26Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_STYLE_MANAGER #define OSGWIDGET_STYLE_MANAGER diff --git a/include/osgWidget/Table b/include/osgWidget/Table index 0985071f2..4642f3e35 100644 --- a/include/osgWidget/Table +++ b/include/osgWidget/Table @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Table 48 2008-05-05 14:13:20Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_TABLE #define OSGWIDGET_TABLE diff --git a/include/osgWidget/Types b/include/osgWidget/Types index e05c6453e..53273f29a 100644 --- a/include/osgWidget/Types +++ b/include/osgWidget/Types @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Types 33 2008-04-04 19:03:12Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_TYPES #define OSGWIDGET_TYPES @@ -39,6 +38,11 @@ typedef osg::Vec4 Quad; typedef osg::Matrix::value_type matrix_type; +// This is multiplied by a normalized Z value [0.0f, -1.0f] to create a RenderBin number +// to set the state of the Window/Widget with. Perhaps at some later time this should +// be configurable. +const int OSGWIDGET_RENDERBIN_MOD = 5000; + } #endif diff --git a/include/osgWidget/UIObjectParent b/include/osgWidget/UIObjectParent index f25b68170..3d553d54f 100644 --- a/include/osgWidget/UIObjectParent +++ b/include/osgWidget/UIObjectParent @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: UIObjectParent 55 2008-05-12 19:14:42Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_UI_OBJECT_PARENT #define OSGWIDGET_UI_OBJECT_PARENT @@ -26,6 +25,7 @@ template class UIObjectParent { public: + typedef T object_type; typedef osg::observer_ptr ptr_type; typedef std::vector Vector; diff --git a/include/osgWidget/Util b/include/osgWidget/Util index bb82c8534..434886470 100644 --- a/include/osgWidget/Util +++ b/include/osgWidget/Util @@ -11,13 +11,12 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Util 59 2008-05-15 20:55:31Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_UTIL #define OSGWIDGET_UTIL -#include +#include #include #include #include @@ -71,26 +70,12 @@ class WindowManager; OSGWIDGET_EXPORT std::string getFilePath (const std::string&); OSGWIDGET_EXPORT std::string generateRandomName (const std::string&); - -OSGWIDGET_EXPORT osg::Matrix createInvertedYOrthoProjectionMatrix (matrix_type, matrix_type); -OSGWIDGET_EXPORT osg::Camera* createOrthoCamera (matrix_type, matrix_type); -OSGWIDGET_EXPORT osg::Camera* createInvertedYOrthoCamera (matrix_type, matrix_type); +OSGWIDGET_EXPORT osg::Camera* createOrthoCamera (matrix_type, matrix_type); // This function sets up our basic example framework, and optionally sets some root // scene data. -OSGWIDGET_EXPORT int createExample(osgViewer::Viewer&, WindowManager*, osg::Node* = 0); - -// This function works like the above routine, except creates an additional "outside" -// view for looking at your 2D scene. -// TODO: Fix this! -OSGWIDGET_EXPORT int createCompositeExample( - osgViewer::CompositeViewer&, - osgViewer::View*, - WindowManager*, - osg::Node* = 0 -); - -OSGWIDGET_EXPORT bool writeWindowManagerNode(WindowManager*); +OSGWIDGET_EXPORT int createExample (osgViewer::Viewer&, WindowManager*, osg::Node* = 0); +OSGWIDGET_EXPORT bool writeWindowManagerNode (WindowManager*); } diff --git a/include/osgWidget/Version b/include/osgWidget/Version index a41c81f1c..3babc21f6 100644 --- a/include/osgWidget/Version +++ b/include/osgWidget/Version @@ -1,5 +1,4 @@ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Version 64 2008-06-30 21:32:00Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_VERSION #define OSGWIDGET_VERSION diff --git a/include/osgWidget/ViewerEventHandlers b/include/osgWidget/ViewerEventHandlers index cd37ceb1f..53bb4fe28 100644 --- a/include/osgWidget/ViewerEventHandlers +++ b/include/osgWidget/ViewerEventHandlers @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: ViewerEventHandlers 31 2008-04-01 19:36:41Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_VIEWER_EVENT_HANDLERS #define OSGWIDGET_VIEWER_EVENT_HANDLERS @@ -31,6 +30,7 @@ namespace osgWidget { class OSGWIDGET_EXPORT MouseHandler: public osgGA::GUIEventHandler { public: + MouseHandler(WindowManager*); virtual bool handle( @@ -46,7 +46,7 @@ class OSGWIDGET_EXPORT MouseHandler: public osgGA::GUIEventHandler protected: - osg::ref_ptr _wm; + osg::observer_ptr _wm; bool _handleMousePush (float, float, int); bool _handleMouseRelease (float, float, int); @@ -57,13 +57,13 @@ class OSGWIDGET_EXPORT MouseHandler: public osgGA::GUIEventHandler MouseAction _isMouseEvent (osgGA::GUIEventAdapter::EventType) const; bool _doMouseEvent (float, float, MouseEvent); - }; // This handles the forwarding of keypress events. class OSGWIDGET_EXPORT KeyboardHandler: public osgGA::GUIEventHandler { public: + KeyboardHandler(WindowManager*); virtual bool handle( @@ -74,7 +74,7 @@ class OSGWIDGET_EXPORT KeyboardHandler: public osgGA::GUIEventHandler ); protected: - osg::ref_ptr _wm; + osg::observer_ptr _wm; }; @@ -82,7 +82,8 @@ class OSGWIDGET_EXPORT KeyboardHandler: public osgGA::GUIEventHandler class OSGWIDGET_EXPORT ResizeHandler: public osgGA::GUIEventHandler { public: - ResizeHandler(WindowManager*, osg::Camera*); + + ResizeHandler(WindowManager*, osg::Camera* = 0); virtual bool handle( const osgGA::GUIEventAdapter&, @@ -93,9 +94,30 @@ class OSGWIDGET_EXPORT ResizeHandler: public osgGA::GUIEventHandler protected: - osg::ref_ptr _wm; - osg::ref_ptr _camera; + osg::observer_ptr _wm; + osg::observer_ptr _camera; +}; +// This class provides a hotkey that lets you toggle back and forth between +// a camera and setting the CameraManipulator's home point. +class OSGWIDGET_EXPORT CameraSwitchHandler: public osgGA::GUIEventHandler +{ + public: + + CameraSwitchHandler(WindowManager*, osg::Camera*); + + virtual bool handle( + const osgGA::GUIEventAdapter&, + osgGA::GUIActionAdapter&, + osg::Object*, + osg::NodeVisitor* + ); + + protected: + + osg::observer_ptr _wm; + osg::observer_ptr _camera; + osg::ref_ptr _oldNode; }; } diff --git a/include/osgWidget/Widget b/include/osgWidget/Widget index a2c196043..a78a271b4 100644 --- a/include/osgWidget/Widget +++ b/include/osgWidget/Widget @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Widget 64 2008-06-30 21:32:00Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_WIDGET #define OSGWIDGET_WIDGET @@ -44,14 +43,14 @@ public: LR = LOWER_RIGHT, UR = UPPER_RIGHT, UL = UPPER_LEFT, - ALL_CORNERS = 4 + ALL_CORNERS = 4 }; enum Layer { - LAYER_TOP = 20, - LAYER_HIGH = 15, - LAYER_MIDDLE = 10, - LAYER_LOW = 5, + LAYER_TOP = 100, + LAYER_HIGH = 75, + LAYER_MIDDLE = 50, + LAYER_LOW = 25, LAYER_BG = 0 }; @@ -94,7 +93,8 @@ public: // 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 managed(WindowManager*) { + } virtual void unmanaged(WindowManager*) { } @@ -117,6 +117,7 @@ public: 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 @@ -127,8 +128,9 @@ public: void setTexCoordWrapHorizontal (); void setTexCoordWrapVertical (); - bool setImage (osg::Image*, bool=false); - bool setImage (const std::string&, bool=false); + bool setImage (osg::Image*, bool = false, bool = false); + 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); @@ -149,7 +151,6 @@ public: const Color& getColor (Corner = ALL_CORNERS) const; const TexCoord& getTexCoord (Corner = ALL_CORNERS) const; - Corner convertCorner (Corner) const; Color getImageColorAtXY (point_type x, point_type y) const; XYCoord localXY (double, double) const; @@ -216,6 +217,14 @@ public: 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); } @@ -237,11 +246,6 @@ public: setMinimumSize(xy.x(), xy.y()); } - // TODO: Refine this... - void setLayer(Layer l, unsigned int offset = 0) { - _layer = l + offset; - } - void setPadLeft(point_type p) { _padLeft = p; } @@ -394,8 +398,6 @@ public: protected: - - point_type _calculateZ(unsigned int) const; PointArray* _verts() { @@ -422,15 +424,23 @@ public: return dynamic_cast(getTexCoordArray(0)); } - osg::Texture2D* _texture() { + osg::Texture* _texture() { + osg::StateSet* ss = getStateSet(); + + if(!ss) return 0; + return dynamic_cast( - getStateSet()->getTextureAttribute(0, osg::StateAttribute::TEXTURE) + ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE) ); } - const osg::Texture2D* _texture() const { + const osg::Texture* _texture() const { + const osg::StateSet* ss = getStateSet(); + + if(!ss) return 0; + return dynamic_cast( - getStateSet()->getTextureAttribute(0, osg::StateAttribute::TEXTURE) + ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE) ); } diff --git a/include/osgWidget/Window b/include/osgWidget/Window index 7f5754017..bd6a20abb 100644 --- a/include/osgWidget/Window +++ b/include/osgWidget/Window @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Window 66 2008-07-14 21:54:09Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_WINDOW #define OSGWIDGET_WINDOW @@ -73,7 +72,8 @@ class OSGWIDGET_EXPORT Window: virtual void unmanaged (WindowManager*); virtual void positioned (); - bool setWindow(Window*); + bool setWindow (Window*); + void updateSizeFromWindow (); Window* getWindow() { return _window.get(); @@ -139,7 +139,8 @@ class OSGWIDGET_EXPORT Window: // This method wraps our Geode's addDrawable() method and returns the index of // the newly-added Drawable. - unsigned int addDrawableAndGetIndex(osg::Drawable*); + unsigned int addDrawableAndGetIndex (osg::Drawable*); + unsigned int addChildAndGetIndex (osg::Node*); bool isVisible () const; bool isXYWithinVisible (float, float) const; @@ -147,6 +148,7 @@ class OSGWIDGET_EXPORT Window: 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; @@ -157,7 +159,11 @@ class OSGWIDGET_EXPORT Window: XYCoord getAbsoluteOrigin () const; // This method wraps the current Window in a EmbeddedWindow object and returns it. - EmbeddedWindow* embed(); + EmbeddedWindow* embed( + const std::string& = "", + Widget::Layer = Widget::LAYER_MIDDLE, + unsigned int = 0 + ); Widget* getFocused() { return _focused.get(); @@ -313,6 +319,14 @@ class OSGWIDGET_EXPORT Window: _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; @@ -328,6 +342,10 @@ class OSGWIDGET_EXPORT Window: _y = y; } + void setOrigin(const XYCoord& xy) { + setOrigin(xy.x(), xy.y()); + } + void setRotate(matrix_type r) { _r = r; } @@ -382,19 +400,19 @@ class OSGWIDGET_EXPORT Window: } void attachMoveCallback() { - addCallback(Callback(&callbackWindowMove, EVENT_MOUSE_DRAG)); + addCallback(new Callback(&callbackWindowMove, EVENT_MOUSE_DRAG)); } void attachRotateCallback() { - addCallback(Callback(&callbackWindowRotate, EVENT_MOUSE_DRAG)); + addCallback(new Callback(&callbackWindowRotate, EVENT_MOUSE_DRAG)); } void attachScaleCallback() { - addCallback(Callback(&callbackWindowScale, EVENT_MOUSE_DRAG)); + addCallback(new Callback(&callbackWindowScale, EVENT_MOUSE_DRAG)); } void attachTabFocusCallback() { - addCallback(Callback(&callbackWindowTabFocus, EVENT_KEY_DOWN)); + addCallback(new Callback(&callbackWindowTabFocus, EVENT_KEY_DOWN)); } typedef point_type (Widget::*Getter)() const; diff --git a/include/osgWidget/WindowManager b/include/osgWidget/WindowManager index bf79d91ae..749e3308d 100644 --- a/include/osgWidget/WindowManager +++ b/include/osgWidget/WindowManager @@ -11,8 +11,7 @@ * OpenSceneGraph Public License for more details. */ -// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: WindowManager 66 2008-07-14 21:54:09Z cubicool $ +// Code by: Jeremy Moles (cubicool) 2007-2008 #ifndef OSGWIDGET_WINDOW_MANAGER #define OSGWIDGET_WINDOW_MANAGER @@ -40,11 +39,10 @@ typedef osgUtil::LineSegmentIntersector::Intersections Intersections; class OSGWIDGET_EXPORT WindowManager: public osg::Switch, public UIObjectParent { public: enum WmFlags { - WM_USE_LUA = 0x00000001, - WM_USE_PYTHON = 0x00000002, - WM_PICK_DEBUG = 0x00000004, - WM_NO_INVERT_Y = 0x00000008, - WM_NO_BETA_WARN = 0x00000010 + WM_USE_LUA = 0x00000001, + WM_USE_PYTHON = 0x00000002, + WM_USE_RENDERBINS = 0x00000004, + WM_PICK_DEBUG = 0x00000008 }; enum PointerDirection { @@ -91,6 +89,9 @@ class OSGWIDGET_EXPORT WindowManager: public osg::Switch, public UIObjectParent< void setStyleManager (StyleManager*); void resizeAllWindows (bool = true); + XYCoord windowXY (double, double) const; + XYCoord localXY (double, double) const; + // Methods all called by the ViewerEventHandlers::MouseHandler object, or // by some customer caller of your own. Examples of this to come... bool pointerMove (float, float); @@ -119,8 +120,8 @@ class OSGWIDGET_EXPORT WindowManager: public osg::Switch, public UIObjectParent< return (_flags & WM_USE_PYTHON) != 0; } - bool isInvertedY() const { - return (_flags & WM_NO_INVERT_Y) == 0; + bool isUsingRenderBins() const { + return (_flags & WM_USE_RENDERBINS) != 0; } int getMouseKeysDown() const { @@ -242,6 +243,11 @@ class OSGWIDGET_EXPORT WindowManager: public osg::Switch, public UIObjectParent< _height = h; } + void setWindowSize(point_type w, point_type h) { + _windowWidth = w; + _windowHeight = h; + } + // Wrappers around the real calls. These only pertains to mouse buttons, // particularly 3-button mice, although there are other more generic // "pointer" API methods. @@ -282,10 +288,20 @@ class OSGWIDGET_EXPORT WindowManager: public osg::Switch, public UIObjectParent< } }; + // A functor used to sort the Windows by their BinNum component in descending order. + struct WindowBinNumberCompare: public std::binary_function { + bool operator()(const ptr_type& x, const ptr_type& y) { + return + x.get()->getOrCreateStateSet()->getBinNumber() > + y.get()->getOrCreateStateSet()->getBinNumber() + ; + } + }; + point_type _width; point_type _height; - point_type _zNear; - point_type _zFar; + point_type _windowWidth; + point_type _windowHeight; matrix_type _numForeground; matrix_type _numBackground; unsigned int _flags; diff --git a/src/osgWidget/Box.cpp b/src/osgWidget/Box.cpp index c3da08517..b0c9d6e03 100644 --- a/src/osgWidget/Box.cpp +++ b/src/osgWidget/Box.cpp @@ -1,11 +1,10 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Box.cpp 64 2008-06-30 21:32:00Z cubicool $ #include namespace osgWidget { -Box::Box(const std::string& name, BOX_TYPE bt, bool uniform): +Box::Box(const std::string& name, BoxType bt, bool uniform): Window (name), _boxType (bt), _uniform (uniform), diff --git a/src/osgWidget/Canvas.cpp b/src/osgWidget/Canvas.cpp index 2459e79ad..7040cf2d6 100644 --- a/src/osgWidget/Canvas.cpp +++ b/src/osgWidget/Canvas.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Canvas.cpp 66 2008-07-14 21:54:09Z cubicool $ #include @@ -20,13 +19,11 @@ void Canvas::_resizeImplementation(point_type w, point_type h) { } bool Canvas::addWidget(Widget* widget, point_type x, point_type y) { - if(Window::addWidget(widget)) { - widget->setOrigin(x, y); + if(!widget) return false; - return true; - } - - return false; + widget->setOrigin(x, y); + + return Window::addWidget(widget); } } diff --git a/src/osgWidget/Frame.cpp b/src/osgWidget/Frame.cpp index dab72159d..507a1a4d6 100644 --- a/src/osgWidget/Frame.cpp +++ b/src/osgWidget/Frame.cpp @@ -1,13 +1,15 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Frame.cpp 59 2008-05-15 20:55:31Z cubicool $ +#include #include #include #include +#include namespace osgWidget { -std::string Frame::cornerToString(CORNER c) { +std::string Frame::cornerTypeToString(CornerType c) +{ if(c == CORNER_LOWER_LEFT) return "CornerLowerLeft"; else if(c == CORNER_LOWER_RIGHT) return "CornerLowerRight"; @@ -17,7 +19,8 @@ std::string Frame::cornerToString(CORNER c) { else return "CornerUpperLeft"; } -std::string Frame::borderToString(BORDER b) { +std::string Frame::borderTypeToString(BorderType b) +{ if(b == BORDER_LEFT) return "BorderLeft"; else if(b == BORDER_RIGHT) return "BorderRight"; @@ -27,54 +30,44 @@ std::string Frame::borderToString(BORDER b) { else return "BorderBottom"; } -Frame::Corner::Corner(CORNER corner, point_type width, point_type height): -Widget (cornerToString(corner), width, height), -_corner (corner) { - setEventMask(EVENT_MASK_MOUSE_DRAG); +Frame::Corner::Corner(CornerType corner, point_type width, point_type height): +Widget (cornerTypeToString(corner), width, height), +_corner (corner) +{ } Frame::Corner::Corner(const Corner& corner, const osg::CopyOp& co): Widget (corner, co), -_corner (corner._corner) { +_corner (corner._corner) +{ } -bool Frame::Corner::mouseDrag(double x, double y, WindowManager* wm) { - Window* parent = getParent(); +void Frame::Corner::parented(Window* window) { + Frame* parent = dynamic_cast(getParent()); - if(!parent) return false; + if(!parent) return; - if(wm->isInvertedY()) { - if(_corner == CORNER_UPPER_LEFT) { - if(parent->resizeAdd(-x, -y)) parent->addOrigin(x, y); - } + if(parent->canResize()) setEventMask(EVENT_MASK_MOUSE_DRAG); +} - else if(_corner == CORNER_UPPER_RIGHT) { - if(parent->resizeAdd(x, -y)) parent->addY(y); - } +bool Frame::Corner::mouseDrag(double x, double y, WindowManager* wm) +{ + Frame* parent = dynamic_cast(getParent()); - else if(_corner == CORNER_LOWER_RIGHT) parent->resizeAdd(x, y); + if(!parent || !parent->canResize()) return false; - else { - if(parent->resizeAdd(-x, y)) parent->addX(x); - } + if(_corner == CORNER_UPPER_LEFT) { + if(parent->resizeAdd(-x, y)) parent->addX(x); + } + + else if(_corner == CORNER_UPPER_RIGHT) parent->resizeAdd(x, y); + + else if(_corner == CORNER_LOWER_RIGHT) { + if(parent->resizeAdd(x, -y)) parent->addY(y); } - // These are basically flipped-around versions of the above routines; we - // do it this way to avoid lots of uncessary if tests. else { - if(_corner == CORNER_UPPER_LEFT) { - if(parent->resizeAdd(-x, y)) parent->addX(x); - } - - else if(_corner == CORNER_UPPER_RIGHT) parent->resizeAdd(x, y); - - else if(_corner == CORNER_LOWER_RIGHT) { - if(parent->resizeAdd(x, -y)) parent->addY(y); - } - - else { - if(parent->resizeAdd(-x, -y)) parent->addOrigin(x, y); - } + if(parent->resizeAdd(-x, -y)) parent->addOrigin(x, y); } parent->update(); @@ -82,34 +75,84 @@ bool Frame::Corner::mouseDrag(double x, double y, WindowManager* wm) { return true; } -Frame::Border::Border(BORDER border, point_type width, point_type height): -Widget (borderToString(border), width, height), -_border (border) { +Frame::Border::Border(BorderType border, point_type width, point_type height): +Widget (borderTypeToString(border), width, height), +_border (border) +{ setCanFill(true); - setEventMask(EVENT_MASK_MOUSE_DRAG); } Frame::Border::Border(const Border& border, const osg::CopyOp& co): Widget (border, co), -_border (border._border) { +_border (border._border) +{ } -bool Frame::Border::mouseDrag(double x, double y, WindowManager* wm) { - Window* parent = getParent(); +void Frame::Border::parented(Window* window) { + Frame* parent = dynamic_cast(getParent()); - if(!parent) return false; + if(!parent) return; - if(_border == BORDER_LEFT) { - if(parent->resizeAdd(-x, 0.0f)) parent->addX(x); + if(parent->canResize()) setEventMask(EVENT_MASK_MOUSE_DRAG); +} + +void Frame::Border::positioned() +{ + osg::Image* image = _image(); + + if(!image) return; + + Frame* parent = dynamic_cast(getParent()); + + if(!parent || !parent->canTexture()) return; + + point_type w = image->s() / 8.0f; + point_type h = getHeight(); + + if(_border == BORDER_LEFT) setTexCoordRegion(w * 3, 0.0f, w, h); + + else if(_border == BORDER_RIGHT) setTexCoordRegion(w * 4, 0.0f, w, h); + + else if(_border == BORDER_TOP) { + // TODO: Temporary; fix this. + point_type tx1 = (w * 2) / image->s(); + point_type tx2 = w / image->s(); + point_type tx3 = getWidth() / w; + + setTexCoord(tx1, tx3, LL); + setTexCoord(tx1, 0.0f, LR); + setTexCoord(tx2, 0.0f, UR); + setTexCoord(tx2, tx3, UL); } - else if(_border == BORDER_RIGHT) parent->resizeAdd(x, 0.0f); + else { + point_type tx1 = (w * 7) / image->s(); + point_type tx2 = (w * 6) / image->s(); + point_type tx3 = getWidth() / w; - else if(_border == BORDER_TOP) parent->addOrigin(x, y); + setTexCoord(tx1, tx3, LL); + setTexCoord(tx1, 0.0f, LR); + setTexCoord(tx2, 0.0f, UR); + setTexCoord(tx2, tx3, UL); + } +} + +bool Frame::Border::mouseDrag(double x, double y, WindowManager* wm) +{ + Frame* parent = dynamic_cast(getParent()); + + if(!parent) return false; + + if(_border == BORDER_TOP && parent->canMove()) parent->addOrigin(x, y); else { - // The only BORDER that inverted-Y affects is this... - if(wm->isInvertedY()) parent->resizeAdd(0.0f, y); + if(!parent->canResize()) return false; + + if(_border == BORDER_LEFT) { + if(parent->resizeAdd(-x, 0.0f)) parent->addX(x); + } + + else if(_border == BORDER_RIGHT) parent->resizeAdd(x, 0.0f); else { if(parent->resizeAdd(0.0f, -y)) parent->addY(y); @@ -121,54 +164,29 @@ bool Frame::Border::mouseDrag(double x, double y, WindowManager* wm) { return true; } -Frame::Frame(const std::string& name): -Table(name, 3, 3) { +Frame::Frame(const std::string& name, unsigned int flags): +Table (name, 3, 3), +_flags (flags) +{ } Frame::Frame(const Frame& frame, const osg::CopyOp& co): -Table(frame, co) { +Table(frame, co) +{ } -Widget* Frame::_getCorner(CORNER c) const { - return const_cast(getByName(cornerToString(c))); +Widget* Frame::_getCorner(CornerType c) const +{ + return const_cast(getByName(cornerTypeToString(c))); } -Widget* Frame::_getBorder(BORDER b) const { - return const_cast(getByName(borderToString(b))); +Widget* Frame::_getBorder(BorderType b) const +{ + return const_cast(getByName(borderTypeToString(b))); } -void Frame::managed(WindowManager* wm) { - Window::managed(wm); - - // Our Frame is created in an inverted-Y environment, so if this is the case - // just return here. - if(wm->isInvertedY()) return; - - Corner* ll = getCorner(CORNER_LOWER_LEFT); - Corner* lr = getCorner(CORNER_LOWER_RIGHT); - Corner* ul = getCorner(CORNER_UPPER_LEFT); - Corner* ur = getCorner(CORNER_UPPER_RIGHT); - Border* t = getBorder(BORDER_TOP); - Border* b = getBorder(BORDER_BOTTOM); - - if(!ll || !lr || !ul || !ur || !t || !b) { - warn() - << "One or more of your Corner/Border objects in the Frame [" - << _name << "] are invalid; cannot invert orientation." << std::endl - ; - - return; - } - - ll->setCornerAndName(CORNER_UPPER_LEFT); - lr->setCornerAndName(CORNER_UPPER_RIGHT); - ul->setCornerAndName(CORNER_LOWER_LEFT); - ur->setCornerAndName(CORNER_LOWER_RIGHT); - t->setBorderAndName(BORDER_BOTTOM); - b->setBorderAndName(BORDER_TOP); -} - -bool Frame::setWindow(Window* window) { +bool Frame::setWindow(Window* window) +{ if(!window) return false; EmbeddedWindow* ew = getEmbeddedWindow(); @@ -186,24 +204,25 @@ Frame* Frame::createSimpleFrame( point_type ch, point_type w, point_type h, + unsigned int flags, Frame* exFrame ) { Frame* frame = 0; // Use an "existing frame" if we have it (for example, if you've in inherited from // Frame and want to use this stuff. - if(!exFrame) frame = new Frame(name); + if(!exFrame) frame = new Frame(name, flags); else frame = exFrame; - frame->addWidget(new Corner(CORNER_UPPER_LEFT, cw, ch), 0, 0); - frame->addWidget(new Border(BORDER_TOP, w, ch), 0, 1); - frame->addWidget(new Corner(CORNER_UPPER_RIGHT, cw, ch), 0, 2); - frame->addWidget(new Border(BORDER_LEFT, cw, h), 1, 0); - frame->addWidget(new Border(BORDER_RIGHT, cw, h), 1, 2); - frame->addWidget(new Corner(CORNER_LOWER_LEFT, cw, ch), 2, 0); - frame->addWidget(new Border(BORDER_BOTTOM, w, ch), 2, 1); - frame->addWidget(new Corner(CORNER_LOWER_RIGHT, cw, ch), 2, 2); + frame->addWidget(new Corner(CORNER_LOWER_LEFT, cw, ch), 0, 0); + frame->addWidget(new Border(BORDER_BOTTOM, w, ch), 0, 1); + frame->addWidget(new Corner(CORNER_LOWER_RIGHT, cw, ch), 0, 2); + frame->addWidget(new Border(BORDER_LEFT, cw, h), 1, 0); + frame->addWidget(new Border(BORDER_RIGHT, cw, h), 1, 2); + frame->addWidget(new Corner(CORNER_UPPER_LEFT, cw, ch), 2, 0); + frame->addWidget(new Border(BORDER_TOP, w, ch), 2, 1); + frame->addWidget(new Corner(CORNER_UPPER_RIGHT, cw, ch), 2, 2); EmbeddedWindow* ew = new EmbeddedWindow(name, w, h); @@ -214,6 +233,7 @@ Frame* Frame::createSimpleFrame( return frame; } +/* Frame* Frame::createSimpleFrameWithSingleTexture( const std::string& name, const std::string& texture, @@ -247,5 +267,332 @@ Frame* Frame::createSimpleFrameWithSingleTexture( return frame; } +*/ + +// Inspired by: http://www.wowwiki.com/EdgeFiles +Frame* Frame::createSimpleFrameWithSingleTexture( + const std::string& name, + osg::Image* image, + point_type width, + point_type height, + unsigned int flags, + Frame* exFrame +) { + Frame* frame = 0; + + double w = width; + double h = height; + + if (image) + { + w = image->s() / 8.0f; + h = image->t(); + } + + // The same as above... + if(!exFrame) frame = createSimpleFrame(name, w, h, width, height, flags); + + else frame = createSimpleFrame(name, w, h, width, height, 0, exFrame); + + if (image) + { + + for(unsigned int i = 0; i < 9; i++) frame->getObjects()[i]->setImage(image); + + XYCoord twh(w, h); + + frame->getCorner(CORNER_UPPER_LEFT )->setTexCoordRegion(0.0f, 0.0f, twh); + frame->getBorder(BORDER_TOP )->setTexCoordRegion(w, 0.0f, twh); + frame->getCorner(CORNER_UPPER_RIGHT)->setTexCoordRegion(w * 2, 0.0f, twh); + frame->getBorder(BORDER_LEFT )->setTexCoordRegion(w * 3, 0.0f, twh); + frame->getBorder(BORDER_RIGHT )->setTexCoordRegion(w * 4, 0.0f, twh); + frame->getCorner(CORNER_LOWER_LEFT )->setTexCoordRegion(w * 5, 0.0f, twh); + frame->getBorder(BORDER_BOTTOM )->setTexCoordRegion(w * 6, 0.0f, twh); + frame->getCorner(CORNER_LOWER_RIGHT)->setTexCoordRegion(w * 7, 0.0f, twh); + + // We set all of these to wrap vertically, but the REAL texture coordinates will + // be generated properly in the positioned() method. + frame->getByRowCol(0, 1)->setTexCoordWrapVertical(); + frame->getByRowCol(1, 0)->setTexCoordWrapVertical(); + frame->getByRowCol(1, 2)->setTexCoordWrapVertical(); + frame->getByRowCol(2, 1)->setTexCoordWrapVertical(); + + // frame->getEmbeddedWindow()->setTexCoordRegion(cw, ch, tw - (cw * 2.0f), th - (ch * 2.0f)); + } + else + { + osg::notify(osg::WARN) << "createSimpleFrameWithSingleTexture with a null image, the frame " << name << " will be use texture" << std::endl; + } + + return frame; +} + +bool Frame::resizeFrame(point_type w, point_type h) { + Border* left = getBorder(BORDER_LEFT); + Border* right = getBorder(BORDER_RIGHT); + Border* top = getBorder(BORDER_TOP); + Border* bottom = getBorder(BORDER_BOTTOM); + + if(!left || !right || !top || !bottom) return false; + + return resize( + left->getWidth() + right->getWidth() + w, + top->getHeight() + bottom->getHeight() + h + ); +} + + +osg::Image* createNatifEdgeImageFromTheme(osg::Image* theme); + +Frame* Frame::createSimpleFrameFromTheme( + const std::string& name, + osg::Image* image, + point_type width, + point_type height, + unsigned int flags, + Frame* exFrame +) { + + osg::ref_ptr natifImage = createNatifEdgeImageFromTheme(image); + Frame* frame; + + frame = createSimpleFrameWithSingleTexture(name, natifImage.get(), width, height, flags, exFrame); + + if (frame && image && natifImage.valid()) + { + const unsigned int bpps = image->getPixelSizeInBits() / 8; + const unsigned int one_third_s = image->s()/3; + unsigned char* srcdata = (unsigned char*)image->data(); + osg::Vec4 color(0,0,0,1); + for (unsigned int d = 0; d < bpps; d++) + { + color[d] = srcdata[one_third_s * image->s() * bpps + (one_third_s) * bpps + d] * 1.0/255.0; + } + frame->getEmbeddedWindow()->setColor(color); + } + return frame; +} + + + + + + + +// (c) 2006-2008 Jean-Sébastien Guay +// adapted by Cedric Pinson + +/** Implementation of copyImage. */ +template +void copyDataImpl(const osg::Image* source, + const unsigned int x1, const unsigned int y1, + const unsigned int x2, const unsigned int y2, + osg::Image* destination, + const unsigned int xd = 0, const unsigned int yd = 0) +{ + if ((unsigned int)destination->s() >= xd + (x2 - x1) && + (unsigned int)destination->t() >= yd + (y2 - y1)) + { + const unsigned int bpps = source->getPixelSizeInBits() / (8 * sizeof(T)); + + T* srcdata = (T*)source->data(); + T* dstdata = (T*)destination->data(); + + for (unsigned int y = 0; y < y2 - y1; ++y) + { + for (unsigned int x = 0; x < x2 - x1; ++x) + { + for (unsigned int d = 0; d < bpps; d++) + { + T v = srcdata[(y + y1) * source->s() * bpps + (x + x1) * bpps + d]; + dstdata[(yd + y) * destination->s() * bpps + (xd + x) * bpps + d] = v; + } + } + } + } + else + assert(false && "copyDataImpl: Incorrect image dimensions."); +} + +/** Copies a rectangle of corners (x1, y1), (x2, y2) from an image into + another image starting at position (xd, yd). No scaling is done, the + pixels are just copied, so the destination image must be at least + (xd + (x2 - x1)) by (yd + (y2 - y1)) pixels. */ +void copyData(const osg::Image* source, + const unsigned int x1, const unsigned int y1, + const unsigned int x2, const unsigned int y2, + osg::Image* destination, + const unsigned int xd, const unsigned int yd) +{ + if (source->getDataType() == destination->getDataType()) + { + if (source->getDataType() == GL_UNSIGNED_BYTE) + { + copyDataImpl(source, x1, y1, x2, y2, + destination, xd, yd); + } + else + { + assert(false && "copyData not implemented for this data type"); + } + } + else + { + assert(false && "source and destination images must be of the same type."); + return; + } +} + + +/** Implementation of rotateImage. */ +template +osg::Image* rotateImageImpl(osg::Image* image) +{ + if (image->s() == image->t()) + { + const unsigned int s = image->s(); + const unsigned int bpp = image->getPixelSizeInBits() / (8 * sizeof(T)); + + osg::ref_ptr destination = new osg::Image; + destination->allocateImage(s, s, 1, + image->getPixelFormat(), image->getDataType(), + image->getPacking()); + destination->setInternalTextureFormat(image->getInternalTextureFormat()); + + T* srcdata = (T*)image->data(); + T* dstdata = (T*)destination->data(); + + for (unsigned int y = 0; y < s; ++y) + { + for (unsigned int x = 0; x < s; ++x) + { + for (unsigned int p = 0; p < bpp; p++) + dstdata[y * s * bpp + x * bpp + p] = srcdata[x * s * bpp + y * bpp + p]; + } + } + + return destination.release(); + } + else + { + assert(false && "rotateImageImpl: Image must be square."); + return 0; + } +} + +/** Rotates an osg::Image by 90 degrees. Returns a new osg::Image, be sure to + store it in a ref_ptr so it will be freed correctly. */ +osg::Image* rotateImage(osg::Image* image) +{ + if (image->getDataType() == GL_UNSIGNED_BYTE) + { + return rotateImageImpl(image); + } + else + { + assert(false && "rotateImage not implemented for this data type"); + return 0; + } +} + + + +// SOURCE +// +---+---+---+ +// | 1 | 2 | 3 | +// +---+---+---+ +// | 4 | | 5 | +// +---+---+---+ +// | 6 | 7 | 8 | +// +---+---+---+ + + +// FINAL +// +---+---+---+---+---+---+---+---+ +// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +// +---+---+---+---+---+---+---+---+ + +// 1. Upper-Left corner. +// 2. Top border (rotated 90 degrees CCW). +// 3. Upper-Right corner. +// 4. Left border. +// 5. Right border. +// 6. Bottom-Left corner. +// 7. Bottom border (rotated 90 degrees CCW). +// 8. Bottom-Right corner. + +osg::Image* createNatifEdgeImageFromTheme(osg::Image* theme) +{ + if (!theme) { + osg::notify(osg::WARN) << "can't create a natif edge image from null image theme as argument" << std::endl; + return 0; + } + osg::ref_ptr final = new osg::Image; + const int s = theme->s(); + const int t = theme->t(); + const GLenum pixelFormat = theme->getPixelFormat(); + const GLenum dataType = theme->getDataType(); + const GLint internalFormat = theme->getInternalTextureFormat(); + unsigned int packing = theme->getPacking(); + + if (s != t) + { + osg::notify(osg::WARN) << "width and height are different, bad format theme image " << theme->getFileName() << std::endl; + return 0; + } + + // check size + int ceilvalue = static_cast(ceil(s * 1.0 / 3)); + int intvalue = s/3; + if (intvalue != ceilvalue) + { + osg::notify(osg::WARN) << "the size of theme file " << theme->getFileName() << " can not be divided by 3, check the documentation about theme format" << std::endl; + return 0; + } + + const unsigned int one_third_s = s/3; + const unsigned int one_third_t = t/3; + + final->allocateImage(8 * one_third_s , one_third_t, 1, pixelFormat, dataType, packing); + final->setInternalTextureFormat(internalFormat); + + // copy 1 (6 in source) + copyData(theme, 0, 2 * one_third_s, one_third_s, 3 * one_third_s, final.get(), 0, 0); + + // rotate and copy 2 + osg::ref_ptr rotateandcopy2 = new osg::Image; + rotateandcopy2->allocateImage(one_third_s , one_third_t, 1, pixelFormat, dataType, packing); + rotateandcopy2->setInternalTextureFormat(internalFormat); + copyData(theme, one_third_s, 0, 2 * one_third_s , one_third_s, rotateandcopy2.get(), 0, 0); + rotateandcopy2 = rotateImage(rotateandcopy2.get()); + rotateandcopy2->flipHorizontal(); + copyData(rotateandcopy2.get(), 0, 0, one_third_s , one_third_s, final.get(), 6*one_third_s, 0); + + // copy 3 (8 in source) + copyData(theme, 2*one_third_s , 2 *one_third_s, 3*one_third_s , 3 * one_third_s, final.get(), 2 * one_third_s, 0); + + // copy 4 + copyData(theme, 0, one_third_s, one_third_s , 2 * one_third_s, final.get(), 3 * one_third_s, 0); + + // copy 5 + copyData(theme, 2*one_third_s , one_third_s, 3 * one_third_s , 2 * one_third_s, final.get(), 4 * one_third_s, 0); + + // copy 6 (1 in source) + copyData(theme, 0 , 0, one_third_s, one_third_s, final.get(), 5 * one_third_s, 0); + + // rotate and copy 7 + osg::ref_ptr rotateandcopy7 = new osg::Image; + rotateandcopy7->allocateImage(one_third_s , one_third_t, 1, pixelFormat, dataType, packing); + rotateandcopy7->setInternalTextureFormat(internalFormat); + copyData(theme, one_third_s, 2*one_third_s, 2 * one_third_s , 3 * one_third_s, rotateandcopy7.get(), 0, 0); + rotateandcopy7 = rotateImage(rotateandcopy7.get()); + rotateandcopy7->flipHorizontal(); + copyData(rotateandcopy7.get(), 0, 0, one_third_s , one_third_s, final.get(), one_third_s, 0); + + // copy 8 (3 in source) + copyData(theme, 2 * one_third_s, 0, 3 * one_third_s , one_third_s , final.get(), 7 * one_third_s, 0); + + return final.release(); +} } diff --git a/src/osgWidget/Input.cpp b/src/osgWidget/Input.cpp index 830e6f652..d5c6bd857 100644 --- a/src/osgWidget/Input.cpp +++ b/src/osgWidget/Input.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Input.cpp 65 2008-07-14 16:29:28Z cubicool $ #include #include @@ -22,7 +21,7 @@ _cursor (new Widget("cursor")) { // Make the cursor un-copyable. _cursor->setCanClone(false); _cursor->setDataVariance(osg::Object::DYNAMIC); - _cursor->setColor(0.0f, 0.0f, 0.0f, 0.0f); + _cursor->setColor(0.0f, 0.0f, 0.0f, 1.0f); setEventMask( // For showing/hiding the "cursor." @@ -46,9 +45,9 @@ void Input::_calculateSize(const XYCoord& size) { point_type width = size.x() + _cursor->getWidth(); point_type height = _cursor->getHeight(); - if(width > getWidth()) setWidth(osg::round(width)); + // if(width > getWidth()) setWidth(osg::round(width)); - if(height > getHeight()) setHeight(osg::round(height)); + // if(height > getHeight()) setHeight(osg::round(height)); } void Input::_calculateCursorOffsets() { @@ -59,28 +58,22 @@ void Input::_calculateCursorOffsets() { const osgText::Text::GlyphQuads& gq = tgqmi->second; - point_type accum = 0.0f; + osg::Vec3 pos = _text->getPosition(); - std::ostream& os = warn() << "_offsets[ "; - for(unsigned int i = 0; i < _maxSize; i++) { - osg::Vec2 ul = gq.getCoords()[0 + (i * 4)]; - osg::Vec2 ll = gq.getCoords()[1 + (i * 4)]; - osg::Vec2 lr = gq.getCoords()[2 + (i * 4)]; - osg::Vec2 ur = gq.getCoords()[3 + (i * 4)]; + osg::Vec3 ul = gq.getTransformedCoords(0)[0 + (i * 4)]; + osg::Vec3 ll = gq.getTransformedCoords(0)[1 + (i * 4)]; + osg::Vec3 lr = gq.getTransformedCoords(0)[2 + (i * 4)]; + osg::Vec3 ur = gq.getTransformedCoords(0)[3 + (i * 4)]; - accum += osg::round(lr.x() - ll.x()); - - _offsets[i] = accum; - - os << _offsets[i] << " (" << static_cast(_text->getText()[i]) << ") "; + _offsets[i] = lr.x() - pos.x(); + + // warn() << "vb: " << gq.getGlyphs()[i]->getHorizontalBearing() << std::endl; } - - os << "]" << std::endl; } bool Input::focus(WindowManager*) { - _cursor->setColor(1.0f, 1.0f, 1.0f, 0.5f); + _cursor->setColor(0.0f, 0.0f, 0.0f, 1.0f); return true; } @@ -112,7 +105,7 @@ void Input::positioned() { ; point_type x = getX() + _xoff; - point_type y = getY() + th + _yoff; + point_type y = getY() + _yoff; // XYCoord size = getTextSize(); @@ -129,7 +122,6 @@ bool Input::keyUp(int key, int mask, WindowManager*) { } bool Input::keyDown(int key, int mask, WindowManager*) { - /* osgText::String& s = _text->getText(); if(key == osgGA::GUIEventAdapter::KEY_BackSpace) { @@ -166,16 +158,30 @@ bool Input::keyDown(int key, int mask, WindowManager*) { _calculateSize(getTextSize()); getParent()->resize(); - */ - - warn() << "Input is disabled until someone can help me understand how to use osgText; sorry..." << std::endl; return false; } -void Input::setCursor(Widget*) -{ - warn() << "Input::setCursor(Widget*) not implemented yet."<getCharacterHeight(), _text->getCharacterHeight()); + + osgText::String utf(s); + + unsigned int descent = 0; + + for(osgText::String::iterator i = utf.begin(); i != utf.end(); i++) { + osgText::Font* font = const_cast(_text->getFont()); + osgText::Font::Glyph* glyph = font->getGlyph(fr, *i); + unsigned int d = abs(glyph->getHorizontalBearing().y()); + + if(d > descent) descent = d; + } + + return descent; } } + diff --git a/src/osgWidget/Label.cpp b/src/osgWidget/Label.cpp index 2da44f1ae..ce5f7c69f 100644 --- a/src/osgWidget/Label.cpp +++ b/src/osgWidget/Label.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Label.cpp 59 2008-05-15 20:55:31Z cubicool $ #include #include @@ -9,12 +8,17 @@ namespace osgWidget { Label::Label(const std::string& name, const std::string& label): Widget (name, 0, 0), -_textIndex (0), -_text (new osgText::Text()) { - _text->setText(label); +_text (new osgText::Text()), +_textIndex (0) { _text->setAlignment(osgText::Text::LEFT_BOTTOM); _text->setDataVariance(osg::Object::DYNAMIC); + if(label.size()) { + _text->setText(label); + + _calculateSize(getTextSize()); + } + // TODO: Make a patch for this! // If you're wondering why we don't use this let me explain... // @@ -36,7 +40,7 @@ _textIndex (label._textIndex) { } void Label::_calculateSize(const XYCoord& size) { - if(size.x() && size.y()) setMinimumSize(size.x(), size.y()); + // if(size.x() && size.y()) setMinimumSize(size.x(), size.y()); if(getWidth() < size.x()) setWidth(size.x()); @@ -45,8 +49,15 @@ void Label::_calculateSize(const XYCoord& size) { // TODO: This will almost certainly get out of sync. :( void Label::parented(Window* parent) { - // If we've been cloned, use the index of the old text Drawable. - if(_textIndex) parent->getGeode()->setDrawable(_textIndex, _text.get()); + osg::Geode* geode = parent->getGeode(); + + // If we've been cloned, use the index of the old text Drawable if it's already there. + // However, we have a problem here: imagine a Label gets cloned AFTER being added to + // a Window; it'll have a _textIndex, but that _textIndex won't apply to the + // currently cloned object. In this case, we'll need to check to be SURE. + osgText::Text* text = dynamic_cast(geode->getDrawable(_textIndex)); + + if(text) parent->getGeode()->setDrawable(_textIndex, _text.get()); // Otherwise, add it as new. else _textIndex = parent->addDrawableAndGetIndex(_text.get()); @@ -58,33 +69,16 @@ void Label::unparented(Window* parent) { _textIndex = 0; } -void Label::managed(WindowManager* wm) { - if(wm->isInvertedY()) { - // We rotate along our X axis, so we need to make sure and translate the - // text later to preserve centering. - _text->setAxisAlignment(osgText::Text::USER_DEFINED_ROTATION); - _text->setRotation(osg::Quat( - osg::DegreesToRadians(180.0f), - osg::Vec3(1.0f, 0.0f, 0.0f) - )); - } -} - void Label::positioned() { XYCoord size = getTextSize(); point_type x = osg::round(((getWidth() - size.x()) / 2.0f) + getX()); - point_type y = 0.0f; + point_type y = osg::round(((getHeight() - size.y()) / 2.0f) + getY()); + point_type z = _calculateZ(getLayer() + 1); - if(getWindowManager() && getWindowManager()->isInvertedY()) y = - osg::round(((getHeight() - size.y()) / 2.0f) + getY() + size.y()) - ; - - else y = osg::round(((getHeight() - size.y()) / 2.0f) + getY()); - // These values are permisable with CENTER_CENTER mode is active. // point_type x = round(getX() + (getWidth() / 2.0f)); // point_type y = round(getY() + (getHeight() / 2.0f)); - + /* warn() << "Label widget size : " << getWidth() << " x " << getHeight() << std::endl; warn() << "Label widget tsize: " << getWidthTotal() << " x " << getHeightTotal() << std::endl; @@ -94,12 +88,18 @@ void Label::positioned() { warn() << "------------------------------------" << std::endl; */ - _text->setPosition(osg::Vec3(x, y, _calculateZ(getLayer() + 1))); -} + const WindowManager* wm = _getWindowManager(); -void Label::update() -{ - warn() << "Label::update() not implemented yet."<isUsingRenderBins()) { + _text->getOrCreateStateSet()->setRenderBinDetails( + static_cast(z * OSGWIDGET_RENDERBIN_MOD), + "RenderBin" + ); + + z = 0.0f; + } + + _text->setPosition(osg::Vec3(x, y, z)); } void Label::setLabel(const std::string& label) { diff --git a/src/osgWidget/Lua.cpp b/src/osgWidget/Lua.cpp index 6d63071bd..3fa9c7d9c 100644 --- a/src/osgWidget/Lua.cpp +++ b/src/osgWidget/Lua.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Lua.cpp 2 2008-01-24 16:11:26Z cubicool $ #include #include diff --git a/src/osgWidget/Python.cpp b/src/osgWidget/Python.cpp index 2771491ca..979d631d3 100644 --- a/src/osgWidget/Python.cpp +++ b/src/osgWidget/Python.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Python.cpp 59 2008-05-15 20:55:31Z cubicool $ // Python.h needs to be included before anything else. #ifdef OSGWIDGET_USEPYTHON @@ -172,7 +171,7 @@ bool PythonEngine::runFile(const std::string& filePath) { return false; } - FILE* f = osgDB::fopen(filePath.c_str(), "r"); + FILE* f = fopen(filePath.c_str(), "r"); PyObject* r = PyRun_File(f, filePath.c_str(), Py_file_input, _data->main, _data->main); fclose(f); diff --git a/src/osgWidget/StyleManager.cpp b/src/osgWidget/StyleManager.cpp index e9f3b39c2..0aeb4c8b9 100644 --- a/src/osgWidget/StyleManager.cpp +++ b/src/osgWidget/StyleManager.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: StyleManager.cpp 55 2008-05-12 19:14:42Z cubicool $ #include #include diff --git a/src/osgWidget/Table.cpp b/src/osgWidget/Table.cpp index 25e37a757..a1240e541 100644 --- a/src/osgWidget/Table.cpp +++ b/src/osgWidget/Table.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Table.cpp 48 2008-05-05 14:13:20Z cubicool $ #include diff --git a/src/osgWidget/Util.cpp b/src/osgWidget/Util.cpp index 3179103a8..fec924256 100644 --- a/src/osgWidget/Util.cpp +++ b/src/osgWidget/Util.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: Util.cpp 59 2008-05-15 20:55:31Z cubicool $ #include @@ -36,14 +35,6 @@ std::string generateRandomName(const std::string& base) { return ss.str(); } -osg::Matrix createInvertedYOrthoProjectionMatrix(matrix_type width, matrix_type height) { - osg::Matrix m = osg::Matrix::ortho2D(0.0f, width, 0.0f, height); - osg::Matrix s = osg::Matrix::scale(1.0f, -1.0f, 1.0f); - osg::Matrix t = osg::Matrix::translate(0.0f, -height, 0.0f); - - return t * s * m; -} - osg::Camera* createOrthoCamera(matrix_type width, matrix_type height) { osg::Camera* camera = new osg::Camera(); @@ -61,20 +52,12 @@ osg::Camera* createOrthoCamera(matrix_type width, matrix_type height) { return camera; } -osg::Camera* createInvertedYOrthoCamera(matrix_type width, matrix_type height) { - osg::Camera* camera = createOrthoCamera(width, height); +int createExample(osgViewer::Viewer& viewer, WindowManager* wm, osg::Node* node) { + if(!wm) return 1; - camera->setProjectionMatrix(createInvertedYOrthoProjectionMatrix(width, height)); - - return camera; -} - -osg::Group* _createExampleCommon(osgViewer::View* view, WindowManager* wm, osg::Node* node) { - if(!wm) return 0; - - view->setUpViewInWindow( - 0, - 0, + viewer.setUpViewInWindow( + 50, + 50, static_cast(wm->getWidth()), static_cast(wm->getHeight()) ); @@ -86,87 +69,23 @@ osg::Group* _createExampleCommon(osgViewer::View* view, WindowManager* wm, osg:: if(node) group->addChild(node); - view->addEventHandler(new osgWidget::MouseHandler(wm)); - view->addEventHandler(new osgWidget::KeyboardHandler(wm)); - view->addEventHandler(new osgWidget::ResizeHandler(wm, camera)); - view->addEventHandler(new osgViewer::StatsHandler()); - view->addEventHandler(new osgViewer::WindowSizeHandler()); - view->addEventHandler(new osgGA::StateSetManipulator( - view->getCamera()->getOrCreateStateSet() + viewer.addEventHandler(new osgWidget::MouseHandler(wm)); + viewer.addEventHandler(new osgWidget::KeyboardHandler(wm)); + viewer.addEventHandler(new osgWidget::ResizeHandler(wm, camera)); + viewer.addEventHandler(new osgWidget::CameraSwitchHandler(wm, camera)); + viewer.addEventHandler(new osgViewer::StatsHandler()); + viewer.addEventHandler(new osgViewer::WindowSizeHandler()); + viewer.addEventHandler(new osgGA::StateSetManipulator( + viewer.getCamera()->getOrCreateStateSet() )); wm->resizeAllWindows(); - - return group; -} - -int createExample(osgViewer::Viewer& viewer, WindowManager* wm, osg::Node* node) { - osg::Group* group = _createExampleCommon(&viewer, wm, node); viewer.setSceneData(group); return viewer.run(); } -// TODO: This function is totally broken; I don't really have any idea of how to do this. -// Incredibly frustrating stuff. -int createCompositeExample( - osgViewer::CompositeViewer& viewer, - osgViewer::View* view, - WindowManager* wm, - osg::Node* node -) { - osg::Group* group = _createExampleCommon(view, wm, node); - osg::MatrixTransform* watcher = new osg::MatrixTransform(); - - watcher->addChild(wm); - - // Setup the main 2D view. - viewer.addView(view); - - view->setSceneData(group); - - // The view that "watches" the main view. - osgViewer::View* viewWatcher = new osgViewer::View(); - - viewer.addView(viewWatcher); - - int w = static_cast(wm->getWidth()); - int h = static_cast(wm->getHeight()); - - viewWatcher->setUpViewInWindow(0, 0, w, h); - - // Setup our parent MatrixTransform so things look right in perspective. - watcher->setMatrix( - osg::Matrix::scale(1.0f, -1.0f, 1000.0f) * - osg::Matrix::rotate(osg::DegreesToRadians(90.0f), osg::Vec3d(1.0f, 0.0f, 0.0f)) - ); - - watcher->getOrCreateStateSet()->setAttributeAndModes( - new osg::Scissor(0, 0, w, h), - osg::StateAttribute::OVERRIDE - ); - - osgGA::TrackballManipulator* tb = new osgGA::TrackballManipulator(); - - warn() << watcher->getMatrix() << std::endl; - - /* - const osg::BoundingSphere& bs = watcher->getBound(); - - tb->setHomePosition( - bs.center() + osg::Vec3(0.0f, -3.5f * bs.radius(), 0.0f), - bs.center(), - osg::Vec3(0.0f, 1.0f, 0.0f) - ); - */ - - viewWatcher->setSceneData(watcher); - viewWatcher->setCameraManipulator(tb); - - return viewer.run(); -} - bool writeWindowManagerNode(WindowManager* wm) { osgDB::writeNodeFile(*wm->getParent(0), "osgWidget.osg"); diff --git a/src/osgWidget/ViewerEventHandlers.cpp b/src/osgWidget/ViewerEventHandlers.cpp index 2724581e5..bee952d0f 100644 --- a/src/osgWidget/ViewerEventHandlers.cpp +++ b/src/osgWidget/ViewerEventHandlers.cpp @@ -1,5 +1,4 @@ // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 -// $Id: ViewerEventHandlers.cpp 59 2008-05-15 20:55:31Z cubicool $ #include @@ -175,16 +174,87 @@ bool ResizeHandler::handle( osg::Matrix::value_type w = gea.getWindowWidth(); osg::Matrix::value_type h = gea.getWindowHeight(); - if(_wm->isInvertedY()) _camera->setProjectionMatrix( - createInvertedYOrthoProjectionMatrix(w, h) - ); + if(_camera.valid()) { + _camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0f, w, 0.0f, h)); - else _camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0f, w, 0.0f, h)); + _wm->setSize(w, h); + } - _wm->setSize(w, h); + _wm->setWindowSize(w, h); _wm->resizeAllWindows(); return true; } +CameraSwitchHandler::CameraSwitchHandler(WindowManager* wm, osg::Camera* camera): +_wm (wm), +_camera (camera) { +} + +bool CameraSwitchHandler::handle( + const osgGA::GUIEventAdapter& gea, + osgGA::GUIActionAdapter& gaa, + osg::Object* obj, + osg::NodeVisitor* nv +) { + if( + gea.getEventType() != osgGA::GUIEventAdapter::KEYDOWN || + gea.getKey() != osgGA::GUIEventAdapter::KEY_F12 + ) return false; + + osgViewer::View* view = dynamic_cast(&gaa); + + if(!view) return false; + + osg::Node* oldNode = view->getSceneData(); + + osg::MatrixTransform* oldTrans = dynamic_cast(oldNode); + + if(!oldTrans) { + // Imagine this is the number of pixels... + double scale = 2000.0f; + double width = _wm->getWidth(); + double height = _wm->getHeight(); + + _oldNode = oldNode; + + osg::MatrixTransform* mt = new osg::MatrixTransform(); + + mt->setMatrix( + osg::Matrix::translate(width / 2.0f, 0.0f, 0.0f) * + osg::Matrix::scale(1.0f, 1.0f, scale) * + osg::Matrix::rotate(osg::DegreesToRadians(45.0f), 0.0f, 1.0f, 0.0f) + ); + + mt->addChild(_wm.get()); + mt->getOrCreateStateSet()->setMode( + GL_LIGHTING, + osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF + ); + mt->getOrCreateStateSet()->setMode( + GL_SCISSOR_TEST, + osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF + ); + + osgGA::MatrixManipulator* mm = view->getCameraManipulator(); + + // mm->setDistance(3000.0f); + // mm->setMinimumZoomScale(10.0f); + mm->setHomePosition( + // eye + osg::Vec3(width / 2.0f, height, 100.0f), + // center + osg::Vec3(0.0f, 0.0f, -(scale / 2.0f)), + // up + osg::Vec3(0.0f, 1.0f, 0.0f) + ); + + view->setSceneData(mt); + } + + else view->setSceneData(_oldNode.get()); + + return true; +} + } diff --git a/src/osgWidget/Widget.cpp b/src/osgWidget/Widget.cpp index 896c3c880..7d3e80fae 100644 --- a/src/osgWidget/Widget.cpp +++ b/src/osgWidget/Widget.cpp @@ -3,8 +3,7 @@ #include #include -#include -#include +#include #include #include #include @@ -34,8 +33,8 @@ _canFill (false), _canClone (true), _isManaged (false), _isStyled (false), -_minWidth (w), -_minHeight (h) { +_minWidth (0.0f), +_minHeight (0.0f) { _name = name.size() ? name : generateRandomName("Widget"); if(!_norms.valid()) { @@ -63,9 +62,6 @@ _minHeight (h) { setDimensions(0.0f, 0.0f, w, h); setColor(1.0f, 1.0f, 1.0f, 1.0f); - - getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); - getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } Widget::Widget(const Widget& widget, const osg::CopyOp& co): @@ -108,26 +104,13 @@ WindowManager* Widget::_getWindowManager() const { } osg::Image* Widget::_getImage() const { - const osg::Texture2D* texture = _texture(); + const osg::Texture* texture = _texture(); if(texture) return const_cast(texture->getImage(0)); return 0; } -void Widget::managed(WindowManager* wm) { - if(!wm->isInvertedY()) return; - - osg::Matrix s = osg::Matrix::scale(1.0f, -1.0f, 1.0f); - osg::Matrix t = osg::Matrix::translate(0.0f, -1.0, 0.0f); - - getOrCreateStateSet()->setTextureAttributeAndModes( - 0, - new osg::TexMat(t * s), - osg::StateAttribute::ON - ); -} - void Widget::setDimensions(point_type x, point_type y, point_type w, point_type h, point_type z) { if(w != -1.0f && w < _minWidth) { warn() @@ -205,6 +188,14 @@ void Widget::setDimensions(point_type x, point_type y, point_type w, point_type } } + const WindowManager* wm = _getWindowManager(); + + if(wm && wm->isUsingRenderBins()) { + getOrCreateStateSet()->setRenderBinDetails(static_cast(z), "RenderBin"); + + z = 0.0f; + } + (*verts)[LL].set(x, y, z); (*verts)[LR].set(x + w, y, z); (*verts)[UR].set(x + w, y + h, z); @@ -221,7 +212,7 @@ void Widget::setColor(color_type r, color_type g, color_type b, color_type a, Co (*cols)[UL].set(r, g, b, a); } - else (*cols)[convertCorner(p)].set(r, g, b, a); + else (*cols)[p].set(r, g, b, a); } void Widget::addColor(color_type r, color_type g, color_type b, color_type a, Corner p) { @@ -234,7 +225,7 @@ void Widget::addColor(color_type r, color_type g, color_type b, color_type a, Co (*cols)[UL] += Color(r, g, b, a); } - else (*cols)[convertCorner(p)] += Color(r, g, b, a); + else (*cols)[p] += Color(r, g, b, a); } void Widget::setTexCoord(texcoord_type tx, texcoord_type ty, Corner p) { @@ -247,7 +238,15 @@ void Widget::setTexCoord(texcoord_type tx, texcoord_type ty, Corner p) { (*texs)[UL].set(tx, ty); } - else (*texs)[convertCorner(p)].set(tx, ty); + else (*texs)[p].set(tx, ty); +} + +// TODO: We chop off any offset here if you use TOP; we need to do the same +// for BG, etc. +void Widget::setLayer(Layer layer, unsigned int offset) { + if(layer == LAYER_TOP) offset = 0; + + _layer = layer + offset; } void Widget::setTexCoordRegion(point_type x, point_type y, point_type w, point_type h) { @@ -263,27 +262,27 @@ void Widget::setTexCoordRegion(point_type x, point_type y, point_type w, point_t // Set the LOWER_LEFT point. XYCoord t(x / tw, y / tw); - (*texs)[UL] = t; + (*texs)[LL] = t; // Set the LOWER_RIGHT point. t += XYCoord(w / tw, 0.0f); - (*texs)[UR] = t; + (*texs)[LR] = t; // Set the UPPER_RIGHT point. t += XYCoord(0.0f, h / th); - (*texs)[LR] = t; + (*texs)[UR] = t; // Set the UPPER_LEFT point. t += XYCoord(-(w / tw), 0.0f); - (*texs)[LL] = t; + (*texs)[UL] = t; } void Widget::setTexCoordWrapHorizontal() { - osg::Image* image = _image(); - osg::Texture2D* texture = _texture(); + osg::Image* image = _image(); + osg::Texture* texture = _texture(); if(!image || !texture || image->s() == 0.0f) return; @@ -294,8 +293,8 @@ void Widget::setTexCoordWrapHorizontal() { } void Widget::setTexCoordWrapVertical() { - osg::Image* image = _image(); - osg::Texture2D* texture = _texture(); + osg::Image* image = _image(); + osg::Texture* texture = _texture(); if(!image || !texture || image->t() == 0.0f) return; @@ -311,35 +310,27 @@ XYCoord Widget::localXY(double _x, double _y) const { return _parent->localXY(_x, _y) - getOrigin(); } -bool Widget::setImage(osg::Image* image, bool setTexCoords) { +bool Widget::setImage(osg::Image* image, bool setTexCoords, bool useTextRect) { if(!image) { warn() << "Widget [" << _name << "] cannot use a NULL image." << std::endl; return false; } - osg::Texture2D* texture = new osg::Texture2D(); + osg::Texture* texture = 0; - texture->setDataVariance(osg::Object::DYNAMIC); + if(useTextRect) texture = new osg::TextureRectangle(); + + else texture = new osg::Texture2D(); + + if(!texture) return false; + texture->setImage(0, image); - getOrCreateStateSet()->setTextureAttributeAndModes( - 0, - texture, - osg::StateAttribute::ON - ); - - if(setTexCoords) { - setTexCoord(0.0f, 0.0f, LOWER_LEFT); - setTexCoord(1.0f, 0.0f, LOWER_RIGHT); - setTexCoord(1.0f, 1.0f, UPPER_RIGHT); - setTexCoord(0.0f, 1.0f, UPPER_LEFT); - } - - return true; + return setTexture(texture, setTexCoords, useTextRect); } -bool Widget::setImage(const std::string& filePath, bool setTexCoords) { +bool Widget::setImage(const std::string& filePath, bool setTexCoords, bool useTextRect) { if(!osgDB::findDataFile(filePath).size()) { warn() << "Widget [" << _name @@ -350,7 +341,37 @@ bool Widget::setImage(const std::string& filePath, bool setTexCoords) { return false; } - return setImage(osgDB::readImageFile(filePath), setTexCoords); + return setImage(osgDB::readImageFile(filePath), setTexCoords, useTextRect); +} + +bool Widget::setTexture(osg::Texture* texture, bool setTexCoords, bool useTextRect) { + if(!texture) return false; + + getOrCreateStateSet()->setTextureAttributeAndModes( + 0, + texture, + osg::StateAttribute::ON + ); + + if(setTexCoords) { + if(useTextRect) { + osg::Image* image = texture->getImage(0); + + setTexCoord(0.0f, 0.0f, LOWER_LEFT); + setTexCoord(image->s(), 0.0f, LOWER_RIGHT); + setTexCoord(image->s(), image->t(), UPPER_RIGHT); + setTexCoord(0.0f, image->t(), UPPER_LEFT); + } + + else { + setTexCoord(0.0f, 0.0f, LOWER_LEFT); + setTexCoord(1.0f, 0.0f, LOWER_RIGHT); + setTexCoord(1.0f, 1.0f, UPPER_RIGHT); + setTexCoord(0.0f, 1.0f, UPPER_LEFT); + } + } + + return true; } void Widget::setPadding(point_type pad) { @@ -451,7 +472,7 @@ const Point& Widget::getPoint(Corner p) const { if(p == ALL_CORNERS) point = UPPER_LEFT; - return (*_verts())[convertCorner(point)]; + return (*_verts())[point]; } const Color& Widget::getColor(Corner p) const { @@ -459,7 +480,7 @@ const Color& Widget::getColor(Corner p) const { if(p == ALL_CORNERS) point = UPPER_LEFT; - return (*_cols())[convertCorner(point)]; + return (*_cols())[point]; } const TexCoord& Widget::getTexCoord(Corner p) const { @@ -467,25 +488,7 @@ const TexCoord& Widget::getTexCoord(Corner p) const { if(p == ALL_CORNERS) point = UPPER_LEFT; - return (*_texs())[convertCorner(point)]; -} - -// This converts our points back and forth depding on whether or not we're in an -// inverted-Y WindowManager. -Widget::Corner Widget::convertCorner(Corner p) const { - const WindowManager* wm = getWindowManager(); - - if(!wm || !wm->isInvertedY()) return p; - - if(p == UPPER_LEFT) return LOWER_LEFT; - - else if(p == UPPER_RIGHT) return LOWER_RIGHT; - - else if(p == LOWER_LEFT) return UPPER_LEFT; - - else if(p == LOWER_RIGHT) return UPPER_RIGHT; - - else return p; + return (*_texs())[point]; } Color Widget::getImageColorAtXY(point_type x, point_type y) const { diff --git a/src/osgWidget/Window.cpp b/src/osgWidget/Window.cpp index bdded05f1..36689a5e4 100644 --- a/src/osgWidget/Window.cpp +++ b/src/osgWidget/Window.cpp @@ -70,7 +70,11 @@ void Window::EmbeddedWindow::parented(Window* parent) { } void Window::EmbeddedWindow::unparented(Window*) { - // TODO: Figure out what's necessary here... + if(_window.valid()) { + _window->_parent = 0; + + if(_parent) _parent->removeChild(_window.get()); + } } void Window::EmbeddedWindow::managed(WindowManager* wm) { @@ -95,6 +99,8 @@ void Window::EmbeddedWindow::positioned() { // If the widget is fillable, ask the internal Window to resize itself. // Whether or not the Window honors this reqest will be up to it. _window->setOrigin(x, y); + _window->setZ(_calculateZ(getLayer() + 1)); + _window->setZRange(_calculateZ(LAYER_TOP - (getLayer() + 1))); _window->setVisibleArea(0, 0, static_cast(w), static_cast(h)); _window->resize(w, h); } @@ -109,7 +115,6 @@ bool Window::EmbeddedWindow::setWindow(Window* win) { return false; } - // TODO: I need to handle there already being a Window here. _window = win; _window->resize(); @@ -124,21 +129,27 @@ bool Window::EmbeddedWindow::setWindow(Window* win) { return true; } +void Window::EmbeddedWindow::updateSizeFromWindow() { + setSize(_window->getSize()); + + if(_parent) _parent->resize(); +} + Window::Window(const std::string& name): -_parent (0), -_wm (0), -_index (0), -_x (0.0f), -_y (0.0f), -_z (0.0f), -_zRange (0.0f), -_strata (STRATA_NONE), -_vis (VM_FULL), -_r (0.0f), -_s (1.0f), -_scaleDenom (100.0f), -_vAnchor (VA_NONE), -_hAnchor (HA_NONE) { +_parent (0), +_wm (0), +_index (0), +_x (0.0f), +_y (0.0f), +_z (0.0f), +_zRange (0.0f), +_strata (STRATA_NONE), +_vis (VM_FULL), +_r (0.0f), +_s (1.0f), +_scaleDenom (100.0f), +_vAnchor (VA_NONE), +_hAnchor (HA_NONE) { _name = name.size() ? name : generateRandomName("Window"); // TODO: Fix the "bg" name. @@ -146,7 +157,7 @@ _hAnchor (HA_NONE) { Widget* bg = new Widget(name + "bg", 0.0f, 0.0f); bg->setLayer(Widget::LAYER_BG); - bg->setColor(0.0f, 0.0f, 0.0f, 0.5f); + bg->setColor(1.0f, 1.0f, 1.0f, 1.0f); _setParented(bg); @@ -201,7 +212,14 @@ _visibleArea (window._visibleArea) { for(unsigned int i = 1; i < geode->getNumDrawables(); i++) { Widget* widget = dynamic_cast(geode->getDrawable(i)); - if(!widget || !widget->canClone()) continue; + if(!widget) continue; + + // TODO: Properly test this... + if(!widget->canClone()) { + // geode->removeDrawable(widget); + + continue; + } _setParented(widget); @@ -286,22 +304,11 @@ bool Window::resizePercent(point_type width, point_type height) { } void Window::update() { - // Update all embedded children; the zRange values continue to decrease in precision - // as you add more and more embedded Windows. WindowList wl; getEmbeddedList(wl); - // Each child Window gets half the zRange of it's parent Window. This means the more - // you embed Windows into other Windows, the less depth precision you're going to have. - for(WindowList::iterator w = wl.begin(); w != wl.end(); w++) { - Window* win = w->get(); - - win->_z = _zRange / 2.0f; - win->_zRange = _zRange / 2.0f; - - win->update(); - } + for(WindowList::iterator w = wl.begin(); w != wl.end(); w++) w->get()->update(); matrix_type x = _x; matrix_type y = _y; @@ -319,6 +326,42 @@ void Window::update() { xy.set(x, y); } + + matrix_type z = _z; + + // We can't do proper scissoring until we have access to our parent WindowManager, and + // we need to determine the sorting method we want to use. + if(_wm) { + if(_wm->isUsingRenderBins()) { + getOrCreateStateSet()->setRenderBinDetails( + static_cast((1.0f - fabs(_z)) * OSGWIDGET_RENDERBIN_MOD), + "RenderBin" + ); + + z = 0.0f; + } + + int sx = static_cast(xy.x()); + int sy = static_cast(xy.y()); + int sw = static_cast(_width.current); + int sh = static_cast(_height.current); + + // This sets the Scissor area to some offset defined by the user. + if(_vis == VM_PARTIAL) { + sw = static_cast(_visibleArea[2]); + sh = static_cast(_visibleArea[3]); + } + + // Otherwise, use the size of the WindowManager itself. + else if(_vis == VM_ENTIRE) { + sx = 0; + sy = 0; + sw = static_cast(_wm->getWidth()); + sh = static_cast(_wm->getHeight()); + } + + _scissor()->setScissor(sx, sy, sw, sh); + } // Update the Window itself, setting it's matrix according to translate, rotate, and // scale values. @@ -326,47 +369,11 @@ void Window::update() { osg::DegreesToRadians(_r), osg::Vec3d(0.0f, 0.0f, 1.0f) ); - + osg::Matrix s = osg::Matrix::scale(_s, _s, 1.0f); - osg::Matrix t = osg::Matrix::translate(x - _visibleArea[0], y - _visibleArea[1], _z); + osg::Matrix t = osg::Matrix::translate(x - _visibleArea[0], y - _visibleArea[1], z); setMatrix(r * s * t); - - // We can't do proper scissoring until we have access to our parent WindowManager. - if(_wm) { - int x = static_cast(xy.x()); - int y = static_cast(xy.y()); - int w = static_cast(_width.current); - int h = static_cast(_height.current); - int wmh = static_cast(_wm->getHeight()); - int nx = x; - int ny = y; - int nw = w; - int nh = h; - - // This sets the Scissor area to the full size of the Window. - if(_vis == VM_FULL && _wm->isInvertedY()) ny = wmh - h - y; - - // This sets the Scissor area to some offset defined by the user. - else if(_vis == VM_PARTIAL) { - if(_wm->isInvertedY()) ny = wmh - y - static_cast(_visibleArea[3]); - - // else ny = static_cast(_visibleArea[3]); - - nw = static_cast(_visibleArea[2]); - nh = static_cast(_visibleArea[3]); - } - - // Otherwise, use the size of the WindowManager itself. - else { - nx = 0; - ny = 0; - nw = static_cast(_wm->getWidth()); - nh = wmh; - } - - _scissor()->setScissor(nx, ny, nw, nh); - } } void Window::_setWidthAndHeightUnknownSizeError(const std::string& size, point_type val) { @@ -526,9 +533,9 @@ void Window::_setParented(Widget* widget, bool setUnparented) { } else { - widget->_parent = 0; - widget->unparented(this); + + widget->_parent = 0; } } @@ -639,6 +646,7 @@ void Window::addVisibleArea(int x, int y, int w, int h) { _visibleArea[3] += h; } +// The topmost Window always has this method called, instead of the embedded window directly. bool Window::setFocused(const Widget* widget) { // TODO: I've turned on the warn() here, but perhaps I shouldn't? I need to define // the conditions under which it's okay to call setFocus() with a NULL widget. @@ -650,7 +658,28 @@ bool Window::setFocused(const Widget* widget) { ConstIterator i = std::find(begin(), end(), widget); + bool found = false; + if(i == end()) { + // We couldn't find the widget in the toplevel, so lets see if one of our + // EmbeddedWindow objects has it. + WindowList wl; + + getEmbeddedList(wl); + + for(WindowList::iterator w = wl.begin(); w != wl.end(); w++) { + ConstIterator ii = std::find(w->get()->begin(), w->get()->end(), widget); + + if(ii != w->get()->end()) { + found = true; + i = ii; + } + } + } + + else found = true; + + if(!found) { warn() << "Window [" << _name << "] couldn't find the Widget [" << widget->getName() @@ -666,9 +695,31 @@ bool Window::setFocused(const Widget* widget) { } bool Window::setFocused(const std::string& name) { - Widget* w = getByName(name); + Widget* w1 = getByName(name); - if(!w) { + bool found = false; + + if(!w1) { + // Just like above, we couldn't find the widget in the toplevel, so lets see if + // one of our EmbeddedWindow objects has it. The difference here is that we + // search by name. + WindowList wl; + + getEmbeddedList(wl); + + for(WindowList::iterator w = wl.begin(); w != wl.end(); w++) { + Widget* w2 = w->get()->getByName(name); + + if(w2) { + found = true; + w1 = w2; + } + } + } + + else found = true; + + if(!found) { warn() << "Window [" << _name << "] couldn't find a Widget named [" << name @@ -678,11 +729,17 @@ bool Window::setFocused(const std::string& name) { return false; } - _setFocused(w); + _setFocused(w1); return true; } +bool Window::grabFocus() { + if(!_wm) return false; + + return _wm->setFocused(this); +} + bool Window::setFirstFocusable() { WidgetList focusList; @@ -724,8 +781,6 @@ XYCoord Window::localXY(double absx, double absy) const { double x = absx - xy.x(); double y = absy - xy.y(); - if(_wm && _wm->isInvertedY()) y = (_wm->getHeight() - absy) - xy.y(); - return XYCoord(x + _visibleArea[0], y + _visibleArea[1]); } @@ -746,13 +801,21 @@ XYCoord Window::getAbsoluteOrigin() const { return xy; } -Window::EmbeddedWindow* Window::embed() { - EmbeddedWindow* ew = new EmbeddedWindow(_name + "Embedded", getWidth(), getHeight()); +Window::EmbeddedWindow* Window::embed( + const std::string& newName, + Widget::Layer layer, + unsigned int layerOffset +) { + EmbeddedWindow* ew = new EmbeddedWindow( + newName.size() > 0 ? newName : _name + "Embedded", + getWidth(), + getHeight() + ); ew->setWindow(this); ew->setSize(getWidth(), getHeight()); - ew->setMinimumSize(getMinWidth(), getMinHeight()); ew->setCanFill(true); + ew->setLayer(layer, layerOffset); return ew; } @@ -779,7 +842,11 @@ bool Window::getEmbeddedList(WindowList& wl) const { if(!ew || !ew->getWindow()) continue; - wl.push_back(ew->getWindow()); + else { + wl.push_back(ew->getWindow()); + + ew->getWindow()->getEmbeddedList(wl); + } } return wl.size() != 0; @@ -852,6 +919,12 @@ unsigned int Window::addDrawableAndGetIndex(osg::Drawable* drawable) { return 0; } +unsigned int Window::addChildAndGetIndex(osg::Node* node) { + if(addChild(node)) return getChildIndex(node); + + return 0; +} + // All of the subsequent functions are very boring and uninteresting, although hopefully // self-explanatory. They simply wrap calls to _compare<>() with the proper templates, and // forward the optional iteration ranges... @@ -945,7 +1018,7 @@ Window::Sizes Window::_getWidthImplementation() const { point_type w = osg::round(bb.xMax() - bb.xMin()); - return Sizes(w, w); + return Sizes(w, 0.0f); } Window::Sizes Window::_getHeightImplementation() const { @@ -953,7 +1026,7 @@ Window::Sizes Window::_getHeightImplementation() const { point_type h = osg::round(bb.yMax() - bb.yMin()); - return Sizes(h, h); + return Sizes(h, 0.0f); } } diff --git a/src/osgWidget/WindowManager.cpp b/src/osgWidget/WindowManager.cpp index 3ff7aa1da..1a3f1db45 100644 --- a/src/osgWidget/WindowManager.cpp +++ b/src/osgWidget/WindowManager.cpp @@ -23,8 +23,8 @@ WindowManager::WindowManager( ): _width (width), _height (height), -_zNear (0.0f), -_zFar (-1.0f), +_windowWidth (width), +_windowHeight (height), _numForeground (0.0f), _numBackground (0.0f), _flags (flags), @@ -56,6 +56,8 @@ _styleManager (new StyleManager()) { if(!_python->initialize()) warn() << "Error creating PythonEngine." << std::endl; } + if(_flags & WM_USE_RENDERBINS) getOrCreateStateSet()->setMode(GL_DEPTH_TEST, false); + // Setup our picking debug (is debug the right word here?) Window... if(_flags & WM_PICK_DEBUG) { _pickWindow = new Box("PickWindow", Box::VERTICAL); @@ -79,28 +81,11 @@ _styleManager (new StyleManager()) { _updatePickWindow(0, 0, 0); } - if(!(_flags & WM_NO_BETA_WARN)) { - Box* box = new Box("BetaWarningBox", Box::VERTICAL); - Label* label = new Label("BetaWarning"); - - label->setFontSize(15); - label->setFontColor(0.0f, 0.0f, 1.0f, 1.0f); - label->setFont("fonts/arial.ttf"); - label->setPadding(5.0f); - label->setCanFill(true); - label->setLabel("This is BETA software! Please see: http://osgwidget.googlecode.com"); - - box->getBackground()->setColor(1.0f, 0.7f, 0.0f, 1.0f); - box->addWidget(label); - box->setNodeMask(~_nodeMask); - box->removeEventMask(EVENT_MASK_FOCUS); - box->setStrata(Window::STRATA_BACKGROUND); - box->setOrigin(0.0f, 0.0f); - - addChild(box); - - box->resizePercent(100.0f, 0.0f); - } + getOrCreateStateSet()->setMode( + GL_BLEND, + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE + ); + getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } WindowManager::WindowManager(const WindowManager& wm, const osg::CopyOp& co): @@ -140,7 +125,8 @@ bool WindowManager::_handleMousePushed(float x, float y, bool& down) { if(!_lastPush) return false; - bool handled = _lastPush->callMethodAndCallbacks(ev); + // TODO: This is the old way; it didn't allow Event handler code to call grabFocus(). + // bool handled = _lastPush->callMethodAndCallbacks(ev); if(_focusMode != PFM_SLOPPY) { if(ev._window) { @@ -155,7 +141,7 @@ bool WindowManager::_handleMousePushed(float x, float y, bool& down) { else if(_focusMode == PFM_UNFOCUS) setFocused(0); } - return handled; + return _lastPush->callMethodAndCallbacks(ev); } bool WindowManager::_handleMouseReleased(float x, float y, bool& down) { @@ -181,10 +167,7 @@ bool WindowManager::_handleMouseReleased(float x, float y, bool& down) { void WindowManager::_getPointerXYDiff(float& x, float& y) { x -= _lastX; - - if(isInvertedY()) y = -(y - _lastY); - - else y -= _lastY; + y -= _lastY; } void WindowManager::_updatePickWindow(const WidgetList* wl, point_type x, point_type y) { @@ -299,9 +282,10 @@ bool WindowManager::pickAtXY(float x, float y, WidgetList& wl) { // Make sure that our window is valid, and that our pick is within the // "visible area" of the Window. - if(!win || - (win->getVisibilityMode()==Window::VM_PARTIAL && !win->isPointerXYWithinVisible(x, y))) - { + if( + !win || + (win->getVisibilityMode() == Window::VM_PARTIAL && !win->isPointerXYWithinVisible(x, y)) + ) { continue; } @@ -334,6 +318,49 @@ bool WindowManager::pickAtXY(float x, float y, WidgetList& wl) { return false; } +/* +bool WindowManager::pickAtXY(float x, float y, WidgetList& wl) { + Intersections intr; + + if(!_view->computeIntersections(x, y, intr, _nodeMask)) return false; + + typedef std::vector > WindowVector; + + WindowVector windows; + + Window* activeWin = 0; + + for(Intersections::iterator i = intr.begin(); i != intr.end(); i++) { + Window* win = dynamic_cast(i->nodePath.back()->getParent(0)); + + if( + !win || + (win->getVisibilityMode() == Window::VM_PARTIAL && !win->isPointerXYWithinVisible(x, y)) + ) { + continue; + } + + if(activeWin != win) { + activeWin = win; + + windows.push_back(win); + } + } + + if(!windows.size()) return false; + + std::sort(windows.begin(), windows.end(), WindowBinNumberCompare()); + + for(WindowVector::iterator i = windows.begin(); i != windows.end(); i++) { + warn() << "- " << i->get()->getName() << " " << i->get()->getOrCreateStateSet()->getBinNumber() << std::endl; + } + + warn() << std::endl; + + return false; +} +*/ + bool WindowManager::setFocused(Window* window) { Event ev(this); @@ -371,7 +398,7 @@ bool WindowManager::setFocused(Window* window) { // the Z space allocated to it so that it can properly arrange it's children. We // add 2 additional Windows here for anything that should appear in the background // and foreground areas. - matrix_type zRange = (_zNear - _zFar) / (focusable.size() + 2.0f); + matrix_type zRange = 1.0f / (focusable.size() + 2.0f); // Our offset for the following for() loop. unsigned int i = 3; @@ -457,6 +484,16 @@ void WindowManager::resizeAllWindows(bool visible) { } } +// Returns the application window coordinates of the WindowManager XY position. +XYCoord WindowManager::windowXY(double x, double y) const { + return XYCoord((_windowWidth / _width) * x, (_windowHeight / _height) * y); +} + +// Returns the WindowManager coordinates of the application window XY position. +XYCoord WindowManager::localXY(double x, double y) const { + return XYCoord((_width / _windowWidth) * x, (_height / _windowHeight) * y); +} + // This is called by a ViewerEventHandler/MouseHandler (or whatever) as the pointer moves // around and intersects with objects. It also resets our state data (_widget, _leftDown, // etc.) The return value of this method is mostly useless. @@ -574,11 +611,7 @@ bool WindowManager::keyUp(int key, int mask) { // A convenience wrapper for creating a proper orthographic camera using the current // width and height. osg::Camera* WindowManager::createParentOrthoCamera() { - osg::Camera* camera = 0; - - if(isInvertedY()) camera = createInvertedYOrthoCamera(_width, _height); - - else camera = createOrthoCamera(_width, _height); + osg::Camera* camera = createOrthoCamera(_width, _height); camera->addChild(this);