From c2b77aa08ef7e77b66cdde05b847ab543f99854d Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 15 Jul 2008 17:21:25 +0000 Subject: [PATCH] From Jeremy Moles, import of the osgWidget NodeKit, sourced from the original http://osgwidget.googlecode.com/svn/trunk Notes from Robert Osfield, I've merged osgWidget trunk, and added/changed CMakeLists.txt file to make it suitable for inclusion in the core OSG, and moved imagery/scripts/shaders out into OpenSceneGraph-Data --- examples/CMakeLists.txt | 18 + examples/osgwidgetaddremove/CMakeLists.txt | 9 + .../osgwidgetaddremove/osgwidgetaddremove.cpp | 134 +++ examples/osgwidgetbox/CMakeLists.txt | 9 + examples/osgwidgetbox/osgwidgetbox.cpp | 122 +++ examples/osgwidgetcanvas/CMakeLists.txt | 9 + examples/osgwidgetcanvas/osgwidgetcanvas.cpp | 118 +++ examples/osgwidgetframe/CMakeLists.txt | 9 + examples/osgwidgetframe/osgwidgetframe.cpp | 89 ++ examples/osgwidgetinput/CMakeLists.txt | 9 + examples/osgwidgetinput/osgwidgetinput.cpp | 186 ++++ examples/osgwidgetlabel/CMakeLists.txt | 9 + examples/osgwidgetlabel/osgwidgetlabel.cpp | 120 +++ examples/osgwidgetmenu/CMakeLists.txt | 9 + examples/osgwidgetmenu/osgwidgetmenu.cpp | 129 +++ examples/osgwidgetnotebook/CMakeLists.txt | 9 + .../osgwidgetnotebook/osgwidgetnotebook.cpp | 134 +++ examples/osgwidgetscrolled/CMakeLists.txt | 9 + .../osgwidgetscrolled/osgwidgetscrolled.cpp | 134 +++ examples/osgwidgetshader/CMakeLists.txt | 9 + examples/osgwidgetshader/osgwidgetshader.cpp | 74 ++ examples/osgwidgetstyled/CMakeLists.txt | 9 + examples/osgwidgetstyled/osgwidgetstyled.cpp | 83 ++ examples/osgwidgettable/CMakeLists.txt | 9 + examples/osgwidgettable/osgwidgettable.cpp | 69 ++ examples/osgwidgetversion/CMakeLists.txt | 9 + .../osgwidgetversion/osgwidgetversion.cpp | 14 + examples/osgwidgetwindow/CMakeLists.txt | 9 + examples/osgwidgetwindow/osgwidgetwindow.cpp | 204 ++++ include/osgWidget/Box | 39 + include/osgWidget/Canvas | 28 + include/osgWidget/EventInterface | 376 +++++++ include/osgWidget/Export | 47 + include/osgWidget/Frame | 161 +++ include/osgWidget/Input | 77 ++ include/osgWidget/Label | 59 ++ include/osgWidget/Lua | 31 + include/osgWidget/Python | 28 + include/osgWidget/ScriptEngine | 29 + include/osgWidget/StyleInterface | 39 + include/osgWidget/StyleManager | 175 ++++ include/osgWidget/Table | 63 ++ include/osgWidget/Types | 31 + include/osgWidget/UIObjectParent | 123 +++ include/osgWidget/Util | 79 ++ include/osgWidget/Version | 23 + include/osgWidget/ViewerEventHandlers | 78 ++ include/osgWidget/Widget | 626 ++++++++++++ include/osgWidget/Window | 636 ++++++++++++ include/osgWidget/WindowManager | 358 +++++++ src/CMakeLists.txt | 40 +- src/osgPlugins/CMakeLists.txt | 4 + src/osgPlugins/osgWidget/Box.cpp | 113 +++ src/osgPlugins/osgWidget/CMakeLists.txt | 19 + src/osgPlugins/osgWidget/EmbeddedWindow.cpp | 32 + src/osgPlugins/osgWidget/Frame.cpp | 30 + src/osgPlugins/osgWidget/Input.cpp | 30 + src/osgPlugins/osgWidget/Label.cpp | 30 + src/osgPlugins/osgWidget/Table.cpp | 30 + src/osgPlugins/osgWidget/Widget.cpp | 75 ++ src/osgPlugins/osgWidget/WindowManager.cpp | 30 + src/osgWidget/Box.cpp | 194 ++++ src/osgWidget/CMakeLists.txt | 66 ++ src/osgWidget/Canvas.cpp | 32 + src/osgWidget/Frame.cpp | 251 +++++ src/osgWidget/Input.cpp | 176 ++++ src/osgWidget/Label.cpp | 140 +++ src/osgWidget/Lua.cpp | 171 ++++ src/osgWidget/Python.cpp | 215 ++++ src/osgWidget/StyleManager.cpp | 376 +++++++ src/osgWidget/Table.cpp | 225 ++++ src/osgWidget/Util.cpp | 176 ++++ src/osgWidget/Version.cpp | 83 ++ src/osgWidget/ViewerEventHandlers.cpp | 190 ++++ src/osgWidget/Widget.cpp | 524 ++++++++++ src/osgWidget/Window.cpp | 959 ++++++++++++++++++ src/osgWidget/WindowManager.cpp | 587 +++++++++++ 77 files changed, 9643 insertions(+), 15 deletions(-) create mode 100644 examples/osgwidgetaddremove/CMakeLists.txt create mode 100644 examples/osgwidgetaddremove/osgwidgetaddremove.cpp create mode 100644 examples/osgwidgetbox/CMakeLists.txt create mode 100644 examples/osgwidgetbox/osgwidgetbox.cpp create mode 100644 examples/osgwidgetcanvas/CMakeLists.txt create mode 100644 examples/osgwidgetcanvas/osgwidgetcanvas.cpp create mode 100644 examples/osgwidgetframe/CMakeLists.txt create mode 100644 examples/osgwidgetframe/osgwidgetframe.cpp create mode 100644 examples/osgwidgetinput/CMakeLists.txt create mode 100644 examples/osgwidgetinput/osgwidgetinput.cpp create mode 100644 examples/osgwidgetlabel/CMakeLists.txt create mode 100644 examples/osgwidgetlabel/osgwidgetlabel.cpp create mode 100644 examples/osgwidgetmenu/CMakeLists.txt create mode 100644 examples/osgwidgetmenu/osgwidgetmenu.cpp create mode 100644 examples/osgwidgetnotebook/CMakeLists.txt create mode 100644 examples/osgwidgetnotebook/osgwidgetnotebook.cpp create mode 100644 examples/osgwidgetscrolled/CMakeLists.txt create mode 100644 examples/osgwidgetscrolled/osgwidgetscrolled.cpp create mode 100644 examples/osgwidgetshader/CMakeLists.txt create mode 100644 examples/osgwidgetshader/osgwidgetshader.cpp create mode 100644 examples/osgwidgetstyled/CMakeLists.txt create mode 100644 examples/osgwidgetstyled/osgwidgetstyled.cpp create mode 100644 examples/osgwidgettable/CMakeLists.txt create mode 100644 examples/osgwidgettable/osgwidgettable.cpp create mode 100644 examples/osgwidgetversion/CMakeLists.txt create mode 100644 examples/osgwidgetversion/osgwidgetversion.cpp create mode 100644 examples/osgwidgetwindow/CMakeLists.txt create mode 100644 examples/osgwidgetwindow/osgwidgetwindow.cpp create mode 100644 include/osgWidget/Box create mode 100644 include/osgWidget/Canvas create mode 100644 include/osgWidget/EventInterface create mode 100644 include/osgWidget/Export create mode 100644 include/osgWidget/Frame create mode 100644 include/osgWidget/Input create mode 100644 include/osgWidget/Label create mode 100644 include/osgWidget/Lua create mode 100644 include/osgWidget/Python create mode 100644 include/osgWidget/ScriptEngine create mode 100644 include/osgWidget/StyleInterface create mode 100644 include/osgWidget/StyleManager create mode 100644 include/osgWidget/Table create mode 100644 include/osgWidget/Types create mode 100644 include/osgWidget/UIObjectParent create mode 100644 include/osgWidget/Util create mode 100644 include/osgWidget/Version create mode 100644 include/osgWidget/ViewerEventHandlers create mode 100644 include/osgWidget/Widget create mode 100644 include/osgWidget/Window create mode 100644 include/osgWidget/WindowManager create mode 100644 src/osgPlugins/osgWidget/Box.cpp create mode 100644 src/osgPlugins/osgWidget/CMakeLists.txt create mode 100644 src/osgPlugins/osgWidget/EmbeddedWindow.cpp create mode 100644 src/osgPlugins/osgWidget/Frame.cpp create mode 100644 src/osgPlugins/osgWidget/Input.cpp create mode 100644 src/osgPlugins/osgWidget/Label.cpp create mode 100644 src/osgPlugins/osgWidget/Table.cpp create mode 100644 src/osgPlugins/osgWidget/Widget.cpp create mode 100644 src/osgPlugins/osgWidget/WindowManager.cpp create mode 100644 src/osgWidget/Box.cpp create mode 100644 src/osgWidget/CMakeLists.txt create mode 100644 src/osgWidget/Canvas.cpp create mode 100644 src/osgWidget/Frame.cpp create mode 100644 src/osgWidget/Input.cpp create mode 100644 src/osgWidget/Label.cpp create mode 100644 src/osgWidget/Lua.cpp create mode 100644 src/osgWidget/Python.cpp create mode 100644 src/osgWidget/StyleManager.cpp create mode 100644 src/osgWidget/Table.cpp create mode 100644 src/osgWidget/Util.cpp create mode 100644 src/osgWidget/Version.cpp create mode 100644 src/osgWidget/ViewerEventHandlers.cpp create mode 100644 src/osgWidget/Widget.cpp create mode 100644 src/osgWidget/Window.cpp create mode 100644 src/osgWidget/WindowManager.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 38cd6befb..44a0d23fe 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -149,6 +149,24 @@ IF(DYNAMIC_OPENSCENEGRAPH) ADD_SUBDIRECTORY(osgviewerCocoa) ENDIF(APPLE) + IF (BUILD_OSGWIDGET)) + ADD_SUBDIRECTORY(osgwidgetaddremove) + ADD_SUBDIRECTORY(osgwidgetbox) + ADD_SUBDIRECTORY(osgwidgetcanvas) + ADD_SUBDIRECTORY(osgwidgetframe) + ADD_SUBDIRECTORY(osgwidgetinput) + ADD_SUBDIRECTORY(osgwidgetlabel) + ADD_SUBDIRECTORY(osgwidgetmenu) + ADD_SUBDIRECTORY(osgwidgetnotebook) + ADD_SUBDIRECTORY(osgwidgetscrolled) + ADD_SUBDIRECTORY(osgwidgetshader) + ADD_SUBDIRECTORY(osgwidgetstyled) + ADD_SUBDIRECTORY(osgwidgettable) + ADD_SUBDIRECTORY(osgwidgetversion) + ADD_SUBDIRECTORY(osgwidgetwindow + ENDIF(BUILD_OSGWIDGET) + + #ADD_SUBDIRECTORY(osgcegui) #to add subject to find socket#ADD_SUBDIRECTORY(osgcluster) diff --git a/examples/osgwidgetaddremove/CMakeLists.txt b/examples/osgwidgetaddremove/CMakeLists.txt new file mode 100644 index 000000000..ee761196a --- /dev/null +++ b/examples/osgwidgetaddremove/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetaddremove) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetaddremove osgwidgetaddremove.cpp) + +SET_TARGET_PROPERTIES(osgwidgetaddremove PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetaddremove DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetaddremove/osgwidgetaddremove.cpp b/examples/osgwidgetaddremove/osgwidgetaddremove.cpp new file mode 100644 index 000000000..280aa8d9c --- /dev/null +++ b/examples/osgwidgetaddremove/osgwidgetaddremove.cpp @@ -0,0 +1,134 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetaddremove.cpp 45 2008-04-23 16:46:11Z cubicool $ + +#include +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +class ABCWidget: public osgWidget::Label { +public: + ABCWidget(const std::string& label): + osgWidget::Label("", label) { + setFont("fonts/Calibri1.ttf"); + setFontSize(20); + setCanFill(true); + setShadow(0.08f); + addSize(10.0f, 10.0f); + } +}; + +class Button: public osgWidget::Label { +public: + Button(const std::string& label): + osgWidget::Label("", label) { + setFont("fonts/Calibri1.ttf"); + setFontSize(30); + setColor(0.8f, 0.2f, 0.2f, 0.8f); + setCanFill(true); + setShadow(0.1f); + setEventMask(osgWidget::EVENT_MASK_MOUSE_CLICK); + addSize(20.0f, 20.0f); + } + + // NOTE! I need to make it clearer than Push/Release can happen so fast that + // the changes you make aren't visible with your refresh rate. Throttling state + // changes and what-have-you on mousePush/mouseRelease/etc. is going to be + // annoying... + + virtual bool mousePush(double, double, osgWidget::WindowManager*) { + addColor(0.2f, 0.2f, 0.2f, 0.0f); + + return true; + } + + virtual bool mouseRelease(double, double, osgWidget::WindowManager*) { + addColor(-0.2f, -0.2f, -0.2f, 0.0f); + + return true; + } +}; + +class AddRemove: public osgWidget::Box { + osg::ref_ptr _win1; + +public: + AddRemove(): + osgWidget::Box ("buttons", osgWidget::Box::VERTICAL), + _win1 (new osgWidget::Box("win1", osgWidget::Box::VERTICAL)) { + addWidget(new Button("Add Widget")); + addWidget(new Button("Remove Widget")); + + // Take special note here! Not only do the Button objects have their + // own overridden methods for changing the color, but they have attached + // callbacks for doing the work with local data. + getByName("Widget_1")->addCallback(osgWidget::Callback( + &AddRemove::handlePressAdd, + this, + osgWidget::EVENT_MOUSE_PUSH + )); + + getByName("Widget_2")->addCallback(osgWidget::Callback( + &AddRemove::handlePressRemove, + this, + osgWidget::EVENT_MOUSE_PUSH + )); + } + + virtual void managed(osgWidget::WindowManager* wm) { + osgWidget::Box::managed(wm); + + _win1->setOrigin(250.0f, 0.0f); + + wm->addChild(_win1.get()); + } + + bool handlePressAdd(osgWidget::Event& ev) { + static unsigned int num = 0; + + std::stringstream ss; + + ss << "a random widget " << num; + + _win1->addWidget(new ABCWidget(ss.str())); + _win1->resize(); + + num++; + + return true; + } + + bool handlePressRemove(osgWidget::Event& ev) { + // TODO: Temporary hack! + const osgWidget::Box::Vector& v = _win1->getObjects(); + + if(!v.size()) return false; + + osgWidget::Widget* w = _win1->getObjects()[v.size() - 1].get(); + + _win1->removeWidget(w); + _win1->resize(); + + return true; + } +}; + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D + ); + + osgWidget::Box* buttons = new AddRemove(); + + wm->addChild(buttons); + + return createExample(viewer, wm); +} diff --git a/examples/osgwidgetbox/CMakeLists.txt b/examples/osgwidgetbox/CMakeLists.txt new file mode 100644 index 000000000..b233181f3 --- /dev/null +++ b/examples/osgwidgetbox/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetbox) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetbox osgwidgetbox.cpp) + +SET_TARGET_PROPERTIES(osgwidgetbox PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetbox DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetbox/osgwidgetbox.cpp b/examples/osgwidgetbox/osgwidgetbox.cpp new file mode 100644 index 000000000..fed0ed7d7 --- /dev/null +++ b/examples/osgwidgetbox/osgwidgetbox.cpp @@ -0,0 +1,122 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetbox.cpp 59 2008-05-15 20:55:31Z cubicool $ + +// NOTE: You'll find this example very similar to osgwidgetwindow. However, here we +// demonstrate a bit of subclassing of Widget so that we can respond to events +// such as mouseEnter and mouseLeave. We also demonstrate the use of padding, though +// fill and alignment should be working too. + +#include +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; +const unsigned int MASK_3D = 0x0F000000; + +struct ColorWidget: public osgWidget::Widget { + ColorWidget(): + osgWidget::Widget("", 256.0f, 256.0f) { + } + + bool mouseEnter(double, double, osgWidget::WindowManager*) { + addColor(-osgWidget::Color(0.4f, 0.4f, 0.4f, 0.0f)); + + // osgWidget::warn() << "enter: " << getColor() << std::endl; + + return true; + } + + bool mouseLeave(double, double, osgWidget::WindowManager*) { + addColor(osgWidget::Color(0.4f, 0.4f, 0.4f, 0.0f)); + + // osgWidget::warn() << "leave: " << getColor() << std::endl; + + return true; + } + + bool mouseOver(double x, double y, osgWidget::WindowManager*) { + osgWidget::Color c = getImageColorAtPointerXY(x, y); + + if(c.a() < 0.001f) { + // osgWidget::warn() << "Transparent Pixel: " << x << " " << y << std::endl; + + return false; + } + + return true; + } + + bool keyUp(int key, int keyMask, osgWidget::WindowManager*) { + // osgWidget::warn() << "..." << key << " - " << keyMask << std::endl; + + return true; + } +}; + +osgWidget::Box* createBox(const std::string& name, osgWidget::Box::BOX_TYPE bt) { + osgWidget::Box* box = new osgWidget::Box(name, bt, true); + osgWidget::Widget* widget1 = new osgWidget::Widget(name + "_widget1", 100.0f, 100.0f); + osgWidget::Widget* widget2 = new osgWidget::Widget(name + "_widget2", 100.0f, 100.0f); + osgWidget::Widget* widget3 = new ColorWidget(); + + widget1->setColor(0.3f, 0.3f, 0.3f, 1.0f); + widget2->setColor(0.6f, 0.6f, 0.6f, 1.0f); + + widget3->setImage("osgWidget/natascha.png"); + widget3->setTexCoord(0.0f, 0.0f, osgWidget::Widget::LOWER_LEFT); + widget3->setTexCoord(1.0f, 0.0f, osgWidget::Widget::LOWER_RIGHT); + widget3->setTexCoord(1.0f, 1.0f, osgWidget::Widget::UPPER_RIGHT); + widget3->setTexCoord(0.0f, 1.0f, osgWidget::Widget::UPPER_LEFT); + + box->addWidget(widget1); + box->addWidget(widget2); + box->addWidget(widget3); + + return box; +} + +int main(int argc, char** argv) { + osgViewer::CompositeViewer viewer; + + osgViewer::View* view = new osgViewer::View(); + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + view, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG | + osgWidget::WindowManager::WM_NO_INVERT_Y + ); + + wm->setPointerFocusMode(osgWidget::WindowManager::PFM_SLOPPY); + + osgWidget::Window* box1 = createBox("HBOX", osgWidget::Box::HORIZONTAL); + osgWidget::Window* box2 = createBox("VBOX", osgWidget::Box::VERTICAL); + osgWidget::Window* box3 = createBox("HBOX2", osgWidget::Box::HORIZONTAL); + osgWidget::Window* box4 = createBox("VBOX2", osgWidget::Box::VERTICAL); + + box1->getBackground()->setColor(1.0f, 0.0f, 0.0f, 0.8f); + box1->attachMoveCallback(); + + box2->getBackground()->setColor(0.0f, 1.0f, 0.0f, 0.8f); + box2->attachMoveCallback(); + + box3->getBackground()->setColor(0.0f, 0.0f, 1.0f, 0.8f); + box3->attachMoveCallback(); + + wm->addChild(box1); + wm->addChild(box2); + wm->addChild(box3); + wm->addChild(box4); + + box4->hide(); + + osg::Node* model = osgDB::readNodeFile("spaceship.osg"); + + model->setNodeMask(MASK_3D); + + return osgWidget::createCompositeExample(viewer, view, wm, model); +} diff --git a/examples/osgwidgetcanvas/CMakeLists.txt b/examples/osgwidgetcanvas/CMakeLists.txt new file mode 100644 index 000000000..f6b4424d2 --- /dev/null +++ b/examples/osgwidgetcanvas/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetcanvas) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetcanvas osgwidgetcanvas.cpp) + +SET_TARGET_PROPERTIES(osgwidgetcanvas PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetcanvas DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetcanvas/osgwidgetcanvas.cpp b/examples/osgwidgetcanvas/osgwidgetcanvas.cpp new file mode 100644 index 000000000..fc9f38be9 --- /dev/null +++ b/examples/osgwidgetcanvas/osgwidgetcanvas.cpp @@ -0,0 +1,118 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetcanvas.cpp 33 2008-04-04 19:03:12Z cubicool $ + +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +bool colorWidgetEnter(osgWidget::Event& event) { + event.getWidget()->addColor(0.5f, 0.2f, 0.3f, 0.0f); + + // osgWidget::warn() << "WIDGET mouseEnter " << event.getWidget()->getName() << std::endl; + + return true; +} + +bool colorWidgetLeave(osgWidget::Event& event) { + event.getWidget()->addColor(-0.5f, -0.2f, -0.3f, 0.0f); + + // osgWidget::warn() << "WIDGET mouseLeave" << std::endl; + + return true; +} + +bool windowMouseOver(osgWidget::Event& event) { + osgWidget::XYCoord xy = event.getWindow()->localXY(event.x, event.y); + + // osgWidget::warn() << "WINDOW " << xy.x() << " - " << xy.y() << std::endl; + + return true; +} + +bool widgetMouseOver(osgWidget::Event& event) { + osgWidget::XYCoord xy = event.getWidget()->localXY(event.x, event.y); + + // osgWidget::warn() << "WIDGET mouseOver " << xy.x() << " - " << xy.y() << std::endl; + + return true; +} + +osgWidget::Widget* createWidget( + const std::string& name, + osgWidget::color_type col, + osgWidget::Widget::LAYER layer +) { + osgWidget::Widget* widget = new osgWidget::Widget(name, 200.0f, 200.0f); + + widget->setEventMask(osgWidget::EVENT_ALL); + widget->addCallback(osgWidget::Callback(&colorWidgetEnter, osgWidget::EVENT_MOUSE_PUSH)); + widget->addCallback(osgWidget::Callback(&colorWidgetLeave, osgWidget::EVENT_MOUSE_RELEASE)); + widget->addCallback(osgWidget::Callback(&colorWidgetEnter, osgWidget::EVENT_MOUSE_ENTER)); + widget->addCallback(osgWidget::Callback(&colorWidgetLeave, osgWidget::EVENT_MOUSE_LEAVE)); + widget->addCallback(osgWidget::Callback(&widgetMouseOver, osgWidget::EVENT_MOUSE_OVER)); + widget->setColor(col, col, col, 0.5f); + widget->setLayer(layer); + + return widget; +} + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG + ); + + osgWidget::Canvas* canvas = new osgWidget::Canvas("canvas"); + + canvas->addCallback(osgWidget::Callback(&windowMouseOver, osgWidget::EVENT_MOUSE_OVER)); + canvas->attachMoveCallback(); + canvas->attachRotateCallback(); + canvas->attachScaleCallback(); + + canvas->addWidget( + createWidget("w1", 0.2f, osgWidget::Widget::LAYER_LOW), + 0.0f, + 0.0f + ); + + canvas->addWidget( + createWidget("w2", 0.4f, osgWidget::Widget::LAYER_MIDDLE), + 200.0f, + 0.0f + ); + + canvas->addWidget( + createWidget("w3", 0.6f, osgWidget::Widget::LAYER_HIGH), + 400.0f, + 0.0f + ); + + // Add a child and then resize it relatively to the size of the parent Window. + osgWidget::Widget* relWidget = new osgWidget::Widget("relative"); + + relWidget->setLayer(osgWidget::Widget::LAYER_LOW, 1); + relWidget->setCoordinateMode(osgWidget::Widget::CM_RELATIVE); + relWidget->setSize(0.2f, 0.2f); + relWidget->setColor(0.5f, 0.5f, 0.1f, 0.9f); + + osgWidget::warn() << canvas->getWidth() << std::endl; + + canvas->addWidget(relWidget, 0.4f, 0.4f); + + relWidget->addOrigin(0.1f, 0.1f); + relWidget->addSize(0.2f, 0.2f); + + canvas->resize(); + + // Finally, add the whole thing to the WindowManager. + wm->addChild(canvas); + + return osgWidget::createExample(viewer, wm); +} diff --git a/examples/osgwidgetframe/CMakeLists.txt b/examples/osgwidgetframe/CMakeLists.txt new file mode 100644 index 000000000..2f31b0d72 --- /dev/null +++ b/examples/osgwidgetframe/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetframe) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetframe osgwidgetframe.cpp) + +SET_TARGET_PROPERTIES(osgwidgetframe PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetframe DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetframe/osgwidgetframe.cpp b/examples/osgwidgetframe/osgwidgetframe.cpp new file mode 100644 index 000000000..34fdeb665 --- /dev/null +++ b/examples/osgwidgetframe/osgwidgetframe.cpp @@ -0,0 +1,89 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetframe.cpp 40 2008-04-11 14:05:11Z cubicool $ + +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG + ); + + osgWidget::Frame* frame = osgWidget::Frame::createSimpleFrame( + "frame", + 32.0f, + 32.0f, + 300.0f, + 300.0f + ); + + osgWidget::Table* table = new osgWidget::Table("table", 2, 2); + osgWidget::Box* bottom = new osgWidget::Box("panel", osgWidget::Box::HORIZONTAL); + + table->addWidget(new osgWidget::Widget("red", 300.0f, 300.0f), 0, 0); + table->addWidget(new osgWidget::Widget("white", 300.0f, 300.0f), 0, 1); + table->addWidget(new osgWidget::Widget("yellow", 300.0f, 300.0f), 1, 0); + table->addWidget(new osgWidget::Widget("purple", 300.0f, 300.0f), 1, 1); + table->getByRowCol(0, 0)->setColor(1.0f, 0.0f, 0.0f, 1.0f); + table->getByRowCol(0, 1)->setColor(1.0f, 1.0f, 1.0f, 1.0f); + table->getByRowCol(1, 0)->setColor(1.0f, 1.0f, 0.0f, 1.0f); + table->getByRowCol(1, 1)->setColor(1.0f, 0.0f, 1.0f, 1.0f); + table->getByRowCol(0, 0)->setMinimumSize(100.0f, 100.0f); + table->getByRowCol(0, 1)->setMinimumSize(100.0f, 100.0f); + table->getByRowCol(1, 0)->setMinimumSize(100.0f, 100.0f); + table->getByRowCol(1, 1)->setMinimumSize(100.0f, 100.0f); + + frame->setWindow(table); + + // Give frame some nice textures. + // TODO: This has to be done after setWindow(); wtf? + frame->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.0f); + + osgWidget::Widget* l = frame->getBorder(osgWidget::Frame::BORDER_LEFT); + osgWidget::Widget* r = frame->getBorder(osgWidget::Frame::BORDER_RIGHT); + osgWidget::Widget* t = frame->getBorder(osgWidget::Frame::BORDER_TOP); + osgWidget::Widget* b = frame->getBorder(osgWidget::Frame::BORDER_BOTTOM); + + l->setImage("../examples/osgwidgetframe/images/border-left.tga", true); + r->setImage("../examples/osgwidgetframe/images/border-right.tga", true); + t->setImage("../examples/osgwidgetframe/images/border-top.tga", true); + b->setImage("../examples/osgwidgetframe/images/border-bottom.tga", true); + + l->setTexCoordWrapVertical(); + r->setTexCoordWrapVertical(); + t->setTexCoordWrapHorizontal(); + b->setTexCoordWrapHorizontal(); + + // Create the bottom, XArt panel. + osgWidget::Widget* left = new osgWidget::Widget("left", 512.0f, 256.0f); + osgWidget::Widget* center = new osgWidget::Widget("center", 256.0f, 256.0f); + osgWidget::Widget* right = new osgWidget::Widget("right", 512.0f, 256.0f); + + left->setImage("../examples/osgwidgetframe/images/panel-left.tga", true); + center->setImage("../examples/osgwidgetframe/images/panel-center.tga", true); + right->setImage("../examples/osgwidgetframe/images/panel-right.tga", true); + + center->setTexCoordWrapHorizontal(); + + bottom->addWidget(left); + bottom->addWidget(center); + bottom->addWidget(right); + bottom->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.0f); + bottom->setOrigin(0.0f, 1024.0f - 256.0f); + + // Add everything to the WindowManager. + wm->addChild(frame); + wm->addChild(bottom); + + return osgWidget::createExample(viewer, wm); +} diff --git a/examples/osgwidgetinput/CMakeLists.txt b/examples/osgwidgetinput/CMakeLists.txt new file mode 100644 index 000000000..f5f1f4ce9 --- /dev/null +++ b/examples/osgwidgetinput/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetinput) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetinput osgwidgetinput.cpp) + +SET_TARGET_PROPERTIES(osgwidgetinput PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetinput DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetinput/osgwidgetinput.cpp b/examples/osgwidgetinput/osgwidgetinput.cpp new file mode 100644 index 000000000..411cab766 --- /dev/null +++ b/examples/osgwidgetinput/osgwidgetinput.cpp @@ -0,0 +1,186 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetinput.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include + +#include +#include +#include +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +const char* INFO = + "Use the Input Wigets below to enter the X, Y, and Z position of a\n" + "sphere to be inserted into the scene. Once you've done this, use\n" + "the button below to add it!" +; + +void setupLabel(osgWidget::Label* label) { + label->setFontSize(16); + label->setFontColor(1.0f, 1.0f, 1.0f, 1.0f); + // label->setFont("fonts/monospace.ttf"); + label->setFont("fonts/Calibri1.ttf"); + label->setPadding(2.0f); + label->setHeight(18.0f); + label->setCanFill(true); +} + +osgWidget::Input* createTableRow( + osgWidget::Table* table, + unsigned int rowNum, + const std::string& valName +) { + std::stringstream ssLabel; + std::stringstream ssInput; + + ssLabel << "Label_Row" << rowNum; + ssInput << "Input_Row" << rowNum; + + osgWidget::Label* label = new osgWidget::Label(ssLabel.str(), valName); + osgWidget::Input* input = new osgWidget::Input(ssInput.str(), "", 20); + + setupLabel(label); + setupLabel(input); + + label->setWidth(50.0f); + label->setColor(0.1f, 0.1f, 0.1f, 1.0f); + + input->setWidth(150.0f); + input->setColor(0.4f, 0.4f, 0.4f, 1.0f); + + table->addWidget(label, rowNum, 0); + table->addWidget(input, rowNum, 1); + + return input; +} + +osgWidget::Label* createLabel(const std::string& text) { + osgWidget::Label* label = new osgWidget::Label("", text); + + setupLabel(label); + + return label; +} + +class Button: public osgWidget::Label { +public: + typedef std::vector Inputs; + +private: + Inputs _xyz; + +public: + Button(const std::string& text, const Inputs& inputs): + osgWidget::Label("", text), + _xyz(inputs) { + setupLabel(this); + + setEventMask(osgWidget::EVENT_MASK_MOUSE_CLICK); + setShadow(0.1f); + addHeight(4.0f); + } + + bool mousePush(double, double, osgWidget::WindowManager*) { + osgWidget::warn() + << "x: " << _xyz[0]->getLabel() << std::endl + << "y: " << _xyz[1]->getLabel() << std::endl + << "z: " << _xyz[2]->getLabel() << std::endl + ; + + return false; + } +}; + +// TODO: Testing our _parent/EmbeddedWindow stuff. +bool info(osgWidget::Event& ev) { + osgWidget::warn() << "MousePush @ Window: " << ev.getWindow()->getName() << std::endl; + + return true; +} + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG + ); + + osgWidget::Box* box = new osgWidget::Box("vbox", osgWidget::Box::VERTICAL); + osgWidget::Table* table = new osgWidget::Table("table", 3, 2); + osgWidget::Box* lbox1 = new osgWidget::Box("lbox1", osgWidget::Box::HORIZONTAL); + osgWidget::Box* lbox2 = new osgWidget::Box("lbox2", osgWidget::Box::HORIZONTAL); + osgWidget::Frame* frame = osgWidget::Frame::createSimpleFrameWithSingleTexture( + "frame", + "osgWidget/theme.png", + 64.0f, + 64.0f, + 16.0f, + 16.0f, + 100.0f, + 100.0f + ); + + osgWidget::Input* x = createTableRow(table, 0, "X Position"); + osgWidget::Input* y = createTableRow(table, 1, "Y Position"); + osgWidget::Input* z = createTableRow(table, 2, "Z Position"); + + Button::Inputs inputs; + + inputs.push_back(x); + inputs.push_back(y); + inputs.push_back(z); + + table->addCallback(osgWidget::Callback(&info, osgWidget::EVENT_MOUSE_PUSH)); + + lbox1->addWidget(createLabel(INFO)); + lbox2->addWidget(new Button("Add To Scene...", inputs)); + + box->addWidget(lbox1->embed()); + box->addWidget(table->embed()); + box->addWidget(lbox2->embed()); + box->addCallback(osgWidget::Callback(&info, osgWidget::EVENT_MOUSE_PUSH)); + + frame->setWindow(box); + frame->getEmbeddedWindow()->setSize(box->getWidth(), box->getHeight()); + frame->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.0f); + frame->attachTabFocusCallback(); + + for(osgWidget::Frame::Iterator i = frame->begin(); i != frame->end(); i++) { + if(i->valid()) i->get()->setColor(0.5f, 0.7f, 1.0f, 1.0f); + } + + wm->addChild(frame); + + /* + // Print out our focus list, it should just have 3 widgets. + osgWidget::WidgetList wl; + + box->getFocusList(wl); + + for(osgWidget::WidgetList::iterator i = wl.begin(); i != wl.end(); i++) { + osgWidget::warn() << i->get()->getName() << std::endl; + } + */ + + lbox1->getBackground()->setColor(1.0f, 0.0f, 0.0f, 1.0f, osgWidget::Widget::UPPER_LEFT); + lbox1->getBackground()->setColor(0.0f, 1.0f, 0.0f, 1.0f, osgWidget::Widget::LOWER_LEFT); + lbox1->getBackground()->setColor(0.0f, 0.0f, 1.0f, 1.0f, osgWidget::Widget::LOWER_RIGHT); + lbox1->getBackground()->setColor(1.0f, 1.0f, 1.0f, 1.0f, osgWidget::Widget::UPPER_RIGHT); + lbox1->setVisibilityMode(osgWidget::Window::VM_ENTIRE); + lbox1->update(); + + int r = osgWidget::createExample(viewer, wm); + + // osgWidget::writeWindowManagerNode(wm); + // osgDB::writeNodeFile(*box, "osgWidget.osg"); + + return r; +} diff --git a/examples/osgwidgetlabel/CMakeLists.txt b/examples/osgwidgetlabel/CMakeLists.txt new file mode 100644 index 000000000..4760a4264 --- /dev/null +++ b/examples/osgwidgetlabel/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetlabel) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetlabel osgwidgetlabel.cpp) + +SET_TARGET_PROPERTIES(osgwidgetlabel PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetlabel DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetlabel/osgwidgetlabel.cpp b/examples/osgwidgetlabel/osgwidgetlabel.cpp new file mode 100644 index 000000000..27f762ad7 --- /dev/null +++ b/examples/osgwidgetlabel/osgwidgetlabel.cpp @@ -0,0 +1,120 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetlabel.cpp 66 2008-07-14 21:54:09Z cubicool $ + +#include +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +const char* LABEL1 = + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed\n" + "do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris\n" + "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in..." +; + +const char* LABEL2 = + "...reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla\n" + "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in \n" + "culpa qui officia deserunt mollit anim id est laborum. BBBBB" +; + +osgWidget::Label* createLabel(const std::string& l, unsigned int size=13) { + osgWidget::Label* label = new osgWidget::Label("", ""); + + label->setFont("fonts/arial.ttf"); + label->setFontSize(size); + label->setFontColor(1.0f, 1.0f, 1.0f, 1.0f); + label->setLabel(l); + + /* + text->setBackdropType(osgText::Text::DROP_SHADOW_BOTTOM_RIGHT); + text->setBackdropImplementation(osgText::Text::NO_DEPTH_BUFFER); + text->setBackdropOffset(0.2f); + */ + + return label; +} + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG | + osgWidget::WindowManager::WM_NO_INVERT_Y + ); + + osgWidget::Box* box = new osgWidget::Box("HBOX", osgWidget::Box::HORIZONTAL); + osgWidget::Box* vbox = new osgWidget::Box("vbox", osgWidget::Box::VERTICAL); + osgWidget::Label* label1 = createLabel(LABEL1); + osgWidget::Label* label2 = createLabel(LABEL2); + + // Setup the labels for horizontal box. + label1->setPadding(10.0f); + label2->setPadding(10.0f); + + label1->addSize(21.0f, 22.0f); + label2->addSize(21.0f, 22.0f); + + label1->setColor(1.0f, 0.5f, 0.0f, 0.0f); + label2->setColor(1.0f, 0.5f, 0.0f, 0.0f); + + box->addWidget(label1); + box->addWidget(label2); + box->attachMoveCallback(); + box->attachScaleCallback(); + box->attachRotateCallback(); + + // Setup the labels for the vertical box. + osgWidget::Label* label3 = createLabel("Label 3", 80); + osgWidget::Label* label4 = createLabel("Label 4", 60); + osgWidget::Label* label5 = createLabel("ABCDEFGHIJK", 93); + + label3->setPadding(3.0f); + label4->setPadding(3.0f); + label5->setPadding(3.0f); + + label3->setColor(0.0f, 0.0f, 0.5f, 0.5f); + label4->setColor(0.0f, 0.0f, 0.5f, 0.5f); + label5->setColor(0.0f, 0.0f, 0.5f, 0.5f); + + label5->setAlignHorizontal(osgWidget::Widget::HA_LEFT); + label5->setAlignVertical(osgWidget::Widget::VA_BOTTOM); + + // Test our label copy construction... + osgWidget::Label* label6 = label5->cloneAs("label6"); + + label6->setLabel("abcdefghijklmnopqrs"); + + vbox->addWidget(label3); + vbox->addWidget(label4); + vbox->addWidget(label5); + vbox->addWidget(label6); + vbox->attachMoveCallback(); + vbox->attachScaleCallback(); + + vbox->resize(); + + // vbox->setVisibilityMode(osgWidget::Window::VM_ENTIRE); + // vbox->setVisibleArea(50, 50, 500, 200); + // vbox->setAnchorVertical(osgWidget::Window::VA_TOP); + // vbox->setAnchorHorizontal(osgWidget::Window::HA_RIGHT); + + // Test our label-in-window copy construction... + osgWidget::Box* clonedBox = box->cloneAs("HBOX-new"); + + clonedBox->getBackground()->setColor(0.0f, 1.0f, 0.0f, 0.5f); + + wm->addChild(box); + wm->addChild(vbox); + wm->addChild(clonedBox); + + return osgWidget::createExample(viewer, wm); +} diff --git a/examples/osgwidgetmenu/CMakeLists.txt b/examples/osgwidgetmenu/CMakeLists.txt new file mode 100644 index 000000000..87c64d52a --- /dev/null +++ b/examples/osgwidgetmenu/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetmenu) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetmenu osgwidgetmenu.cpp) + +SET_TARGET_PROPERTIES(osgwidgetmenu PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetmenu DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetmenu/osgwidgetmenu.cpp b/examples/osgwidgetmenu/osgwidgetmenu.cpp new file mode 100644 index 000000000..bd8dd12c8 --- /dev/null +++ b/examples/osgwidgetmenu/osgwidgetmenu.cpp @@ -0,0 +1,129 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetmenu.cpp 66 2008-07-14 21:54:09Z cubicool $ + +#include +#include +#include +#include +#include +#include + +// For now this is just an example, but osgWidget::Menu will later be it's own Window. +// I just wanted to get this out there so that people could see it was possible. + +const unsigned int MASK_2D = 0xF0000000; +const unsigned int MASK_3D = 0x0F000000; + +struct ColorLabel: public osgWidget::Label { + ColorLabel(const char* label): + osgWidget::Label("", "") { + setFont("fonts/Calibri1.ttf"); + setFontSize(14); + setFontColor(1.0f, 1.0f, 1.0f, 1.0f); + setColor(0.3f, 0.3f, 0.3f, 1.0f); + addHeight(18.0f); + setCanFill(true); + setLabel(label); + setEventMask(osgWidget::EVENT_MOUSE_PUSH | osgWidget::EVENT_MASK_MOUSE_MOVE); + } + + bool mousePush(double, double, osgWidget::WindowManager*) { + return true; + } + + bool mouseEnter(double, double, osgWidget::WindowManager*) { + setColor(0.6f, 0.6f, 0.6f, 1.0f); + + return true; + } + + bool mouseLeave(double, double, osgWidget::WindowManager*) { + setColor(0.3f, 0.3f, 0.3f, 1.0f); + + return true; + } +}; + +class ColorLabelMenu: public ColorLabel { + osg::ref_ptr _window; + +public: + ColorLabelMenu(const char* label): + ColorLabel(label) { + _window = new osgWidget::Box( + std::string("Menu_") + label, + osgWidget::Box::VERTICAL, + true + ); + + _window->addWidget(new ColorLabel("Open Some Stuff")); + _window->addWidget(new ColorLabel("Do It Now")); + _window->addWidget(new ColorLabel("Hello, How Are U?")); + _window->addWidget(new ColorLabel("Hmmm...")); + _window->addWidget(new ColorLabel("Option 5")); + + _window->resize(); + + setColor(0.8f, 0.8f, 0.8f, 0.8f); + } + + void managed(osgWidget::WindowManager* wm) { + osgWidget::Label::managed(wm); + + wm->addChild(_window.get()); + + _window->hide(); + } + + void positioned() { + osgWidget::Label::positioned(); + + _window->setOrigin(getX(), getHeight()); + _window->resize(getWidth()); + } + + bool mousePush(double, double, osgWidget::WindowManager*) { + if(!_window->isVisible()) _window->show(); + + else _window->hide(); + + return true; + } + + bool mouseLeave(double, double, osgWidget::WindowManager*) { + if(!_window->isVisible()) setColor(0.8f, 0.8f, 0.8f, 0.8f); + + return true; + } +}; + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG | + osgWidget::WindowManager::WM_NO_BETA_WARN + ); + + osgWidget::Window* menu = new osgWidget::Box("menu", osgWidget::Box::HORIZONTAL); + + menu->addWidget(new ColorLabelMenu("Pick me!")); + menu->addWidget(new ColorLabelMenu("No, wait, pick me!")); + menu->addWidget(new ColorLabelMenu("Dont pick them...")); + menu->addWidget(new ColorLabelMenu("Grarar!?!")); + + wm->addChild(menu); + + menu->getBackground()->setColor(1.0f, 1.0f, 1.0f, 0.0f); + menu->resizePercent(100.0f); + + osg::Node* model = osgDB::readNodeFile("osgcool.osg"); + + model->setNodeMask(MASK_3D); + + return osgWidget::createExample(viewer, wm, model); +} diff --git a/examples/osgwidgetnotebook/CMakeLists.txt b/examples/osgwidgetnotebook/CMakeLists.txt new file mode 100644 index 000000000..0ecff512e --- /dev/null +++ b/examples/osgwidgetnotebook/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetnotebook) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetnotebook osgwidgetnotebook.cpp) + +SET_TARGET_PROPERTIES(osgwidgetnotebook PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetnotebook DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetnotebook/osgwidgetnotebook.cpp b/examples/osgwidgetnotebook/osgwidgetnotebook.cpp new file mode 100644 index 000000000..004c9c24a --- /dev/null +++ b/examples/osgwidgetnotebook/osgwidgetnotebook.cpp @@ -0,0 +1,134 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetnotebook.cpp 45 2008-04-23 16:46:11Z cubicool $ + +#include +#include +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; +const unsigned int MASK_3D = 0x0F000000; + +class Notebook: public osgWidget::Box { + osg::ref_ptr _tabs; + osg::ref_ptr _windows; + +public: + // NOTE: This whole thing is just a hack to demonstrate a concept. The real + // implementation would need to be much cleaner. + bool callbackTabPressed(osgWidget::Event& ev) { + osgWidget::Canvas::Vector& objs = _windows->getObjects(); + + for(unsigned int i = 0; i < objs.size(); i++) objs[i]->setLayer( + osgWidget::Widget::LAYER_MIDDLE, + i + ); + + _windows->getByName(ev.getWidget()->getName())->setLayer( + osgWidget::Widget::LAYER_MIDDLE, + objs.size() + ); + + _windows->resize(); + + return true; + } + + Notebook(const std::string& name): + osgWidget::Box(name, osgWidget::Box::VERTICAL) { + _tabs = new osgWidget::Box("tabs", osgWidget::Box::HORIZONTAL); + _windows = new osgWidget::Canvas("canvas"); + + for(unsigned int i = 0; i < 4; i++) { + std::stringstream ss; + + // Setup everything for our Tab... + ss << "Tab_" << i; + + osgWidget::Label* label1 = new osgWidget::Label(ss.str()); + + label1->setFont("fonts/monospace.ttf"); + label1->setFontSize(20); + label1->setFontColor(1.0f, 1.0f, 1.0f, 1.0f); + label1->setColor(0.0f, i / 4.0f, 0.3f, 1.0f); + label1->setLabel(ss.str()); + label1->addSize(20.0f, 20.0f); + label1->setShadow(0.1f); + label1->setCanFill(true); + + _tabs->addWidget(label1); + + // Setup everything for the Window corresponding to the Tab + // in the Canvas down below. + std::stringstream descr; + + descr + << "This is some text" << std::endl + << "for the Tab_" << i << " tab." << std::endl + << "Press the button up top" << std::endl + << "And this should go to the next Window!" << std::endl + ; + + osgWidget::Label* label2 = new osgWidget::Label(ss.str()); + + label2->setFont("fonts/monospace.ttf"); + label2->setFontSize(15); + label2->setFontColor(1.0f, 1.0f, 1.0f, 1.0f); + label2->setColor(0.0f, i / 4.0f, 0.3f, 1.0f); + label2->setLabel(descr.str()); + label2->setLayer(osgWidget::Widget::LAYER_MIDDLE, i); + label2->addSize(50.0f, 50.0f); + + _windows->addWidget(label2, 0.0f, 0.0f); + + label1->setEventMask(osgWidget::EVENT_MOUSE_PUSH); + label1->addCallback(osgWidget::Callback( + &Notebook::callbackTabPressed, + this, + osgWidget::EVENT_MOUSE_PUSH + )); + } + + osgWidget::Label* label = new osgWidget::Label("label"); + + label->setFont("fonts/monospace.ttf"); + label->setFontSize(15); + label->setFontColor(1.0f, 1.0f, 1.0f, 1.0f); + label->setLabel("Drag the window here..."); + label->addSize(20.0f, 20.0f); + label->setShadow(0.08f); + label->setCanFill(true); + + addWidget(label); + addWidget(_tabs->embed()); + addWidget(_windows->embed()); + } +}; + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 720.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG + ); + + Notebook* notebook = new Notebook("notebook"); + + osgWidget::warn() + << "Sizes are..." << std::endl + << "Cur: " << notebook->getSize() << std::endl + << "Min: " << notebook->getMinSize() << std::endl + ; + + notebook->attachMoveCallback(); + + wm->addChild(notebook); + + return osgWidget::createExample(viewer, wm); +} diff --git a/examples/osgwidgetscrolled/CMakeLists.txt b/examples/osgwidgetscrolled/CMakeLists.txt new file mode 100644 index 000000000..939bc0835 --- /dev/null +++ b/examples/osgwidgetscrolled/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetscrolled) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetscrolled osgwidgetscrolled.cpp) + +SET_TARGET_PROPERTIES(osgwidgetscrolled PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetscrolled DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetscrolled/osgwidgetscrolled.cpp b/examples/osgwidgetscrolled/osgwidgetscrolled.cpp new file mode 100644 index 000000000..050bb22ad --- /dev/null +++ b/examples/osgwidgetscrolled/osgwidgetscrolled.cpp @@ -0,0 +1,134 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetframe.cpp 34 2008-04-07 03:12:41Z cubicool $ + +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +// NOTE: THIS IS JUST A TEMPORARY HACK! :) This functionality will all eventually be +// encapsulate into another class in osgWidget proper. +bool scrollWindow(osgWidget::Event& ev) { + // The first thing we need to do is make sure we have a Frame object... + osgWidget::Frame* frame = dynamic_cast(ev.getWindow()); + + if(!frame) return false; + + // And now we need to make sure our Frame has a valid internal EmbeddedWindow widget. + osgWidget::Window::EmbeddedWindow* ew = + dynamic_cast(frame->getEmbeddedWindow()) + ; + + if(!ew) return false; + + // Lets get the visible area so that we can use it to make sure our scrolling action + // is necessary in the first place. + const osgWidget::Quad& va = ew->getWindow()->getVisibleArea(); + + // The user wants to scroll up; make sure that the visible area's Y origin isn't already + // at 0.0f, 0.0f. + if(ev.getWindowManager()->isMouseScrollingUp() && va[1] != 0.0f) + ew->getWindow()->addVisibleArea(0, -20) + ; + + else if(va[1] <= (ew->getWindow()->getHeight() - ew->getHeight())) + ew->getWindow()->addVisibleArea(0, 20) + ; + + // We need to manually call update to make sure the visible area scissoring is done + // properly. + frame->update(); + + return true; +} + +bool changeTheme(osgWidget::Event& ev) { + std::string theme; + + if(ev.key == osgGA::GUIEventAdapter::KEY_Right) + theme = "osgWidget/theme-1.png" + ; + + else if(ev.key == osgGA::GUIEventAdapter::KEY_Left) + theme = "osgWidget/theme-2.png" + ; + + else return false; + + osgWidget::Frame* frame = dynamic_cast(ev.getWindow()); + + if(!frame) return false; + + // This is just one way to access all our Widgets; we could just as well have used: + // + // for(osgWidget::Frame::Iterator i = frame.begin(); i != frame.end() i++) {} + // + // ...and it have worked, too. + for(unsigned int row = 0; row < 3; row++) { + for(unsigned int col = 0; col < 3; col++) { + frame->getByRowCol(row, col)->setImage(theme); + } + } + + return true; +} + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG + ); + + osgWidget::Frame* frame = osgWidget::Frame::createSimpleFrameWithSingleTexture( + "frame", + "../examples/osgwidgetscrolled/theme-2.png", + 64.0f, + 64.0f, + 16.0f, + 16.0f, + 100.0f, + 100.0f + ); + + frame->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.0f); + + // This is our Transformers box. :) + osgWidget::Box* box = new osgWidget::Box("images", osgWidget::Box::VERTICAL); + osgWidget::Widget* img1 = new osgWidget::Widget("im1", 256.0f, 256.0f); + osgWidget::Widget* img2 = new osgWidget::Widget("im2", 256.0f, 256.0f); + osgWidget::Widget* img3 = new osgWidget::Widget("im3", 256.0f, 256.0f); + osgWidget::Widget* img4 = new osgWidget::Widget("im4", 256.0f, 256.0f); + + img1->setImage("../examples/osgwidgetscrolled/images/starscream.jpg", true); + img2->setImage("../examples/osgwidgetscrolled/images/optimus.jpg", true); + img3->setImage("../examples/osgwidgetscrolled/images/megatron.jpg", true); + img4->setImage("../examples/osgwidgetscrolled/images/bumblebee.jpg", true); + + img1->setMinimumSize(10.0f, 10.0f); + img2->setMinimumSize(10.0f, 10.0f); + img3->setMinimumSize(10.0f, 10.0f); + img4->setMinimumSize(10.0f, 10.0f); + + box->addWidget(img1); + box->addWidget(img2); + box->addWidget(img3); + box->addWidget(img4); + box->setEventMask(osgWidget::EVENT_NONE); + + frame->getEmbeddedWindow()->setWindow(box); + frame->getEmbeddedWindow()->setColor(1.0f, 1.0f, 1.0f, 1.0f); + frame->resize(300.0f, 300.0f); + frame->addCallback(osgWidget::Callback(&scrollWindow, osgWidget::EVENT_MOUSE_SCROLL)); + frame->addCallback(osgWidget::Callback(&changeTheme, osgWidget::EVENT_KEY_DOWN)); + + wm->addChild(frame); + + return osgWidget::createExample(viewer, wm); +} diff --git a/examples/osgwidgetshader/CMakeLists.txt b/examples/osgwidgetshader/CMakeLists.txt new file mode 100644 index 000000000..8a53ba2d7 --- /dev/null +++ b/examples/osgwidgetshader/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetshader) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetshader osgwidgetshader.cpp) + +SET_TARGET_PROPERTIES(osgwidgetshader PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetshader DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetshader/osgwidgetshader.cpp b/examples/osgwidgetshader/osgwidgetshader.cpp new file mode 100644 index 000000000..ee40a27ad --- /dev/null +++ b/examples/osgwidgetshader/osgwidgetshader.cpp @@ -0,0 +1,74 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetshader.cpp 28 2008-03-26 15:26:48Z cubicool $ + +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +osgWidget::Widget* createWidget( + const std::string& name, + osgWidget::color_type col, + osgWidget::Widget::LAYER layer +) { + osgWidget::Widget* widget = new osgWidget::Widget(name, 200.0f, 200.0f); + + widget->setColor(col, col, col, 0.2f); + widget->setLayer(layer); + + return widget; +} + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D + ); + + osgWidget::Canvas* canvas = new osgWidget::Canvas("canvas"); + + canvas->attachMoveCallback(); + canvas->attachScaleCallback(); + + canvas->addWidget( + createWidget("w1", 0.2f, osgWidget::Widget::LAYER_LOW), + 0.0f, + 0.0f + ); + + canvas->addWidget( + createWidget("w2", 0.4f, osgWidget::Widget::LAYER_MIDDLE), + 200.0f, + 0.0f + ); + + canvas->addWidget( + createWidget("w3", 0.6f, osgWidget::Widget::LAYER_HIGH), + 400.0f, + 0.0f + ); + + + wm->addChild(canvas); + + osg::Program* program = new osg::Program(); + + program->addShader(osg::Shader::readShaderFile( + osg::Shader::VERTEX, + "osgWidget/osgwidgetshader-vert.glsl" + )); + + program->addShader(osg::Shader::readShaderFile( + osg::Shader::FRAGMENT, + "osgWidget/osgwidgetshader-frag.glsl" + )); + + canvas->getGeode()->getOrCreateStateSet()->setAttribute(program); + + return osgWidget::createExample(viewer, wm); +} diff --git a/examples/osgwidgetstyled/CMakeLists.txt b/examples/osgwidgetstyled/CMakeLists.txt new file mode 100644 index 000000000..c871cf7df --- /dev/null +++ b/examples/osgwidgetstyled/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetstyled) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetstyled osgwidgetstyled.cpp) + +SET_TARGET_PROPERTIES(osgwidgetstyled PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetstyled DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetstyled/osgwidgetstyled.cpp b/examples/osgwidgetstyled/osgwidgetstyled.cpp new file mode 100644 index 000000000..20df682a1 --- /dev/null +++ b/examples/osgwidgetstyled/osgwidgetstyled.cpp @@ -0,0 +1,83 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetshader.cpp 28 2008-03-26 15:26:48Z cubicool $ + +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +const std::string& STYLE1 = + "color 0 0 0 128\n" + "padding 5\n" +; + +const std::string& STYLE2 = + "color 1.0 0.5 0.0\n" +; + +const std::string& STYLE3 = + "fill true\n" +; + +const std::string& STYLE4 = + "pos 100.0 100.0\n" + "size 600 600\n" +; + +class CustomStyled: public osgWidget::Widget { +}; + +class CustomStyle: public osgWidget::Style { + virtual bool applyStyle(osgWidget::Widget* w, osgWidget::Reader r) { + CustomStyled* cs = dynamic_cast(w); + + if(!cs) return false; + + osgWidget::warn() << "Here, okay." << std::endl; + + return true; + } +}; + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D + ); + + osgWidget::Box* box = new osgWidget::Box("box", osgWidget::Box::VERTICAL); + + osgWidget::Widget* widget1 = new osgWidget::Widget("w1", 200.0f, 200.0f); + osgWidget::Widget* widget2 = new osgWidget::Widget("w2", 100.0f, 100.0f); + osgWidget::Widget* widget3 = new osgWidget::Widget("w3", 0.0f, 0.0f); + CustomStyled* cs = new CustomStyled(); + + // Yep. + wm->getStyleManager()->addStyle(new osgWidget::Style("widget.style1", STYLE1)); + wm->getStyleManager()->addStyle(new osgWidget::Style("widget.style2", STYLE2)); + wm->getStyleManager()->addStyle(new osgWidget::Style("spacer", STYLE3)); + wm->getStyleManager()->addStyle(new osgWidget::Style("window", STYLE4)); + // wm->getStyleManager()->addStyle(new CustomStyle("widget", "")); + + widget1->setStyle("widget.style1"); + widget2->setStyle("widget.style2"); + widget3->setStyle("spacer"); + + box->setStyle("window"); + + box->addWidget(widget1); + box->addWidget(widget2); + box->addWidget(widget3); + + wm->addChild(box); + + // box->resizePercent(0.0f, 100.0f); + + return osgWidget::createExample(viewer, wm); +} diff --git a/examples/osgwidgettable/CMakeLists.txt b/examples/osgwidgettable/CMakeLists.txt new file mode 100644 index 000000000..635dad065 --- /dev/null +++ b/examples/osgwidgettable/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgettable) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgettable osgwidgettable.cpp) + +SET_TARGET_PROPERTIES(osgwidgettable PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgettable DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgettable/osgwidgettable.cpp b/examples/osgwidgettable/osgwidgettable.cpp new file mode 100644 index 000000000..b9054de51 --- /dev/null +++ b/examples/osgwidgettable/osgwidgettable.cpp @@ -0,0 +1,69 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgettable.cpp 43 2008-04-17 03:40:05Z cubicool $ + +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; + +// This examples demonstrates the use of an osgWidget::Table, which differs from a Box in +// many ways. First and foremost, a Table's size is intially known, whereas a Box can be +// dynamically added to. Secondly, a table is matrix Layout, with both vertical and +// horizontal placement cells. A Box, on the other hand, can only be vertical or horizontal. + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_PICK_DEBUG + ); + + osgWidget::Table* table = new osgWidget::Table("table", 3, 3); + + // Here we create our "cells" manually, though it will often be convenient to + // do so algorithmically. Also, notice how we set the text name of each widget to + // correspond with it's "index" in the table. This is merely a convenience, which + // we use later... + table->addWidget(new osgWidget::Widget("0, 0", 100.0f, 25.0f), 0, 0); + table->addWidget(new osgWidget::Widget("0, 1", 100.0f, 25.0f), 0, 1); + table->addWidget(new osgWidget::Widget("0, 2", 100.0f, 75.0f), 0, 2); + + table->addWidget(new osgWidget::Widget("1, 0", 200.0f, 45.0f), 1, 0); + table->addWidget(new osgWidget::Widget("1, 1", 200.0f, 45.0f), 1, 1); + table->addWidget(new osgWidget::Widget("1, 2", 200.0f, 45.0f), 1, 2); + + table->addWidget(new osgWidget::Widget("2, 0", 300.0f, 65.0f), 2, 0); + table->addWidget(new osgWidget::Widget("2, 1", 300.0f, 65.0f), 2, 1); + table->addWidget(new osgWidget::Widget("2, 2", 300.0f, 65.0f), 2, 2); + + table->getBackground()->setColor(0.0f, 0.0f, 0.5f, 1.0f); + table->attachMoveCallback(); + + // Use a hackish method of setting the spacing for all Widgets. + for(osgWidget::Table::Iterator i = table->begin(); i != table->end(); i++) + i->get()->setPadding(1.0f) + ; + + // Now we fetch the very first 0, 0 Widget in the table using an awkward method. + // This is merely one way to fetch a Widget from a Window, there are many others. + // The osgWidget::Window::getByName interface will be very handy in scripting languages + // where users will want to retrieve handles to existing Windows using a useful + // textual name, such as "MainGUIParent" or something. + table->getByName("0, 0")->setAlignHorizontal(osgWidget::Widget::HA_LEFT); + table->getByName("0, 0")->setAlignVertical(osgWidget::Widget::VA_BOTTOM); + table->getByName("0, 0")->setPadding(10.0f); + + // Change the colors a bit to differentiate this row from the others. + table->getByName("2, 0")->setColor(1.0f, 0.0f, 0.0f, 1.0f, osgWidget::Widget::LOWER_LEFT); + table->getByName("2, 1")->setColor(1.0f, 0.0f, 0.0f, 0.5f); + table->getByName("2, 2")->setColor(1.0f, 0.0f, 0.0f, 0.5f); + + wm->addChild(table); + + return createExample(viewer, wm); +} diff --git a/examples/osgwidgetversion/CMakeLists.txt b/examples/osgwidgetversion/CMakeLists.txt new file mode 100644 index 000000000..fe42593c0 --- /dev/null +++ b/examples/osgwidgetversion/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetversion) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetversion osgwidgetversion.cpp) + +SET_TARGET_PROPERTIES(osgwidgetversion PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetversion DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetversion/osgwidgetversion.cpp b/examples/osgwidgetversion/osgwidgetversion.cpp new file mode 100644 index 000000000..ac04a7d94 --- /dev/null +++ b/examples/osgwidgetversion/osgwidgetversion.cpp @@ -0,0 +1,14 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetversion.cpp 2 2008-01-24 16:11:26Z cubicool $ + +#include +#include + +int main(int argc, char** argv) { + osg::notify(osg::NOTICE) + << osgWidgetGetLibraryName() << " " + << osgWidgetGetVersion() << std::endl + ; + + return 0; +} diff --git a/examples/osgwidgetwindow/CMakeLists.txt b/examples/osgwidgetwindow/CMakeLists.txt new file mode 100644 index 000000000..961d468a3 --- /dev/null +++ b/examples/osgwidgetwindow/CMakeLists.txt @@ -0,0 +1,9 @@ +PROJECT(osgwidgetwindow) + +LINK_LIBRARIES(debug osgWidgetd optimized osgWidget) + +ADD_EXECUTABLE(osgwidgetwindow osgwidgetwindow.cpp) + +SET_TARGET_PROPERTIES(osgwidgetwindow PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +INSTALL(TARGETS osgwidgetwindow DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/examples/osgwidgetwindow/osgwidgetwindow.cpp b/examples/osgwidgetwindow/osgwidgetwindow.cpp new file mode 100644 index 000000000..2055b3fbd --- /dev/null +++ b/examples/osgwidgetwindow/osgwidgetwindow.cpp @@ -0,0 +1,204 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: osgwidgetwindow.cpp 66 2008-07-14 21:54:09Z cubicool $ + +#include +#include +#include +#include +#include +#include +#include +#include + +const unsigned int MASK_2D = 0xF0000000; +const unsigned int MASK_3D = 0x0F000000; + +// Here we create (and later demonstrate) the use of a simple function callback. +bool windowClicked(osgWidget::Event& ev) { + std::cout << "windowClicked: " << ev.getWindow()->getName() << std::endl; + + if(ev.getData()) { + std::string* s = static_cast(ev.getData()); + + std::cout << "This is data attached to the event: " << *s << std::endl; + } + + return true; +} + +bool windowScrolled(osgWidget::Event& ev) { + osgWidget::warn() + << "scrolling up? " << ev.getWindowManager()->isMouseScrollingUp() + << std::endl + ; + + return true; +} + +// Here we dcreate a new class and show how to use a method callback (which differs from +// a function callback in that we are required to also pass the "this" argument). +struct Object { + bool windowClicked(osgWidget::Event& ev) { + std::cout << "Object::windowClicked " << ev.getWindow()->getName() << std::endl; + + return true; + } +}; + +int main(int argc, char** argv) { + osgViewer::Viewer viewer; + + // Let's get busy! The WindowManager class is actually an osg::Switch, + // so you can add it to (ideally) an orthographic camera and have it behave as + // expected. Note that you create a WindowManager with a NodeMask--it is very important + // that this be unique for picking to work properly. This also makes it possible to have + // multiple WindowManagers each operating on their own, unique set of Window objects. + // The final bool argument is a group of flags that introduce optional functionality + // for the WindowManager. In our case we include the flags USE_PYTHON and USE_LUA, + // to demonstrate (and test) their usage. Finally, we pass the temporary WM_NO_BETA_WARN + // argument, which prevents creating the orange warning window. :) It will be shown + // in other examples... + osgWidget::WindowManager* wm = new osgWidget::WindowManager( + &viewer, + 1280.0f, + 1024.0f, + MASK_2D, + osgWidget::WindowManager::WM_USE_LUA | + osgWidget::WindowManager::WM_USE_PYTHON | + osgWidget::WindowManager::WM_PICK_DEBUG | + osgWidget::WindowManager::WM_NO_BETA_WARN + ); + + // An actual osgWidget::Window is pure virtual, so we've got to use the osgWidget::Box + // implementation for now. At a later time, support for Tables and other kinds of + // advanced layout Window types will be added. + osgWidget::Window* box = new osgWidget::Box("box", osgWidget::Box::HORIZONTAL); + + // Now we actually attach our two types of callbacks to the box instance. The first + // uses the simple function signature, the second uses a bound method, passing "this" + // as the second argument to the Callback constructor. + Object obj; + + static std::string data = "lol ur face!"; + + box->addCallback(osgWidget::Callback(&windowClicked, osgWidget::EVENT_MOUSE_PUSH, &data)); + box->addCallback(osgWidget::Callback(&windowScrolled, osgWidget::EVENT_MOUSE_SCROLL)); + box->addCallback(osgWidget::Callback( + &Object::windowClicked, + &obj, + osgWidget::EVENT_MOUSE_PUSH + )); + + // Create some of our "testing" Widgets; included are two Widget subclasses I made + // during testing which I've kept around for testing purposes. You'll notice + // that you cannot move the box using the NullWidget, and that the NotifyWidget + // is a bit verbose. :) + osgWidget::Widget* widget1 = new osgWidget::NotifyWidget("widget1", 300.0f, 100.0f); + osgWidget::Widget* widget2 = new osgWidget::NullWidget("widget2", 400.0f, 75.0f); + osgWidget::Widget* widget3 = new osgWidget::Widget("widget3", 100.0f, 100.0f); + // Set the colors of widget1 and widget3 to green. + widget1->setColor(0.0f, 1.0f, 0.0f, 1.0f); + widget1->setCanFill(true); + widget3->setColor(0.0f, 1.0f, 0.0f, 1.0f); + + widget1->setImage(osgDB::readImageFile("Images/Saturn.TGA"), true); + + // Set the color of widget2, to differentiate it and make it sassy. This is + // like a poor man's gradient! + widget2->setColor(0.9f, 0.0f, 0.0f, 0.9f, osgWidget::Widget::LOWER_LEFT); + widget2->setColor(0.9f, 0.0f, 0.0f, 0.9f, osgWidget::Widget::LOWER_RIGHT); + widget2->setColor(0.0f, 0.0f, 0.9f, 0.9f, osgWidget::Widget::UPPER_RIGHT); + widget2->setColor(0.0f, 0.0f, 0.9f, 0.9f, osgWidget::Widget::UPPER_LEFT); + + // Now add our newly created widgets to our box. + box->addWidget(widget1); + box->addWidget(widget2); + box->addWidget(widget3); + + // For maximum efficiency, Windows don't automatically reallocate their geometry + // and internal positioning every time a widget is added. Thus, we either have to + // call the WindowManger::resizeAllWindows method or manually call + // Window::resize when we're ready. + box->resize(); + + // Now, lets clone our existing box and create a new copy of of it, also adding that + // to the WindowManager. This demonstrates the usages of OSG's ->clone() support, + // though that is abstracted by our META_UIObject macro. + osgWidget::Window* boxCopy = box->cloneAs("newBox"); + + // Move our copy to make it visible. + boxCopy->setOrigin(0.0f, 125.0f); + + boxCopy->getByName("widget1")->setColor(0.5f, 0.0f, 1.0f, 1.0f); + boxCopy->getByName("widget3")->setColor(0.5f, 0.0f, 1.0f, 1.0f); + + // Add the successfully created Box (if we get this far) into the WindowManager, so + // that they can receive events. + wm->addChild(box); + wm->addChild(boxCopy); + + // Now, ask our new box to be 100% the width of the WindowManager. + boxCopy->resizePercent(100.0f, 0.0f); + + // Here we demonstrate the use of osgWidget/io_utils. This is really only useful for + // debugging at the moment, but later I'll make it more generic for .osg and .ive + // creation. + // std::cout << *box << std::endl << *boxCopy << std::endl; + + // Add our event handler; is this better as a MatrixManipulator? Add a few other + // helpful ViewerEventHandlers. + viewer.addEventHandler(new osgWidget::MouseHandler(wm)); + viewer.addEventHandler(new osgWidget::KeyboardHandler(wm)); + viewer.addEventHandler(new osgViewer::StatsHandler()); + viewer.addEventHandler(new osgViewer::WindowSizeHandler()); + viewer.addEventHandler(new osgGA::StateSetManipulator( + viewer.getCamera()->getOrCreateStateSet() + )); + + // Setup our OSG objects for our scene; note the use of the utility function + // createOrthoCamera, which is just a helper for setting up a proper viewing area. + // An alternative (and a MUCH easier alternative at that!) is to + // simply use the createParentOrthoCamera method of the WindowManager class, + // which will wrap the calls to createOrthoCamera and addChild for us! Check out + // some of the other examples to see this in action... + osg::Group* group = new osg::Group(); + osg::Camera* camera = osgWidget::createInvertedYOrthoCamera(1280.0f, 1024.0f); + osg::Node* model = osgDB::readNodeFile("cow.osg"); + + // Set our first non-UI node to be something other than the mask we created our + // WindowManager with to avoid picking. + // TODO: Do I need to create a mechanism for doing this automatically, or should + // that be the responsibility of the users of osgWidget? + model->setNodeMask(MASK_3D); + + // Add the WindowManager instance to the 2D camera. This isn't strictly necessary, + // and you can get some cool results putting the WindowManager directly into a + // 3D scene. This is not necessary if you use WindowManager::createParentOrthoCamera. + camera->addChild(wm); + + // Add our camera and a testing 3D model to the scene. + group->addChild(camera); + group->addChild(model); + + // Here we show how to both run simple strings of code AND run entire files. These + // assume that you're running the osgwidgetwindow example from the build directory, + // otherwise you'll need to adjust the file path below in the call to runFile(). + wm->getLuaEngine()->eval("window = osgwidget.newWindow()"); + wm->getLuaEngine()->runFile("osgWidget/osgwidgetwindow.lua"); + + wm->getPythonEngine()->eval("import osgwidget"); + wm->getPythonEngine()->runFile("osgWidget/osgwidgetwindow.py"); + + viewer.setUpViewInWindow(0, 0, 1280, 1024); + viewer.setSceneData(group); + + /* + osgViewer::Viewer::Cameras cameras; + viewer.getCameras(cameras); + osg::Camera* c = cameras[0]; + osg::Matrix s = osg::Matrix::scale(1.0f, -1.0f, 1.0f); + c->setProjectionMatrix(s * c->getProjectionMatrix()); + */ + + return viewer.run(); +} diff --git a/include/osgWidget/Box b/include/osgWidget/Box new file mode 100644 index 000000000..96838cfb9 --- /dev/null +++ b/include/osgWidget/Box @@ -0,0 +1,39 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Box 46 2008-04-30 16:11:51Z cubicool $ + +#ifndef OSGWIDGET_BOX +#define OSGWIDGET_BOX + +#include + +namespace osgWidget { + +class OSGWIDGET_EXPORT Box: public Window { +public: + enum BOX_TYPE { + VERTICAL, + HORIZONTAL + }; + +private: + BOX_TYPE _boxType; + bool _uniform; + unsigned int _lastAdd; + +protected: + virtual void _resizeImplementation(point_type, point_type); + + virtual Sizes _getWidthImplementation () const; + virtual Sizes _getHeightImplementation () const; + +public: + META_Object (osgWidget, Box); + META_UIObject (Box); + + Box (const std::string& = "", BOX_TYPE = HORIZONTAL, bool = false); + Box (const Box&, const osg::CopyOp&); +}; + +} + +#endif diff --git a/include/osgWidget/Canvas b/include/osgWidget/Canvas new file mode 100644 index 000000000..4216aa97c --- /dev/null +++ b/include/osgWidget/Canvas @@ -0,0 +1,28 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Canvas 66 2008-07-14 21:54:09Z cubicool $ + +#ifndef OSGWIDGET_CANVAS +#define OSGWIDGET_CANVAS + +#include + +namespace osgWidget { + +class OSGWIDGET_EXPORT Canvas: public Window { +protected: + virtual void _resizeImplementation(point_type, point_type); + +public: + META_Object (osgWidget, Canvas); + META_UIObject (Canvas); + + Canvas (const std::string& = ""); + Canvas (const Canvas&, const osg::CopyOp&); + + // This would conflict with the normal addWidget if there were default values. :( + virtual bool addWidget(Widget*, point_type, point_type); +}; + +} + +#endif diff --git a/include/osgWidget/EventInterface b/include/osgWidget/EventInterface new file mode 100644 index 000000000..b4f891a0d --- /dev/null +++ b/include/osgWidget/EventInterface @@ -0,0 +1,376 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: EventInterface 64 2008-06-30 21:32:00Z cubicool $ + +#ifndef OSGWIDGET_EVENT_INTERFACE +#define OSGWIDGET_EVENT_INTERFACE + +#include +#include +#include + +#include + +namespace osgWidget { + +class WindowManager; +class Window; +class Widget; + +enum EVENT_TYPE { + EVENT_NONE = 0x0000, + EVENT_FOCUS = 0x0001, + EVENT_UNFOCUS = 0x0002, + EVENT_MOUSE_ENTER = 0x0004, + EVENT_MOUSE_OVER = 0x0008, + EVENT_MOUSE_LEAVE = 0x0010, + EVENT_MOUSE_DRAG = 0x0020, + EVENT_MOUSE_PUSH = 0x0040, + EVENT_MOUSE_RELEASE = 0x0080, + EVENT_MOUSE_SCROLL = 0x0100, + EVENT_KEY_DOWN = 0x0200, + EVENT_KEY_UP = 0x0400, + EVENT_ALL = 0xFFFF +}; + +// Helpful wrapper around using the raw types, since it often doesn't make sense to +// use some without the others. +enum EVENT_MASK { + EVENT_MASK_FOCUS = EVENT_FOCUS | EVENT_UNFOCUS, + EVENT_MASK_MOUSE_MOVE = EVENT_MOUSE_ENTER | EVENT_MOUSE_OVER | EVENT_MOUSE_LEAVE, + EVENT_MASK_MOUSE_CLICK = EVENT_MOUSE_PUSH | EVENT_MOUSE_RELEASE, + EVENT_MASK_MOUSE_DRAG = EVENT_MASK_MOUSE_MOVE | EVENT_MASK_MOUSE_CLICK | EVENT_MOUSE_DRAG, + EVENT_MASK_KEY = EVENT_KEY_UP | EVENT_KEY_DOWN +}; + +class OSGWIDGET_EXPORT Event { + friend class WindowManager; + friend class Window; + + WindowManager* _wm; + Window* _window; + Widget* _widget; + void* _data; + +public: + EVENT_TYPE type; + double x; + double y; + int key; + int keyMask; + + Event(WindowManager* wm, EVENT_TYPE _type = EVENT_NONE): + _wm (wm), + _window (0), + _widget (0), + _data (0), + type (_type), + x (0.0f), + y (0.0f), + key (-1), + keyMask (-1) { + } + + Event& makeType(EVENT_TYPE _type) { + if(_type != EVENT_NONE) type = _type; + + return *this; + } + + Event& makeMouse(double _x, double _y, EVENT_TYPE _type = EVENT_NONE) { + x = _x; + y = _y; + + if(_type != EVENT_NONE) type = _type; + + return *this; + } + + Event& makeKey(int _key, int _keyMask, EVENT_TYPE _type = EVENT_NONE) { + key = _key; + keyMask = _keyMask; + + if(_type != EVENT_NONE) type = _type; + + return *this; + } + + WindowManager* getWindowManager() { + return _wm; + } + + const WindowManager* getWindowManager() const { + return _wm; + } + + Window* getWindow() { + return _window; + } + + const Window* getWindow() const { + return _window; + } + + Widget* getWidget() { + return _widget; + } + + const Widget* getWidget() const { + return _widget; + } + + void* getData() { + return _data; + } + + const void* getData() const { + return _data; + } + + void setData(void* data) { + _data = data; + } +}; + +// The Callback interface was inspired by the CEGUI project: +// +// http://www.cegui.org.uk/wiki/index.php/Main_Page +// +// It's a great little way to cleanly implement callbacks for events, although +// I did change the names a bit to make them more appropriate for OSG. MANY THANKS +// to the CEGUI project! + +// The CallbackInterface, which the highest-level functor keeps a pointer to. +struct CallbackInterface: public osg::Referenced { + virtual ~CallbackInterface() { + } + + virtual bool operator()(Event&) = 0; +}; + +// The object that facilitates a class method as a callback. +template +class ObjectCallback: public CallbackInterface { +public: + typedef bool (T::*ObjectCallbackType)(Event&); + +private: + ObjectCallbackType _callback; + T* _object; + +public: + ObjectCallback(ObjectCallbackType callback, T* obj): + _callback (callback), + _object (obj) { + } + + virtual bool operator()(Event& ev) { + return (_object->*_callback)(ev); + } +}; + +// The object that facilitates general functions as callbacks. +template +class FunctionCallback: public CallbackInterface { + T* _callback; + +public: + FunctionCallback(T* callback): + _callback(callback) { + } + + virtual bool operator()(Event& ev) { + return (*_callback)(ev); + } +}; + +// The highlevel functor. +class OSGWIDGET_EXPORT Callback { + EVENT_TYPE _type; + void* _data; + + // We use a ref_ptr here so that we don't have to worry about memory. + osg::ref_ptr _callback; + +public: + // Creates a Callback that is bound to a member function. + template + Callback(bool (T::*function)(Event&), T* obj, EVENT_TYPE type, void* data=0): + _type (type), + _data (data), + _callback (new ObjectCallback(function, obj)) { + } + + // Creates a Callback that is bound to a functor pointer. + template + Callback(T* functor, EVENT_TYPE type, void* data=0): + _type (type), + _data (data), + _callback (new FunctionCallback(functor)) { + } + + bool operator()(Event& ev) { + return (*_callback)(ev); + } + + EVENT_TYPE getType() const { + return _type; + } + + void* getData() { + return _data; + } + + const void* getData() const { + return _data; + } +}; + + +class OSGWIDGET_EXPORT EventInterface { +private: + typedef std::list CallbackList; + + unsigned int _eventMask; + CallbackList _callbacks; + +public: + EventInterface(): + _eventMask(EVENT_NONE) { + } + + EventInterface(const EventInterface& ei): + _eventMask (ei._eventMask), + _callbacks (ei._callbacks) { + } + + virtual ~EventInterface() { + } + + // These functions take as their final argument the WindowManager which issued the + // request. This is sometimes useful to get information about key state, etc. + + // Notify the EventInterface object that is has been focused or unfocused; since + // this isn't always bound to a mouse event (i.e., if you want to be able to use + // the TAB key to focus), we need seperate events here. + virtual bool focus (WindowManager*) { return false; } + virtual bool unfocus (WindowManager*) { return false; } + + // Mouse events, pretty self-explanatory. + virtual bool mouseEnter (double, double, WindowManager*) { return false; } + virtual bool mouseOver (double, double, WindowManager*) { return false; } + virtual bool mouseLeave (double, double, WindowManager*) { return false; } + virtual bool mouseDrag (double, double, WindowManager*) { return false; } + virtual bool mousePush (double, double, WindowManager*) { return false; } + virtual bool mouseRelease (double, double, WindowManager*) { return false; } + virtual bool mouseScroll (double, double, WindowManager*) { return false; } + + // These functions pass the osgGA::GUIEventAdapter::KeySymbol and KeyModMask and, + // as above, the WindowManager. + virtual bool keyDown (int, int, WindowManager*) { return false; } + virtual bool keyUp (int, int, WindowManager*) { return false; } + + void setEventMask(unsigned int mask) { + _eventMask = mask; + } + + void addEventMask(unsigned int mask) { + _eventMask |= mask; + } + + void removeEventMask(unsigned int mask) { + _eventMask ^= mask; + } + + unsigned int getEventMask() const { + return _eventMask; + } + + void addCallback(const Callback& cb) { + _callbacks.push_back(cb); + } + + bool callCallbacks(Event& ev) { + if(ev.type == EVENT_NONE || !(_eventMask & ev.type)) return false; + + for(CallbackList::iterator i = _callbacks.begin(); i != _callbacks.end(); i++) { + // 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)(ev)) return true; + } + } + + return false; + } + + bool callMethodAndCallbacks(Event& ev) { + if(ev.type == EVENT_NONE || !(_eventMask & ev.type)) return false; + + bool handled = false; + + if(ev.type == EVENT_FOCUS) handled = focus(ev.getWindowManager()); + + else if(ev.type == EVENT_UNFOCUS) handled = unfocus(ev.getWindowManager()); + + else if(ev.type == EVENT_MOUSE_ENTER) + handled = mouseEnter(ev.x, ev.y, ev.getWindowManager()) + ; + + else if(ev.type == EVENT_MOUSE_OVER) + handled = mouseOver(ev.x, ev.y, ev.getWindowManager()) + ; + + else if(ev.type == EVENT_MOUSE_LEAVE) + handled = mouseLeave(ev.x, ev.y, ev.getWindowManager()) + ; + + else if(ev.type == EVENT_MOUSE_DRAG) + handled = mouseDrag(ev.x, ev.y, ev.getWindowManager()) + ; + + else if(ev.type == EVENT_MOUSE_PUSH) + handled = mousePush(ev.x, ev.y, ev.getWindowManager()) + ; + + else if(ev.type == EVENT_MOUSE_RELEASE) + handled = mouseRelease(ev.x, ev.y, ev.getWindowManager()) + ; + + else if(ev.type == EVENT_MOUSE_SCROLL) + handled = mouseScroll(ev.x, ev.y, ev.getWindowManager()) + ; + + else if(ev.type == EVENT_KEY_DOWN) + handled = keyDown(ev.key, ev.keyMask, ev.getWindowManager()) + ; + + else if(ev.type == EVENT_KEY_UP) + handled = keyUp(ev.key, ev.keyMask, ev.getWindowManager()) + ; + + else return false; + + return callCallbacks(ev) || handled; + } + + bool canFocus () const { return (_eventMask & EVENT_FOCUS) != 0; } + bool canUnfocus () const { return (_eventMask & EVENT_UNFOCUS) != 0; } + + bool canMouseEnter () const { return (_eventMask & EVENT_MOUSE_ENTER) != 0; } + bool canMouseOver () const { return (_eventMask & EVENT_MOUSE_OVER) != 0; } + bool canMouseLeave () const { return (_eventMask & EVENT_MOUSE_LEAVE) != 0; } + bool canMouseDrag () const { return (_eventMask & EVENT_MOUSE_DRAG) != 0; } + bool canMousePush () const { return (_eventMask & EVENT_MOUSE_PUSH) != 0; } + bool canMouseRelease () const { return (_eventMask & EVENT_MOUSE_RELEASE) != 0; } + bool canMouseScroll () const { return (_eventMask & EVENT_MOUSE_SCROLL) != 0; } + + bool canKeyDown () const { return (_eventMask & EVENT_KEY_DOWN) != 0; } + bool canKeyUp () const { return (_eventMask & EVENT_KEY_UP) != 0; } +}; + +} + +#endif diff --git a/include/osgWidget/Export b/include/osgWidget/Export new file mode 100644 index 000000000..1f7afc4ea --- /dev/null +++ b/include/osgWidget/Export @@ -0,0 +1,47 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGWIDGET_EXPORT_ +#define OSGWIDGET_EXPORT_ 1 + +#if defined(_MSC_VER) + #pragma warning( disable : 4244 ) + #pragma warning( disable : 4251 ) + #pragma warning( disable : 4267 ) + #pragma warning( disable : 4275 ) + #pragma warning( disable : 4290 ) + #pragma warning( disable : 4786 ) + #pragma warning( disable : 4305 ) + #pragma warning( disable : 4996 ) +#endif + +#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined( __BCPLUSPLUS__) + # if defined( OSG_LIBRARY_STATIC ) + # define OSGWIDGET_EXPORT + # elif defined( OSGWIDGET_LIBRARY ) + # define OSGWIDGET_EXPORT __declspec(dllexport) + # else + # define OSGWIDGET_EXPORT __declspec(dllimport) + # endif +#else + # define OSGWIDGET_EXPORT +#endif + +/** + +\namespace osgWidet + +The osgWidget is a NodeKit library that extends the core scene graph to support 3D widget set. +*/ + +#endif diff --git a/include/osgWidget/Frame b/include/osgWidget/Frame new file mode 100644 index 000000000..001f94431 --- /dev/null +++ b/include/osgWidget/Frame @@ -0,0 +1,161 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Frame 59 2008-05-15 20:55:31Z cubicool $ + +#ifndef OSGWIDGET_FRAME +#define OSGWIDGET_FRAME + +#include + +namespace osgWidget { + +class OSGWIDGET_EXPORT Frame: public Table { +public: + enum CORNER { + CORNER_LOWER_LEFT, + CORNER_LOWER_RIGHT, + CORNER_UPPER_LEFT, + CORNER_UPPER_RIGHT + }; + + enum BORDER { + BORDER_LEFT, + BORDER_RIGHT, + BORDER_TOP, + BORDER_BOTTOM + }; + +protected: + Widget* _getCorner (CORNER) const; + Widget* _getBorder (BORDER) const; + +public: + static std::string cornerToString (CORNER); + static std::string borderToString (BORDER); + + class OSGWIDGET_EXPORT Corner: public Widget { + CORNER _corner; + + public: + META_Object (osgWidget, Corner); + META_UIObject (Corner); + + Corner (CORNER = CORNER_LOWER_LEFT, point_type = 0.0f, point_type = 0.0f); + Corner (const Corner&, const osg::CopyOp&); + + bool mouseDrag(double, double, WindowManager*); + + CORNER getCorner() const { + return _corner; + } + + void setCorner(CORNER corner) { + _corner = corner; + } + + void setCornerAndName(CORNER corner) { + _corner = corner; + _name = cornerToString(corner); + } + }; + + class OSGWIDGET_EXPORT Border: public Widget { + BORDER _border; + + public: + META_Object (osgWidget, Border); + META_UIObject (Border); + + Border (BORDER = BORDER_LEFT, point_type = 0.0f, point_type = 0.0f); + Border (const Border&, const osg::CopyOp&); + + bool mouseDrag(double, double, WindowManager*); + + BORDER getBorder() const { + return _border; + } + + void setBorder(BORDER border) { + _border = border; + } + + void setBorderAndName(BORDER border) { + _border = border; + _name = borderToString(border); + } + }; + + META_Object (osgWidget, Frame); + META_UIObject (Frame); + + Frame (const std::string& = ""); + 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 + ); + + static Frame* createSimpleFrameWithSingleTexture( + const std::string&, + const std::string&, + point_type, + point_type, + point_type, + point_type, + point_type, + point_type, + Frame* = 0 + ); + + void createSimpleFrame(point_type cw, point_type ch, point_type w, point_type h) { + createSimpleFrame(_name, cw, ch, w, h, 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 + ) { + createSimpleFrameWithSingleTexture(_name, tex, tw, th, cw, ch, w, h, this); + } + + bool setWindow(Window*); + + EmbeddedWindow* getEmbeddedWindow() { + return dynamic_cast(getByRowCol(1, 1)); + } + + const EmbeddedWindow* getEmbeddedWindow() const { + return dynamic_cast(getByRowCol(1, 1)); + } + + Corner* getCorner(CORNER c) { + return dynamic_cast(_getCorner(c)); + } + + const Corner* getCorner(CORNER c) const { + return dynamic_cast(_getCorner(c)); + } + + Border* getBorder(BORDER b) { + return dynamic_cast(_getBorder(b)); + } + + const Border* getBorder(BORDER b) const { + return dynamic_cast(_getBorder(b)); + } +}; + +} + +#endif diff --git a/include/osgWidget/Input b/include/osgWidget/Input new file mode 100644 index 000000000..260ec7da0 --- /dev/null +++ b/include/osgWidget/Input @@ -0,0 +1,77 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Input 45 2008-04-23 16:46:11Z cubicool $ + +#ifndef OSGWIDGET_INPUT +#define OSGWIDGET_INPUT + +#include + +namespace osgWidget { + +class OSGWIDGET_EXPORT Input: public Label { + point_type _xoff; + point_type _yoff; + + unsigned int _index; + unsigned int _size; + unsigned int _cursorIndex; + unsigned int _maxSize; + + std::vector _offsets; + osg::ref_ptr _cursor; + +protected: + virtual void _calculateSize(const XYCoord&); + + void _calculateCursorOffsets(); + +public: + Input(const std::string& = "", const std::string& = "", unsigned int = 20); + + virtual void parented (Window*); + virtual void positioned (); + + virtual bool focus (WindowManager*); + virtual bool unfocus (WindowManager*); + virtual bool keyUp (int, int, WindowManager*); + virtual bool keyDown (int, int, WindowManager*); + + void setCursor(Widget*); + + void setXOffset(point_type xo) { + _xoff = xo; + } + + void setYOffset(point_type yo) { + _yoff = yo; + } + + void setXYOffset(point_type xo, point_type yo) { + _xoff = xo; + _yoff = yo; + } + + osg::Drawable* getCursor() { + return _cursor.get(); + } + + const osg::Drawable* getCursor() const { + return _cursor.get(); + } + + point_type getXOffset() const { + return _xoff; + } + + point_type getYOffset() const { + return _yoff; + } + + XYCoord getXYOffset() const { + return XYCoord(_xoff, _yoff); + } +}; + +} + +#endif diff --git a/include/osgWidget/Label b/include/osgWidget/Label new file mode 100644 index 000000000..be59e1df8 --- /dev/null +++ b/include/osgWidget/Label @@ -0,0 +1,59 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Label 59 2008-05-15 20:55:31Z cubicool $ + +#ifndef OSGWIDGET_LABEL +#define OSGWIDGET_LABEL + +#include +#include +#include + +namespace osgWidget { + +class OSGWIDGET_EXPORT Label: public Widget { + unsigned int _textIndex; + +protected: + osg::ref_ptr _text; + + virtual void _calculateSize(const XYCoord&); + +public: + META_Object (osgWidget, Label); + META_UIObject (Label); + + Label (const std::string& = "", const std::string& = ""); + Label (const Label&, const osg::CopyOp&); + + 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); + void setFontColor (const Color&); + void setShadow (point_type); + + XYCoord getTextSize() const; + + std::string getLabel() const { + return _text->getText().createUTF8EncodedString(); + } + + void setFontColor(point_type r, point_type g, point_type b, point_type a) { + setFontColor(Color(r, g, b, a)); + } + + // For now you only get a const pointer, because we have a highly specific + // interface with the osgText library. + const osgText::Text* getText() const { + return _text.get(); + } +}; + +} + +#endif diff --git a/include/osgWidget/Lua b/include/osgWidget/Lua new file mode 100644 index 000000000..81b612364 --- /dev/null +++ b/include/osgWidget/Lua @@ -0,0 +1,31 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Lua 2 2008-01-24 16:11:26Z cubicool $ + +#ifndef OSGWIDGET_LUA +#define OSGWIDGET_LUA + +#include + +namespace osgWidget { + +// Externally defined; does this work in Windows? +struct LuaEngineData; + +// The actual Engine itself. Every attempt is made to export the implemenation into the +// source file, rather than having it here. +class OSGWIDGET_EXPORT LuaEngine: public ScriptEngine { + LuaEngineData* _data; + WindowManager* _wm; + +public: + LuaEngine(WindowManager* = 0); + + bool initialize (); + bool close (); + bool eval (const std::string&); + bool runFile (const std::string&); +}; + +} + +#endif diff --git a/include/osgWidget/Python b/include/osgWidget/Python new file mode 100644 index 000000000..9cb0d6928 --- /dev/null +++ b/include/osgWidget/Python @@ -0,0 +1,28 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Python 2 2008-01-24 16:11:26Z cubicool $ + +#ifndef OSGWIDGET_PYTHON +#define OSGWIDGET_PYTHON + +#include + +namespace osgWidget { + +struct PythonEngineData; + +class OSGWIDGET_EXPORT PythonEngine: public ScriptEngine { + PythonEngineData* _data; + WindowManager* _wm; + +public: + PythonEngine(WindowManager* = 0); + + bool initialize (); + bool close (); + bool eval (const std::string&); + bool runFile (const std::string&); +}; + +} + +#endif diff --git a/include/osgWidget/ScriptEngine b/include/osgWidget/ScriptEngine new file mode 100644 index 000000000..7f2550e9f --- /dev/null +++ b/include/osgWidget/ScriptEngine @@ -0,0 +1,29 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: ScriptEngine 2 2008-01-24 16:11:26Z cubicool $ + +#ifndef OSGWIDGET_SCRIPT_ENGINE +#define OSGWIDGET_SCRIPT_ENGINE + +#include + +namespace osgWidget { + +// An interface for our scripting API so that we can have a unified way to talk to both +// Lua and Python; perhaps even more! Furthermore, this will allow us to put the +// entire implementation into a source file... +class ScriptEngine: public osg::Referenced { +protected: + std::string _err; + +public: + virtual bool initialize () { return false; } + virtual bool close () { return false; } + virtual bool eval (const std::string&) { return false; } + virtual bool runFile (const std::string&) { return false; } + + virtual const std::string& getLastErrorText() const { return _err; } +}; + +} + +#endif diff --git a/include/osgWidget/StyleInterface b/include/osgWidget/StyleInterface new file mode 100644 index 000000000..f3acf9856 --- /dev/null +++ b/include/osgWidget/StyleInterface @@ -0,0 +1,39 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: StyleInterface 63 2008-06-30 19:18:37Z cubicool $ + +#ifndef OSGWIDGET_STYLE_INTERFACE +#define OSGWIDGET_STYLE_INTERFACE + +namespace osgWidget { + +#include + +class OSGWIDGET_EXPORT StyleInterface { +private: + std::string _style; + +public: + StyleInterface(): + _style("") { + } + + StyleInterface(const StyleInterface& si): + _style(si._style) { + } + + void setStyle(const std::string& style) { + _style = style; + } + + std::string& getStyle() { + return _style; + } + + const std::string& getStyle() const { + return _style; + } +}; + +} + +#endif diff --git a/include/osgWidget/StyleManager b/include/osgWidget/StyleManager new file mode 100644 index 000000000..b1ffbceec --- /dev/null +++ b/include/osgWidget/StyleManager @@ -0,0 +1,175 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: StyleManager 61 2008-06-24 20:24:26Z cubicool $ + +#ifndef OSGWIDGET_STYLE_MANAGER +#define OSGWIDGET_STYLE_MANAGER + +#include +#include +#include +#include +#include + +namespace osgWidget { + +typedef osgDB::FieldReaderIterator& Reader; + +class OSGWIDGET_EXPORT Style: public osg::Object { + std::string _style; + + bool _match(const char* seq, Reader r) { + if(r.matchSequence(seq)) { + ++r; + + return true; + } + + return false; + } + +public: + META_Object(osgWidget, Style); + + // Class and contents... + Style (const std::string& = "", const std::string& = ""); + Style (const Style&, const osg::CopyOp&); + + virtual bool applyStyle (Widget*, Reader); + virtual bool applyStyle (Label*, Reader); + virtual bool applyStyle (Input*, Reader); + virtual bool applyStyle (Window*, Reader); + virtual bool applyStyle (Window::EmbeddedWindow*, Reader); + virtual bool applyStyle (Box*, Reader); + virtual bool applyStyle (Frame::Corner*, Reader); + virtual bool applyStyle (Frame::Border*, Reader); + + void setStyle(const std::string& style) { + _style = style; + } + + std::string& getStyle() { + return _style; + } + + const std::string& getStyle() const { + return _style; + } + + static Widget::LAYER strToLayer (const std::string&); + static Widget::VERTICAL_ALIGNMENT strToVAlign (const std::string&); + static Widget::HORIZONTAL_ALIGNMENT strToHAlign (const std::string&); + static Widget::COORDINATE_MODE strToCoordMode (const std::string&); + static bool strToFill (const std::string&); +}; + +class OSGWIDGET_EXPORT StyleManager: public osg::Object { +public: + typedef std::map > Styles; + typedef Styles::iterator Iterator; + typedef Styles::const_iterator ConstIterator; + +private: + Styles _styles; + + template + bool _applySpecificStyle(T* t, const std::string& style) { + osgDB::FieldReaderIterator r; + + std::istringstream input(_styles[style]->getStyle()); + + r.attach(&input); + + bool inc = false; + + while(!r.eof()) if(_styles[style]->applyStyle(t, r)) inc = true; + + return inc; + } + + template + bool _coerceAndApply( + osg::Object* obj, + const std::string& style, + const std::string& className + ) { + T* t = dynamic_cast(obj); + + if(!t) { + warn() + << "An attempt was made to coerce Object [" << obj->getName() + << "] into a " << className << " but failed." << std::endl + ; + + return 0; + } + + return _applySpecificStyle(t, style); + } + + + bool _applyStyleToObject(osg::Object*, const std::string&); + + // 1. Check and see if the explicit FULL path is available. + // 2. Check and see if each component working backward--minus the last--is available. + // 3. Check to see if just the className() is available. + template + bool _applyStyles(T* t) { + if(!t) { + warn() + << "Cannot call StyleManager::applyStyle with a NULL object." + << std::endl + ; + + return false; + } + + osg::Object* obj = dynamic_cast(t); + + if(!obj) { + warn() + << "Cannot coerce object into osg::Object in StyleManager:::applyStyle" + << std::endl + ; + + return false; + } + + std::string c = obj->className(); + + // Case 3; there's no explicit Style set, so see if there's one for the class. + if(t->getStyle().empty()) { + // Couldn't find the className, so we exit. + if(_styles.find(c) == _styles.end()) return false; + + return _applyStyleToObject(obj, c); + } + + // Case 1... + if(_styles.find(t->getStyle()) != _styles.end()) return _applyStyleToObject( + obj, + t->getStyle() + ); + + return false; + } + +public: + META_Object(osgWidget, StyleManager); + + StyleManager (); + StyleManager (const StyleManager&, const osg::CopyOp&); + + bool addStyle(Style*); + + bool applyStyles(Widget* widget) { + return _applyStyles(widget); + } + + bool applyStyles(Window* window) { + return _applyStyles(window); + } +}; + +} + +#endif diff --git a/include/osgWidget/Table b/include/osgWidget/Table new file mode 100644 index 000000000..12db854cd --- /dev/null +++ b/include/osgWidget/Table @@ -0,0 +1,63 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Table 48 2008-05-05 14:13:20Z cubicool $ + +#ifndef OSGWIDGET_TABLE +#define OSGWIDGET_TABLE + +#include + +namespace osgWidget { + +class OSGWIDGET_EXPORT Table: public Window { + unsigned int _rows; + unsigned int _cols; + unsigned int _lastRowAdd; + unsigned int _lastColAdd; + +public: + typedef std::vector CellSizes; + +protected: + unsigned int _calculateIndex(unsigned int, unsigned int) const; + + void _getRows (CellSizes&, Getter) const; + void _getColumns (CellSizes&, Getter) const; + + virtual void _resizeImplementation(point_type, point_type); + + virtual Sizes _getWidthImplementation () const; + virtual Sizes _getHeightImplementation () const; + +public: + META_Object (osgWidget, Table); + META_UIObject (Table); + + Table (const std::string& = "", unsigned int = 0, unsigned int = 0); + Table (const Table&, const osg::CopyOp&); + + virtual bool addWidget (Widget*); + virtual bool addWidget (Widget*, unsigned int, unsigned int); + + void getRowHeights (CellSizes&) const; + void getRowMinHeights (CellSizes&) const; + void getColumnWidths (CellSizes&) const; + void getColumnMinWidths (CellSizes&) const; + + void addHeightToRow (unsigned int, point_type); + void addWidthToColumn (unsigned int, point_type); + + bool isRowVerticallyFillable (unsigned int) const; + bool isColumnHorizontallyFillable (unsigned int) const; + + Widget* getByRowCol(unsigned int row, unsigned int col) { + return getObjects()[_calculateIndex(row, col)].get(); + } + + const Widget* getByRowCol(unsigned int row, unsigned int col) const { + return getObjects()[_calculateIndex(row, col)].get(); + } +}; + +} + +#endif diff --git a/include/osgWidget/Types b/include/osgWidget/Types new file mode 100644 index 000000000..e65c65926 --- /dev/null +++ b/include/osgWidget/Types @@ -0,0 +1,31 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Types 33 2008-04-04 19:03:12Z cubicool $ + +#ifndef OSGWIDGET_TYPES +#define OSGWIDGET_TYPES + +#include +#include + +namespace osgWidget { + +typedef osg::Vec2Array TexCoordArray; +typedef osg::Vec3Array PointArray; +typedef osg::Vec4Array ColorArray; + +typedef TexCoordArray::value_type TexCoord; +typedef PointArray::value_type Point; +typedef ColorArray::value_type Color; + +typedef TexCoord::value_type texcoord_type; +typedef Point::value_type point_type; +typedef Color::value_type color_type; + +typedef osg::Vec2 XYCoord; +typedef osg::Vec4 Quad; + +typedef osg::Matrix::value_type matrix_type; + +} + +#endif diff --git a/include/osgWidget/UIObjectParent b/include/osgWidget/UIObjectParent new file mode 100644 index 000000000..5aaf5e1da --- /dev/null +++ b/include/osgWidget/UIObjectParent @@ -0,0 +1,123 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: UIObjectParent 55 2008-05-12 19:14:42Z cubicool $ + +#ifndef OSGWIDGET_UI_OBJECT_PARENT +#define OSGWIDGET_UI_OBEJCT_PARENT + +namespace osgWidget { + +#define META_UIObject(name) \ + name * cloneAs(\ + const std::string& newName, \ + const osg::CopyOp& co = osg::CopyOp::DEEP_COPY_ALL \ + ) const { \ + name * obj = dynamic_cast(this->clone(co)); \ + obj->setName(newName); \ + return obj; \ + } + +template +class UIObjectParent { +public: + typedef T object_type; + typedef osg::observer_ptr ptr_type; + typedef std::vector Vector; + typedef typename Vector::iterator Iterator; + typedef typename Vector::const_iterator ConstIterator; + +protected: + Vector _objects; + +public: + Iterator begin() { + return _objects.begin(); + } + + ConstIterator begin() const { + return _objects.begin(); + } + + Iterator end() { + return _objects.end(); + } + + ConstIterator end() const { + return _objects.end(); + } + + typename Vector::size_type size() const { + return _objects.size(); + } + +private: + // I had to add this to avoid ambiguity errors with MSVC. Garbage. + object_type* _getByName(const std::string& name) const { + for(ConstIterator i = begin(); i != end(); i++) { + if(i->valid() && i->get()->getName() == name) return i->get(); + } + + return 0; + } + + object_type* _getByIndex(unsigned int index) const { + for(ConstIterator i = begin(); i != end(); i++) { + if(i->valid() && i->get()->getIndex() == index) return i->get(); + } + + return 0; + } + +public: + object_type* getByName(const std::string& name) { + return _getByName(name); + } + + const object_type* getByName(const std::string& name) const { + return _getByName(name); + } + + object_type* getByIndex(unsigned int index) { + return _getByIndex(index); + } + + const object_type* getByIndex(unsigned int index) const { + return _getByIndex(index); + } + + unsigned int getNumObjects() const { + return _objects.size(); + } + + Vector& getObjects() { + return _objects; + } + + const Vector& getObjects() const { + return _objects; + } + +protected: + bool _remove(object_type* obj) { + Iterator i = std::find(begin(), end(), obj); + + if(i == end()) return false; + + _objects.erase(i); + + return true; + } + + bool _removeByName(const std::string& name) { + for(Iterator i = begin(); i != end(); i++) if(i->get()->getName() == name) { + _objects.erase(i); + + return true; + } + + return false; + } +}; + +} + +#endif diff --git a/include/osgWidget/Util b/include/osgWidget/Util new file mode 100644 index 000000000..b8cee8a82 --- /dev/null +++ b/include/osgWidget/Util @@ -0,0 +1,79 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Util 59 2008-05-15 20:55:31Z cubicool $ + +#ifndef OSGWIDGET_UTIL +#define OSGWIDGET_UTIL + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace osgWidget { + +// These are NOT OSGWIDGET_EXPORT'd; these are internal only! + +inline std::ostream& _notify(osg::NotifySeverity ns = osg::INFO) { + std::ostream& n = osg::notify(ns); + + return n << "osgWidget: "; +} + +inline std::ostream& warn() { + return _notify(osg::WARN); +} + +inline std::ostream& info() { + return _notify(); +} + +inline std::string lowerCase(const std::string& str) { + std::string s = str; + + // TODO: Why can't I specify std::tolower? + std::transform(s.begin(), s.end(), s.begin(), ::tolower); + + return s; +} + +// TODO: Is this totally ghetto or what? +template +inline bool hasDecimal(T v) { + return (v - static_cast(static_cast(v))) > 0.0f; +} + +class WindowManager; + +// These ARE OSGWIDGET_EXPORT'd for your convenience. :) + +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); + +// 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*); + +} + +#endif diff --git a/include/osgWidget/Version b/include/osgWidget/Version new file mode 100644 index 000000000..7310bbdc5 --- /dev/null +++ b/include/osgWidget/Version @@ -0,0 +1,23 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Version 64 2008-06-30 21:32:00Z cubicool $ + +#ifndef OSGWIDGET_VERSION +#define OSGWIDGET_VERSION + +#include + +extern "C" { + +OSGWIDGET_EXPORT unsigned int osgWidgetGetMajorVersion (); +OSGWIDGET_EXPORT unsigned int osgWidgetGetMinorVersion (); +OSGWIDGET_EXPORT unsigned int osgWidgetGetPatchVersion (); +OSGWIDGET_EXPORT const char* osgWidgetGetExtraText (); +OSGWIDGET_EXPORT const char* osgWidgetGetVersion (); +OSGWIDGET_EXPORT const char* osgWidgetGetLibraryName (); +OSGWIDGET_EXPORT bool osgWidgetVersionMinimum (unsigned int, unsigned int, unsigned int); +OSGWIDGET_EXPORT bool osgWidgetVersionMaximum (unsigned int, unsigned int, unsigned int); +OSGWIDGET_EXPORT bool osgWidgetVersionRequired (unsigned int, unsigned int, unsigned int); + +} + +#endif diff --git a/include/osgWidget/ViewerEventHandlers b/include/osgWidget/ViewerEventHandlers new file mode 100644 index 000000000..b78e8cb65 --- /dev/null +++ b/include/osgWidget/ViewerEventHandlers @@ -0,0 +1,78 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: ViewerEventHandlers 31 2008-04-01 19:36:41Z cubicool $ + +#ifndef OSGWIDGET_VIEWER_EVENT_HANDLERS +#define OSGWIDGET_VIEWER_EVENT_HANDLERS + +#include +#include +#include + +// NOTE! These are all just examples of some default event handlers--they are not +// required. You are more than welcome to provide your own even handlers that +// communicate with a WindowManager using it's public API. + +namespace osgWidget { + +// This handles the pressing/moving of mouse buttons, etc. +class OSGWIDGET_EXPORT MouseHandler: public osgGA::GUIEventHandler { + osg::ref_ptr _wm; + + bool _handleMousePush (float, float, int); + bool _handleMouseRelease (float, float, int); + bool _handleMouseDoubleClick (float, float, int); + bool _handleMouseDrag (float, float, int); + bool _handleMouseMove (float, float, int); + bool _handleMouseScroll (float, float, int); + + typedef bool (MouseHandler::*MouseAction)(float, float, int); + typedef bool (WindowManager::*MouseEvent)(float, float); + + MouseAction _isMouseEvent (osgGA::GUIEventAdapter::EventType) const; + bool _doMouseEvent (float, float, MouseEvent); + +public: + MouseHandler(WindowManager*); + + virtual bool handle( + const osgGA::GUIEventAdapter&, + osgGA::GUIActionAdapter&, + osg::Object*, + osg::NodeVisitor* + ); +}; + +// This handles the forwarding of keypress events. +class OSGWIDGET_EXPORT KeyboardHandler: public osgGA::GUIEventHandler { + osg::ref_ptr _wm; + +public: + KeyboardHandler(WindowManager*); + + virtual bool handle( + const osgGA::GUIEventAdapter&, + osgGA::GUIActionAdapter&, + osg::Object*, + osg::NodeVisitor* + ); +}; + +// This class offers a default kind of handling for resizing. +class OSGWIDGET_EXPORT ResizeHandler: public osgGA::GUIEventHandler { + osg::ref_ptr _wm; + osg::ref_ptr _camera; + +public: + ResizeHandler(WindowManager*, osg::Camera*); + + virtual bool handle( + const osgGA::GUIEventAdapter&, + osgGA::GUIActionAdapter&, + osg::Object*, + osg::NodeVisitor* + ); +}; + +} + +#endif diff --git a/include/osgWidget/Widget b/include/osgWidget/Widget new file mode 100644 index 000000000..310f88ed1 --- /dev/null +++ b/include/osgWidget/Widget @@ -0,0 +1,626 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Widget 64 2008-06-30 21:32:00Z cubicool $ + +#ifndef OSGWIDGET_WIDGET +#define OSGWIDGET_WIDGET + +#include +#include +#include +#include +#include + +namespace osgWidget { + +class Window; +class WindowManager; + +// A Widget is a rectangular region that recieves events about the state of various input +// devices such as the pointer and keyboard. It is aware of it's width, height, and origin but +// nothing else. It is the job of higher-level container objects to organize layouts and +// the like, and to contextualize the meaning of the widgets "origin" (whether it is absolute +// or relative). +class OSGWIDGET_EXPORT Widget: public osg::Geometry, public EventInterface, public StyleInterface { +public: + enum POINT { + LOWER_LEFT = 0, + LOWER_RIGHT = 1, + UPPER_RIGHT = 2, + UPPER_LEFT = 3, + LL = LOWER_LEFT, + LR = LOWER_RIGHT, + UR = UPPER_RIGHT, + UL = UPPER_LEFT, + ALL_POINTS = 4 + }; + + enum LAYER { + LAYER_TOP = 20, + LAYER_HIGH = 15, + LAYER_MIDDLE = 10, + LAYER_LOW = 5, + LAYER_BG = 0 + }; + + enum VERTICAL_ALIGNMENT { + VA_CENTER, + VA_TOP, + VA_BOTTOM + }; + + enum HORIZONTAL_ALIGNMENT { + HA_CENTER, + HA_LEFT, + HA_RIGHT + }; + + enum COORDINATE_MODE { + CM_ABSOLUTE, + CM_RELATIVE + }; + +private: + friend class Window; + + // TODO: Because of the current class design, I don't think it's possible to + // have a ref_ptr here. :( + Window* _parent; + + unsigned int _index; + unsigned int _layer; + + // Padding is the value of pixels of space between whatever the widget is "contianed" + // in and the point at which it starts getting placed. + point_type _padLeft; + point_type _padRight; + point_type _padTop; + point_type _padBottom; + + // The alignments are used in conjuction when the widget is NOT set to fill. + VERTICAL_ALIGNMENT _valign; + HORIZONTAL_ALIGNMENT _halign; + + // This flag determines how sizing values are interpretted by setDimensions(). + COORDINATE_MODE _coordMode; + + // These are the relative values, which are not stored directly in our verts + // array but kept around for calculation later. + Quad _relCoords; + + // This fill flag determines whether or not the widget will resize itself to fill + // all available space. + bool _canFill; + + // Set this to false in an implementation to prevent copying. + bool _canClone; + + // This variable is only used by the Window object to determine if it's necessary + // to call managed(). + bool _isManaged; + + // This variable is like _isManaged; it is used to store whether the Widget has + // been styled yet. + bool _isStyled; + + // Set these variables to be the minimum size of a Widget so that it cannot be + // resized any smaller than this. + point_type _minWidth; + point_type _minHeight; + + static osg::ref_ptr _norms; + + WindowManager* _getWindowManager () const; + osg::Image* _getImage () const; + +protected: + point_type _calculateZ(unsigned int) const; + + PointArray* _verts() { + return dynamic_cast(getVertexArray()); + } + + const PointArray* _verts() const { + return dynamic_cast(getVertexArray()); + } + + ColorArray* _cols() { + return dynamic_cast(getColorArray()); + } + + const ColorArray* _cols() const { + return dynamic_cast(getColorArray()); + } + + TexCoordArray* _texs() { + return dynamic_cast(getTexCoordArray(0)); + } + + const TexCoordArray* _texs() const { + return dynamic_cast(getTexCoordArray(0)); + } + + osg::Texture2D* _texture() { + return dynamic_cast( + getStateSet()->getTextureAttribute(0, osg::StateAttribute::TEXTURE) + ); + } + + const osg::Texture2D* _texture() const { + return dynamic_cast( + getStateSet()->getTextureAttribute(0, osg::StateAttribute::TEXTURE) + ); + } + + osg::Image* _image() { + return _getImage(); + } + + const osg::Image* _image() const { + return _getImage(); + } + +public: + META_Object (osgWidget, Widget); + META_UIObject (Widget); + + Widget (const std::string& = "", point_type = 0.0f, point_type = 0.0f); + Widget (const Widget&, const osg::CopyOp&); + + virtual ~Widget() { + } + + // This method is called when the widget is added to a Window; this is useful + // when the widget needs to do something advanced (like a Label). The parent + // is passed as the first argument, although _parent should already be set. + virtual void parented(Window*) { + } + + virtual void unparented(Window*) { + } + + // This method is called when the widget's parent Window is added to a + // WindowManager object. The base managed method (WHICH YOU MUST REMEMBER + // TO CALL IN YOUR DERIVED METHODS!) sets the TexMat properly depending + // on what coordinate system you're using. + virtual void managed(WindowManager*); + + virtual void unmanaged(WindowManager*) { + } + + // This method is called when the widget is resized or reallocated in any + // way. This is useful when the widget manages some internal Drawables that need + // to be modified in some way. + virtual void positioned() { + } + + void setDimensions( + point_type = -1.0f, + point_type = -1.0f, + point_type = -1.0f, + point_type = -1.0f, + point_type = -1.0f + ); + + void setPadding (point_type); + void setColor (color_type, color_type, color_type, color_type, POINT = ALL_POINTS); + void addColor (color_type, color_type, color_type, color_type, POINT = ALL_POINTS); + void setTexCoord (texcoord_type, texcoord_type, POINT = ALL_POINTS); + + // These are additional texture coordinate setting methods. + // This method will use a given origin as the LOWER_LEFT point and texture the + // remaining area based on some width and height values. + void setTexCoordRegion(point_type, point_type, point_type, point_type); + + // These are convenience methods for setting up wrapping modes. + void setTexCoordWrapHorizontal (); + void setTexCoordWrapVertical (); + + bool setImage (osg::Image*, bool=false); + bool setImage (const std::string&, bool=false); + + void addX (point_type); + void addY (point_type); + void addWidth (point_type); + void addHeight (point_type); + void addOrigin (point_type, point_type); + void addSize (point_type, point_type); + + point_type getWidth () const; + point_type getHeight () const; + point_type getX () const; + point_type getY () const; + point_type getZ () const; + point_type getPadHorizontal () const; + point_type getPadVertical () const; + + const Point& getPoint (POINT = ALL_POINTS) const; + const Color& getColor (POINT = ALL_POINTS) const; + const TexCoord& getTexCoord (POINT = ALL_POINTS) const; + + POINT convertPoint (POINT) const; + Color getImageColorAtXY (point_type x, point_type y) const; + XYCoord localXY (double, double) const; + + bool isPaddingUniform() const; + + bool isManaged() const { + return _isManaged; + } + + bool isStyled() const { + return _isStyled; + } + + void setDimensions(const Quad& q, point_type z = -1.0f) { + setDimensions(q[0], q[1], q[2], q[4], z); + } + + void setX(point_type x) { + setDimensions(x); + } + + void setY(point_type y) { + setDimensions(-1.0f, y); + } + + // This method should be use with extreme caution. + void setZ(point_type z) { + setDimensions(-1.0f, -1.0f, -1.0f, -1.0f, z); + } + + void setWidth(point_type w) { + setDimensions(-1.0f, -1.0f, w); + } + + void setHeight(point_type h) { + setDimensions(-1.0f, -1.0f, -1.0f, h); + } + + void setOrigin(point_type x, point_type y) { + setDimensions(x, y); + } + + void setOrigin(const XYCoord& xy) { + setOrigin(xy.x(), xy.y()); + } + + void setSize(point_type w, point_type h) { + setDimensions(-1.0f, -1.0f, w, h); + } + + void setSize(const XYCoord& xy) { + setSize(xy.x(), xy.y()); + } + + void setColor(const Color& col, POINT p = ALL_POINTS) { + setColor(col.r(), col.g(), col.b(), col.a(), p); + } + + void setTexCoord(const XYCoord& xy, POINT p = ALL_POINTS) { + setTexCoord(xy.x(), xy.y(), p); + } + + void setTexCoordRegion(const XYCoord& xy, point_type w, point_type h) { + setTexCoordRegion(xy.x(), xy.y(), w, h); + } + + void addColor(const Color& col, POINT p = ALL_POINTS) { + addColor(col.r(), col.g(), col.b(), col.a(), p); + } + + void addOrigin(const XYCoord& xy) { + addOrigin(xy.x(), xy.y()); + } + + void addSize(const XYCoord& xy) { + addSize(xy.x(), xy.y()); + } + + void setMinimumSize(point_type width, point_type height) { + _minWidth = width; + _minHeight = height; + } + + void setMinimumSize(const XYCoord& xy) { + setMinimumSize(xy.x(), xy.y()); + } + + // TODO: Refine this... + void setLayer(LAYER l, unsigned int offset = 0) { + _layer = l + offset; + } + + void setPadLeft(point_type p) { + _padLeft = p; + } + + void setPadRight(point_type p) { + _padRight = p; + } + + void setPadTop(point_type p) { + _padTop = p; + } + + void setPadBottom(point_type p) { + _padBottom = p; + } + + void setAlignHorizontal(HORIZONTAL_ALIGNMENT h) { + _halign = h; + } + + void setAlignVertical(VERTICAL_ALIGNMENT v) { + _valign = v; + } + + void setCoordinateMode(COORDINATE_MODE cm) { + _coordMode = cm; + } + + void setCanFill(bool f) { + _canFill = f; + } + + void setCanClone(bool c) { + _canClone = c; + } + + WindowManager* getWindowManager() { + return _getWindowManager(); + } + + const WindowManager* getWindowManager() const { + return _getWindowManager(); + } + + Window* getParent() { + return _parent; + } + + const Window* getParent() const { + return _parent; + } + + unsigned int getIndex() const { + return _index; + } + + XYCoord getOrigin() const { + return XYCoord(getX(), getY()); + } + + Color getImageColorAtXY(const XYCoord& xy) const { + return getImageColorAtXY(xy.x(), xy.y()); + } + + Color getImageColorAtPointerXY(double x, double y) const { + return getImageColorAtXY(localXY(x, y)); + } + + Point getPosition() const { + return Point(getX(), getY(), getZ()); + } + + XYCoord getSize() const { + return XYCoord(getWidth(), getHeight()); + } + + Quad getDimensions() const { + return Quad(getX(), getY(), getWidth(), getHeight()); + } + + point_type getPadLeft() const { + return _padLeft; + } + + point_type getPadRight() const { + return _padRight; + } + + point_type getPadTop() const { + return _padTop; + } + + point_type getPadBottom() const { + return _padBottom; + } + + HORIZONTAL_ALIGNMENT getAlignHorizontal() const { + return _halign; + } + + VERTICAL_ALIGNMENT getAlignVertical() const { + return _valign; + } + + COORDINATE_MODE getCoordinateMode() const { + return _coordMode; + } + + bool canFill() const { + return _canFill; + } + + bool canClone() const { + return _canClone; + } + + // This casts the bool _fill variable to be used in iteratively in functions such + // as Window::_accumulate and whatnot. + point_type getFillAsNumeric() const { + return static_cast(_canFill); + } + + point_type getWidthTotal() const { + return getWidth() + getPadHorizontal(); + } + + point_type getHeightTotal() const { + return getHeight() + getPadVertical(); + } + + point_type getMinWidth() const { + return _minWidth; + } + + point_type getMinHeight() const { + return _minHeight; + } + + point_type getMinWidthTotal() const { + return _minWidth + getPadHorizontal(); + } + + point_type getMinHeightTotal() const { + return _minHeight + getPadVertical(); + } + + unsigned int getLayer() const { + return _layer; + } +}; + +typedef std::list > WidgetList; + +// A Widget subclass that prints stuff using osg::notify(). :) +struct NotifyWidget: public Widget { + META_Object(osgWidget, NotifyWidget); + + NotifyWidget(const std::string& n = "", point_type w = 0.0f, point_type h = 0.0f): + Widget(n, w, h) { + setEventMask(EVENT_ALL); + } + + NotifyWidget(const NotifyWidget& widget, const osg::CopyOp& co): + Widget(widget, co) { + } + + bool focus(const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > focus called" << std::endl; + + return false; + } + + bool unfocus(const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > unfocus called" << std::endl; + + return false; + } + + bool mouseEnter(double, double, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > mouseEnter called" << std::endl; + + return false; + } + + bool mouseOver(double, double, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > mouseOver called" << std::endl; + + return false; + } + + bool mouseLeave(double, double, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > mouseLeave called" << std::endl; + + return false; + } + + bool mouseDrag(double, double, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > mouseDrag called" << std::endl; + + return false; + } + + bool mousePush(double, double, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > mousePush called" << std::endl; + + return false; + } + + bool mouseRelease(double, double, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > mouseRelease called" << std::endl; + + return false; + } + + bool mouseScroll(double, double, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > mouseScroll called" << std::endl; + + return false; + } + + bool keyPress(int, int, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > keyPress called" << std::endl; + + return false; + } + + bool keyRelease(int, int, const WindowManager*) { + osg::notify(osg::NOTICE) << _name << " > keyRelease called" << std::endl; + + return false; + } +}; + +// A Widget that eats all events and returns true. +struct NullWidget: public Widget { + META_Object(osgWidget, NullWidget); + + NullWidget(const std::string& n = "", point_type w = 0.0f, point_type h = 0.0f): + Widget(n, w, h) { + setEventMask(EVENT_ALL); + } + + NullWidget(const NullWidget& widget, const osg::CopyOp& co): + Widget(widget, co) { + } + + bool focus(const WindowManager*) { + return true; + } + + bool unfocus(const WindowManager*) { + return true; + } + + bool mouseEnter(double, double, const WindowManager*) { + return true; + } + + bool mouseOver(double, double, const WindowManager*) { + return true; + } + + bool mouseLeave(double, double, const WindowManager*) { + return true; + } + + bool mouseDrag(double, double, const WindowManager*) { + return true; + } + + bool mousePush(double, double, const WindowManager*) { + return true; + } + + bool mouseRelease(double, double, const WindowManager*) { + return true; + } + + bool mouseScroll(double, double, const WindowManager*) { + return true; + } + + bool keyPress(int, int, const WindowManager*) { + return true; + } + + bool keyRelease(int, int, const WindowManager*) { + return true; + } +}; + +} + +#endif diff --git a/include/osgWidget/Window b/include/osgWidget/Window new file mode 100644 index 000000000..566424850 --- /dev/null +++ b/include/osgWidget/Window @@ -0,0 +1,636 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Window 66 2008-07-14 21:54:09Z cubicool $ + +#ifndef OSGWIDGET_WINDOW +#define OSGWIDGET_WINDOW + +#include +#include +#include +#include +#include +#include +#include + +namespace osgWidget { + +// These are helper callbacks you can attach to Windows that will make them moveable, +// rotatable, and scalable respectively. +bool callbackWindowMove (Event&); +bool callbackWindowRotate (Event&); +bool callbackWindowScale (Event&); + +// These are helper callbacks you can attach to Windows to that will make various +// keyboard events behave as you might imagine. +bool callbackWindowTabFocus(Event&); + +class OSGWIDGET_EXPORT Window: + public osg::MatrixTransform, + public UIObjectParent, + public EventInterface, + public StyleInterface +{ +public: + typedef std::list > WindowList; + + struct Sizes { + point_type cur; + point_type min; + + Sizes(point_type c = -1.0f, point_type m = -1.0f): + cur(c), + min(m) { + } + }; + + // TODO: This is a class that puts (embeds) the Window inside of a Widget + // interface, to help assemble Windows with Windows, and what have you. + class OSGWIDGET_EXPORT EmbeddedWindow: public Widget { + osg::ref_ptr _window; + + public: + META_Object (osgWidget::Window, EmbeddedWindow); + META_UIObject (EmbeddedWindow); + + EmbeddedWindow (const std::string& = "", point_type = 0.0f, point_type = 0.0f); + EmbeddedWindow (const EmbeddedWindow&, const osg::CopyOp&); + + virtual void parented (Window*); + virtual void unparented (Window*); + virtual void managed (WindowManager*); + virtual void unmanaged (WindowManager*); + virtual void positioned (); + + bool setWindow(Window*); + + Window* getWindow() { + return _window.get(); + } + + const Window* getWindow() const { + return _window.get(); + } + }; + + // These correspond to special regions honored by the WindowManager. Most Windows + // will want to be NONE, unless they need to exist in the foreground or background + // for some reason. + enum STRATA { + STRATA_NONE, + STRATA_BACKGROUND, + STRATA_FOREGROUND + }; + + // If you only want to display a portion of a Window (such as when it is embedded), + // you will need to set the VISIBILITY_MODE to WM_PARTIAL. Otherwise, the entire + // Window is visible by default. The final enum, VM_ENTIRE, says that no Scissoring + // should take place at all, and is useful in cases where you want to properly + // scale or rotate Windows. + enum VISIBILITY_MODE { + VM_FULL, + VM_PARTIAL, + VM_ENTIRE + }; + + // Anchors are very similar in that they allow us to pre-apply transformations in the + // call to Window::update() that allow us to position a Window somewhere relative + // to the WindowManger's viewable area. However, unlike the ALIGNMENT enums, these + // are totally optional (whereas a Widget must always have some ALIGNMENT value set. + enum VERTICAL_ANCHOR { + VA_NONE, + VA_CENTER, + VA_TOP, + VA_BOTTOM + }; + + enum HORIZONTAL_ANCHOR { + HA_NONE, + HA_CENTER, + HA_LEFT, + HA_RIGHT + }; + + +protected: + typedef point_type (Widget::*Getter)() const; + + typedef std::less Less; + typedef std::greater Greater; + typedef std::plus Plus; + +private: + friend class WindowManager; + + // The (optional) Window that this Window is parented inside. + Window* _parent; + + // The WindowManger to which this window is attached. + WindowManager* _wm; + + // The positional index this Node holds within it's parent WindowManager. + unsigned int _index; + + // The X and Y values of the Window (origin). + matrix_type _x; + matrix_type _y; + + // A pair of values representing the currently calculated Z value and the + // depth range for all children to be used during the call to update(). + matrix_type _z; + matrix_type _zRange; + + // This is a special value that can be used to "force" a Window not to be + // focusable and instead always exist in the foreground or background. + STRATA _strata; + + // A flag determining whether our visible area is the full Window or rather + // a portion of the Window. + VISIBILITY_MODE _vis; + + // A rotation value in degrees. + matrix_type _r; + + // This will also need to adjust geom internally so that picking is correct. + matrix_type _s; + + matrix_type _scaleDenom; + + Sizes _width; + Sizes _height; + + VERTICAL_ANCHOR _vAnchor; + HORIZONTAL_ANCHOR _hAnchor; + + // Not all windows have widgets that can focus, but if they do this should + // be a pointer to it. + osg::observer_ptr _focused; + + // The "visible" area that will define both the glScissor bounds AND will + // be used to make sure our pick is valid. The values herein correspond to + // X, Y, W, and H--in that order. + Quad _visibleArea; + + // This helper method is used by _compare<>() and _accumulate<>(), so ignore this + // function and go see the docs for those instead. This thing is huge and unwieldy + // and not to be triffled with! :) + template + point_type _forEachAssignOrApply( + Getter get, + int begin, + int end, + int add, + bool assign + ) const { + point_type val = 0.0f; + unsigned int c = begin; + + ConstIterator e = end > 0 ? _objects.begin() + end : _objects.end() + end; + + // I WARNED YOU! If you try and understand what this does your head will + // explode! But let me say a few things: in MSVC you can't add to an iterator + // such that the add will cause it to increment past the end of the container. + // This appears to be safe in GCC, where it will just return the last + // item therein, but causes an assertion error in other compilers. I'm not + // sure if there is a cleaner remedy for this, so what we do for now is keep a + // count variable called "c" that makes sure our iterator's opterator+() + // method is safe to call. + for( + ConstIterator i = _objects.begin() + begin; + i < e; + c += add + ) { + point_type v = 0.0f; + + if(i->valid()) v = (i->get()->*get)(); + + // If you want to assign to val, and NOT add a sequence of them... + if(assign) { + if(T()(v, val)) val = v; + } + + // If you want to accumulate a value INTO val... + else val = T()(v, val); + + // Make sure our iterator is safe to increment. Otherwise, set it to + // whatever end is. + // TODO: This isn't 100% accurate, as it does not YET take into account + // our requested end in any way other than implicitly. It should, however, + // work okay for now. + if((c + add) < _objects.size()) i += add; + + else i = e; + } + + return val; + } + + void _setWidthAndHeightUnknownSizeError (const std::string&, point_type); + void _setWidthAndHeightNotPAError (const std::string&, point_type); + void _setWidthAndHeight (); + void _removeFromGeode (Widget*); + + Widget* _getBackground() const; + Window* _getTopmostParent() const; + +protected: + // This method will return the T'th value returned by applying the Getter member function + // pointer to each iterator in the range of iterators defined by offset and add. In + // plain language, this helper method will apply some standard Widget::get* function + // to a range of objects in the _objects Vector, and will return the T'th of that. + // The template T can be any functor accepting two point_type values that return + // a bool. For example, this is commonly used with std::less to find the smallest + // width in a range of Widgets. + template + point_type _compare( + Getter get, + int begin = 0, + int end = 0, + int add = 1 + ) const { + return _forEachAssignOrApply(get, begin, end, add, true); + } + + // This method will return the T'th value accumulated by applying the Getter member + // function to each iterator in the range of iterators defined by offset and add (similar + // to above). For example, this method can be used to apply std::plus to every + // width in a range of Widgets, and return the total. + template + point_type _accumulate( + Getter get, + int begin = 0, + int end = 0, + int add = 1 + ) const { + return _forEachAssignOrApply(get, begin, end, add, false); + } + + osg::Geode* _geode() { + return dynamic_cast(getChild(0)); + } + + const osg::Geode* _geode() const { + return dynamic_cast(getChild(0)); + } + + Widget* _bg() { + return _getBackground(); + } + + const Widget* _bg() const { + return _getBackground(); + } + + osg::Scissor* _scissor() { + return dynamic_cast( + getStateSet()->getAttribute(osg::StateAttribute::SCISSOR) + ); + } + + bool _setWidget (Widget*, int = -1); + bool _setVisible (bool); + void _setFocused (Widget*); + void _setStyled (Widget*); + void _setParented (Widget*, bool=false); + void _setManaged (Widget*, bool=false); + + void _positionWidget(Widget*, point_type, point_type); + + // These return the smallest and largest width and height values for the given + // range of Widgets. + point_type _getMinWidgetWidth (int = 0, int = 0, int = 1) const; + point_type _getMinWidgetHeight (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetWidth (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetHeight (int = 0, int = 0, int = 1) const; + + // These return the smallest and largest minWidth and minHeight values for + // the given range of Widgets. + point_type _getMinWidgetMinWidth (int = 0, int = 0, int = 1) const; + point_type _getMinWidgetMinHeight (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetMinWidth (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetMinHeight (int = 0, int = 0, int = 1) const; + + // These return the smallest and largest width and height total (width + pad) + // values for the given range of Widgets. + point_type _getMinWidgetWidthTotal (int = 0, int = 0, int = 1) const; + point_type _getMinWidgetHeightTotal (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetWidthTotal (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetHeightTotal (int = 0, int = 0, int = 1) const; + + // These return the smallest and largest minWidth and minHeight total + // (width + pad) values for the given range of Widgets. + point_type _getMinWidgetMinWidthTotal (int = 0, int = 0, int = 1) const; + point_type _getMinWidgetMinHeightTotal (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetMinWidthTotal (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetMinHeightTotal (int = 0, int = 0, int = 1) const; + + // These return the smallest and largest horizontal and vertical padding + // values for the given range of Widgets. + point_type _getMinWidgetPadHorizontal (int = 0, int = 0, int = 1) const; + point_type _getMinWidgetPadVertical (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetPadHorizontal (int = 0, int = 0, int = 1) const; + point_type _getMaxWidgetPadVertical (int = 0, int = 0, int = 1) const; + + point_type _getNumFill(int = 0, int = 0, int = 1) const; + + // This method is passed the additional values by which width and height should be + // modified as calculed by the parent method, Window::resize. Keep in mind that these + // values can be negative (indicating a potential "shrink" request) or positive (which + // would indicate a "grow" reqeust). + virtual void _resizeImplementation(point_type, point_type) = 0; + + // These are made into implementation functions since getting the width or height + // of a window can potentially be an expensive operation, and we'll want to cache + // results if possible (which is handled transparently by the actualy Window::resize + // method). They return a Sizes struct which contains two members: cur (for current) + // and min (minimum). It's important that the Window know it's minimum possible + // size so that it can ignore invaled requests to resize. + // + // Default versions using BoundingBox calculations are provided, but some Windows + // override this (Table, Box). + virtual Sizes _getWidthImplementation () const; + virtual Sizes _getHeightImplementation () const; + +public: + META_UIObject(Window); + + Window (const std::string& = ""); + Window (const Window&, const osg::CopyOp&); + + bool resize (point_type = 0.0f, point_type = 0.0f); + bool resizeAdd (point_type = 0.0f, point_type = 0.0f); + bool resizePercent (point_type = 0.0f, point_type = 0.0f); + + virtual void update (); + virtual void managed (WindowManager*); + virtual void unmanaged (WindowManager*); + virtual bool addWidget (Widget*); + virtual bool insertWidget (Widget*, unsigned int); + virtual bool removeWidget (Widget*); + virtual bool replaceWidget (Widget*, Widget*); + + // This method wraps our Geode's addDrawable() method and returns the index of + // the newly-added Drawable. + unsigned int addDrawableAndGetIndex(osg::Drawable*); + + bool isVisible () const; + bool isXYWithinVisible (float, float) const; + void setVisibleArea (int = 0, int = 0, int = 0, int = 0); + void addVisibleArea (int = 0, int = 0, int = 0, int = 0); + bool setFocused (const Widget*); + bool setFocused (const std::string&); + bool setFirstFocusable (); + bool setNextFocusable (); + bool getFocusList (WidgetList&) const; + bool getEmbeddedList (WindowList&) const; + void getParentList (WindowList&) const; + + XYCoord localXY (double, double) const; + XYCoord getAbsoluteOrigin () const; + + // This method wraps the current Window in a EmbeddedWindow object and returns it. + EmbeddedWindow* embed(); + + Widget* getFocused() { + return _focused.get(); + } + + const Widget* getFocused() const { + return _focused.get(); + } + + bool show() { + return _setVisible(true); + } + + bool hide() { + return _setVisible(false); + } + + bool isPointerXYWithinVisible(float x, float y) const { + XYCoord xy = localXY(x, y); + + return isXYWithinVisible(xy.x(), xy.y()); + } + + osg::Geode* getGeode() { + return _geode(); + } + + const osg::Geode* getGeode() const { + return _geode(); + } + + Widget* getBackground() { + return _bg(); + } + + const Widget* getBackground() const { + return _bg(); + } + + WindowManager* getWindowManager() { + return _wm; + } + + const WindowManager* getWindowManager() const { + return _wm; + } + + Window* getParent() { + return _parent; + } + + const Window* getParent() const { + return _parent; + } + + Window* getTopmostParent() { + return _getTopmostParent(); + } + + const Window* getTopmostParent() const { + return _getTopmostParent(); + } + + unsigned int getIndex() const { + return _index; + } + + matrix_type getX() const { + return _x; + } + + matrix_type getY() const { + return _y; + } + + matrix_type getZ() const { + return _z; + } + + point_type getWidth() const { + return _width.cur; + } + + point_type getHeight() const { + return _height.cur; + } + + point_type getMinWidth() const { + return _width.min; + } + + point_type getMinHeight() const { + return _height.min; + } + + VERTICAL_ANCHOR getAnchorVertical() const { + return _vAnchor; + } + + HORIZONTAL_ANCHOR getAnchorHorizontal() const { + return _hAnchor; + } + + XYCoord getOrigin() const { + return XYCoord(_x, _y); + } + + XYCoord getSize() const { + return XYCoord(_width.cur, _height.cur); + } + + XYCoord getMinSize() const { + return XYCoord(_width.min, _height.min); + } + + matrix_type getZRange() const { + return _zRange; + } + + STRATA getStrata() const { + return _strata; + } + + const Quad& getVisibleArea() const { + return _visibleArea; + } + + VISIBILITY_MODE getVisibilityMode() const { + return _vis; + } + + Point getPosition() const { + return Point(_x, _y, _z); + } + + matrix_type getRotate() const { + return _r; + } + + matrix_type getScale() const { + return _s; + } + + matrix_type getScaleDenominator() const { + return _scaleDenom; + } + + void setX(matrix_type x) { + _x = x; + } + + void setY(matrix_type y) { + _y = y; + } + + void setPosition(matrix_type x, matrix_type y, matrix_type z) { + _x = x; + _y = y; + _z = z; + } + + void setPosition(const Point& p) { + setPosition(p.x(), p.y(), p.z()); + } + + void setOrigin(matrix_type x, matrix_type y) { + _x = x; + _y = y; + } + + void setRotate(matrix_type r) { + _r = r; + } + + void setScale(matrix_type s) { + _s = s; + } + + void setScaleDenominator(matrix_type sd) { + _scaleDenom = sd; + } + + void setAnchorVertical(VERTICAL_ANCHOR va) { + _vAnchor = va; + } + + void setAnchorHorizontal(HORIZONTAL_ANCHOR ha) { + _hAnchor = ha; + } + + void setStrata(STRATA s) { + _strata = s; + } + + void setVisibilityMode(VISIBILITY_MODE v) { + _vis = v; + } + + void addX(matrix_type x) { + _x += x; + } + + void addY(matrix_type y) { + _y += y; + } + + void addZ(matrix_type z) { + _z += z; + } + + void addRotate(matrix_type r) { + _r += r; + } + + void addScale(matrix_type s) { + _s += s / (_scaleDenom != 0.0f ? _scaleDenom : 1.0f); + } + + void addOrigin(matrix_type x, matrix_type y) { + _x += x; + _y += y; + } + + void attachMoveCallback() { + addCallback(Callback(&callbackWindowMove, EVENT_MOUSE_DRAG)); + } + + void attachRotateCallback() { + addCallback(Callback(&callbackWindowRotate, EVENT_MOUSE_DRAG)); + } + + void attachScaleCallback() { + addCallback(Callback(&callbackWindowScale, EVENT_MOUSE_DRAG)); + } + + void attachTabFocusCallback() { + addCallback(Callback(&callbackWindowTabFocus, EVENT_KEY_DOWN)); + } +}; + +typedef Window::WindowList WindowList; + +} + +#endif diff --git a/include/osgWidget/WindowManager b/include/osgWidget/WindowManager new file mode 100644 index 000000000..dbf059965 --- /dev/null +++ b/include/osgWidget/WindowManager @@ -0,0 +1,358 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: WindowManager 66 2008-07-14 21:54:09Z cubicool $ + +#ifndef OSGWIDGET_WINDOW_MANAGER +#define OSGWIDGET_WINDOW_MANAGER + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace osgWidget { + +// TODO: It should be possible to use something other than osgWidget/ViewerEventHandlers +// to handle all of these events. In fact, I need to create an SDL example showing this. + +// A private typedef that we use for pickAtXY() below. +typedef osgUtil::LineSegmentIntersector::Intersections Intersections; + +// A WindowManager performs pointer interaction with the topmost (highest Z) Widget, +// and performs keyboard input on the currently focused Window->Widget. +class OSGWIDGET_EXPORT WindowManager: public osg::Switch, public UIObjectParent { +public: + enum WM_FLAGS { + WM_USE_LUA = 0x00000001, + WM_USE_PYTHON = 0x00000002, + WM_PICK_DEBUG = 0x00000004, + WM_NO_INVERT_Y = 0x00000008, + WM_NO_BETA_WARN = 0x00000010 + }; + + enum POINTER_DIRECTION { + PD_NONE = 0x00000000, + PD_LEFT = 0x00000001, + PD_RIGHT = 0x00000002, + PD_UP = 0x00000004, + PD_DOWN = 0x00000008 + }; + + enum POINTER_FOCUS_MODE { + PFM_FOCUS = 0x00000000, + PFM_UNFOCUS = 0x00000001, + PFM_SLOPPY = 0x00000002 + }; + +private: + // A functor used to sort the Windows by their Z component in descending order. + struct WindowZCompare: public std::binary_function { + bool operator()(const ptr_type& x, const ptr_type& y) { + return x.get()->getZ() > y.get()->getZ(); + } + }; + + point_type _width; + point_type _height; + point_type _zNear; + point_type _zFar; + matrix_type _numForeground; + matrix_type _numBackground; + unsigned int _flags; + unsigned int _nodeMask; + osgViewer::View* _view; + float _lastX; + float _lastY; + EventInterface* _lastEvent; + EventInterface* _lastPush; + POINTER_DIRECTION _lastVertical; + POINTER_DIRECTION _lastHorizontal; + POINTER_FOCUS_MODE _focusMode; + bool _leftDown; + bool _middleDown; + bool _rightDown; + + osgGA::GUIEventAdapter::ScrollingMotion _scrolling; + + osg::ref_ptr _lua; + osg::ref_ptr _python; + osg::ref_ptr _styleManager; + + osg::observer_ptr _widget; + osg::observer_ptr _focused; + osg::observer_ptr _pickWindow; + + void childInserted (unsigned int); + void childRemoved (unsigned int, unsigned int); + + bool _handleMousePushed (float, float, bool&); + bool _handleMouseReleased (float, float, bool&); + bool _haneldMouseScrolled (float, float, bool = false); + void _getPointerXYDiff (float&, float&); + void _updatePickWindow (const WidgetList*, point_type, point_type); + +public: + META_Object(osgWidget, WindowManager); + + WindowManager( + osgViewer::View* = 0, + point_type = 0.0f, + point_type = 0.0f, + unsigned int = 0, + unsigned int = 0 + ); + + WindowManager(const WindowManager&, const osg::CopyOp&); + + virtual ~WindowManager(); + + // A static method that will set both the _widget and _window data of an Event + // reference from a passed-in Interface. + static void setEventFromInterface(Event&, EventInterface*); + + // A static template method that will iterate over a container and return a + // properly formed EventInterface*. + template + static EventInterface* getFirstEventInterface(T&, Event&); + + bool pickAtXY (float, float, WidgetList&); + bool setFocused (Window*); + void setPointerXY (float, float); + void setStyleManager (StyleManager*); + void resizeAllWindows (bool = true); + + // 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); + bool pointerDrag (float, float); + bool mouseScroll (float, float); + + osg::Camera* createParentOrthoCamera(); + + unsigned int getNodeMask() const { + return _nodeMask; + } + + point_type getWidth() const { + return _width; + } + + point_type getHeight() const { + return _height; + } + + bool isUsingLua() const { + return (_flags & WM_USE_LUA) != 0; + } + + bool isUsingPython() const { + return (_flags & WM_USE_PYTHON) != 0; + } + + bool isInvertedY() const { + return (_flags & WM_NO_INVERT_Y) == 0; + } + + int getMouseKeysDown() const { + int flag = 0; + + flag |= _leftDown ? osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON : 0; + flag |= _middleDown ? osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON: 0; + flag |= _rightDown ? osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON : 0; + + return flag; + } + + ScriptEngine* getLuaEngine() { + return _lua.get(); + } + + const ScriptEngine* getLuaEngine() const { + return _lua.get(); + } + + ScriptEngine* getPythonEngine() { + return _python.get(); + } + + const ScriptEngine* getPythonEngine() const { + return _python.get(); + } + + StyleManager* getStyleManager() { + return _styleManager.get(); + } + + const StyleManager* getStyleManager() const { + return _styleManager.get(); + } + + POINTER_DIRECTION getPointerVerticalDirection() const { + return _lastVertical; + } + + POINTER_DIRECTION getPointerHorizontalDirection() const { + return _lastHorizontal; + } + + POINTER_FOCUS_MODE getPointerFocusMode() const { + return _focusMode; + } + + int getPointerDirectionVector() const { + return _lastVertical | _lastHorizontal; + } + + bool isPointerMovingUp() const { + return _lastVertical == PD_UP; + } + + bool isPointerMovingDown() const { + return _lastVertical == PD_DOWN; + } + + bool isPointerMovingLeft() const { + return _lastHorizontal == PD_LEFT; + } + + bool isPointerMovingRight() const { + return _lastHorizontal == PD_RIGHT; + } + + bool isPointerMovingVertically() const { + return _lastVertical != PD_NONE; + } + + bool isPointerMovingHorizontally() const { + return _lastHorizontal != PD_NONE; + } + + bool isLeftMouseButtonDown() const { + return _leftDown; + } + + bool isMiddleMouseButtonDown() const { + return _middleDown; + } + + bool isRightMouseButtonDown() const { + return _rightDown; + } + + bool isMouseScrollingUp() const { + return _scrolling == osgGA::GUIEventAdapter::SCROLL_UP; + } + + bool isMouseScrollingDown() const { + return _scrolling == osgGA::GUIEventAdapter::SCROLL_DOWN; + } + + bool setFocusedByName(const std::string& name) { + return setFocused(getByName(name)); + } + + void setScrollingMotion(osgGA::GUIEventAdapter::ScrollingMotion sm) { + _scrolling = sm; + } + + void setPointerFocusMode(POINTER_FOCUS_MODE pfm) { + _focusMode = pfm; + } + + void setWidth(point_type w) { + _width = w; + } + + void setHeight(point_type h) { + _height = h; + } + + void setSize(point_type w, point_type h) { + _width = w; + _height = 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. + bool mousePushedLeft(float x, float y) { + return _handleMousePushed(x, y, _leftDown); + } + + bool mousePushedMiddle(float x, float y) { + return _handleMousePushed(x, y, _middleDown); + } + + bool mousePushedRight(float x, float y) { + return _handleMousePushed(x, y, _rightDown); + } + + bool mouseReleasedLeft(float x, float y) { + return _handleMouseReleased(x, y, _leftDown); + } + + bool mouseReleasedMiddle(float x, float y) { + return _handleMouseReleased(x, y, _middleDown); + } + + bool mouseReleasedRight(float x, float y) { + return _handleMouseReleased(x, y, _rightDown); + } + + // Keyboards wrappers, as above; takes the key and key's mask code, which + // can be compared to osgGA::GUIEventAdapter::{KeySymbol,KeyModMask}. + bool keyDown (int, int); + bool keyUp (int, int); +}; + +// We use a template here because the container could be a list or a vector; or something +// else that supports iteration! +template +EventInterface* WindowManager::getFirstEventInterface(T& container, Event& ev) { + if(!container.size()) return 0; + + // See if we can find a Widget that responds to this event... + for(typename T::iterator i = container.begin(); i != container.end(); i++) { + Widget* widget = i->get(); + + // If so, set the _widget/_window members and return it. + if(widget->getEventMask() & ev.type) { + ev._window = widget->getParent(); + ev._widget = widget; + + return widget; + } + } + + // If we can't find a Widget that will accept this event, try and recurse all + // of the parent Windows and find one that can. + WindowList windowList; + + Window* parent = container.back()->getParent(); + + if(parent) { + parent->getParentList(windowList); + + // A WindowList from getParentList includes the Window the method was called + // on, and the entire tree of parentage. + for(WindowList::iterator i = windowList.begin(); i != windowList.end(); i++) { + Window* window = i->get(); + + if(window->getEventMask() & ev.type) { + ev._window = window; + + return window; + } + } + } + + return 0; +} + +} + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index be9d3bb5f..711165b8b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,21 +1,31 @@ #the old construct SUBDIRS( was substituded by ADD_SUBDIRECTORY that is to be preferred according on CMake docs. FOREACH( mylibfolder - OpenThreads - osg - osgDB - osgUtil - osgGA - osgText - osgManipulator - osgSim - osgFX - osgParticle - osgShadow - osgTerrain - osgViewer -) + OpenThreads + osg + osgDB + osgUtil + osgGA + osgText + osgManipulator + osgSim + osgFX + osgParticle + osgShadow + osgTerrain + osgViewer + ) + ADD_SUBDIRECTORY(${mylibfolder}) -ENDFOREACH( mylibfolder ) + +ENDFOREACH( mylibfolder ) + +OPTION(BUILD_OSGWIDGET "Enable to build osgWidget" ON) +IF (BUILD_OSGWIDGET) + ADD_SUBDIRECTORY(osgWidget) +ENDIF(BUILD_OSGWIDGET) + + + OPTION(BUILD_OSG_PLUGINS "Enable to build OSG Plugins" ON) IF (BUILD_OSG_PLUGINS) ADD_SUBDIRECTORY(osgPlugins) diff --git a/src/osgPlugins/CMakeLists.txt b/src/osgPlugins/CMakeLists.txt index daa58813a..b23886b6a 100644 --- a/src/osgPlugins/CMakeLists.txt +++ b/src/osgPlugins/CMakeLists.txt @@ -166,6 +166,10 @@ IF(RSVG_FOUND AND CAIRO_FOUND) ADD_SUBDIRECTORY(svg) ENDIF(RSVG_FOUND AND CAIRO_FOUND) +IF (BUILD_OSGWIDGET) + ADD_SUBDIRECTORY(osgWidget) +ENDIF(BUILD_OSGWIDGET) + ##########to get all the variables of Cmake #GET_CMAKE_PROPERTY(MYVARS VARIABLES) diff --git a/src/osgPlugins/osgWidget/Box.cpp b/src/osgPlugins/osgWidget/Box.cpp new file mode 100644 index 000000000..9d4acc344 --- /dev/null +++ b/src/osgPlugins/osgWidget/Box.cpp @@ -0,0 +1,113 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Box.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include +#include +#include +#include +#include + +bool osgWidget_Box_readData(osg::Object& obj, osgDB::Input& fr) { + /* + osgWidget::Box& box = static_cast(obj); + + if(fr[0].matchWord("skeleton") and fr[1].isString()) iter = loadFile( + "skeleton", + &osgCal::osgWidget_Box::loadSkeleton, + model, + fr + ); + + if(fr[0].matchWord("animation") and fr[1].isString()) iter = loadFile( + "animation", + &osgCal::osgWidget_Box::loadAnimation, + model, + fr + ); + + if(fr[0].matchWord("mesh") and fr[1].isString()) iter = loadFile( + "mesh", + &osgCal::osgWidget_Box::loadMesh, + model, + fr + ); + + if(fr[0].matchWord("material") and fr[1].isString()) iter = loadFile( + "material", + &osgCal::osgWidget_Box::loadMaterial, + model, + fr + ); + */ + + osgWidget::warn() << "Box read" << std::endl; + + return false; +} + +bool osgWidget_Box_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::Box& model = static_cast(obj); + + fw.indent() << fw.wrapString("Box stuff...") << std::endl; + + return true; +} + +/* +bool Model_readData(osg::Object& obj, osgDB::Input& fr) { + bool iter = false; + + osgCal::Model& model = static_cast(obj); + osgCal::osgWidget_Box* core = static_cast( + fr.readObjectOfType(osgCal::osgWidget_Box("dummy")) + ); + + if(core) { + model.create(core); + + iter = true; + } + + if(fr.matchSequence("StartAnimation")) { + if(fr[1].isString()) { + int animation = core->getAnimationId(fr[1].getStr()); + + if(animation >= 0) model.startLoop(animation, 1.0f, 0.0f); + + else osg::notify(osg::WARN) + << "Couldn't start animation: " << fr[1].getStr() + << std::endl + ; + + iter = true; + fr += 2; + } + } + + return iter; +} + +bool Model_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgCal::Model& model = static_cast(obj); + + fw.writeObject(*model.getosgWidget_Box()); + + return true; +} + +osgDB::RegisterDotOsgWrapperProxy g_ModelProxy( + new osgCal::Model, + "Model", + "Object Node Model", + &Model_readData, + &Model_writeData +); +*/ + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_BoxProxy( + new osgWidget::Box("unset"), + "osgWidget::Box", + "Object Node Group Transform MatrixTransform osgWidget::Box", + &osgWidget_Box_readData, + &osgWidget_Box_writeData +); diff --git a/src/osgPlugins/osgWidget/CMakeLists.txt b/src/osgPlugins/osgWidget/CMakeLists.txt new file mode 100644 index 000000000..1ae14109f --- /dev/null +++ b/src/osgPlugins/osgWidget/CMakeLists.txt @@ -0,0 +1,19 @@ +#this file is automatically generated + + +SET(TARGET_SRC + Box.cpp + EmbeddedWindow.cpp + Frame.cpp + Input.cpp + Label.cpp + Table.cpp + Widget.cpp + WindowManager.cpp +) + +SET(TARGET_ADDED_LIBRARIES osgWidget ) +#### end var setup ### +SETUP_PLUGIN(osgwisget) + + diff --git a/src/osgPlugins/osgWidget/EmbeddedWindow.cpp b/src/osgPlugins/osgWidget/EmbeddedWindow.cpp new file mode 100644 index 000000000..a1b7d74e5 --- /dev/null +++ b/src/osgPlugins/osgWidget/EmbeddedWindow.cpp @@ -0,0 +1,32 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: EmbeddedWindow.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include +#include +#include +#include +#include + +bool osgWidget_EmbeddedWindow_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "EmbeddedWindow read" << std::endl; + + return false; +} + +bool osgWidget_EmbeddedWindow_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::Window::EmbeddedWindow& model = + static_cast(obj) + ; + + fw.indent() << fw.wrapString("EmbeddedWindow stuff...") << std::endl; + + return true; +} + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_EmbeddedWindowProxy( + new osgWidget::Window::EmbeddedWindow("unset"), + "osgWidget::Window::EmbeddedWindow", + "Object Drawable Geometry osgWidget::Widget osgWidget::Window::EmbeddedWindow", + &osgWidget_EmbeddedWindow_readData, + &osgWidget_EmbeddedWindow_writeData +); diff --git a/src/osgPlugins/osgWidget/Frame.cpp b/src/osgPlugins/osgWidget/Frame.cpp new file mode 100644 index 000000000..92d698dbf --- /dev/null +++ b/src/osgPlugins/osgWidget/Frame.cpp @@ -0,0 +1,30 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Frame.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include +#include +#include +#include +#include + +bool osgWidget_Frame_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "Frame read" << std::endl; + + return false; +} + +bool osgWidget_Frame_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::Frame& model = static_cast(obj); + + fw.indent() << fw.wrapString("Frame stuff...") << std::endl; + + return true; +} + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_FrameProxy( + new osgWidget::Frame("unset"), + "osgWidget::Frame", + "Object Node Group Transform MatrixTransform osgWidget::Table osgWidget::Frame", + &osgWidget_Frame_readData, + &osgWidget_Frame_writeData +); diff --git a/src/osgPlugins/osgWidget/Input.cpp b/src/osgPlugins/osgWidget/Input.cpp new file mode 100644 index 000000000..78db98f73 --- /dev/null +++ b/src/osgPlugins/osgWidget/Input.cpp @@ -0,0 +1,30 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Input.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include +#include +#include +#include +#include + +bool osgWidget_Input_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "Input read" << std::endl; + + return false; +} + +bool osgWidget_Input_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::Input& model = static_cast(obj); + + fw.indent() << fw.wrapString("Input stuff...") << std::endl; + + return true; +} + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_InputProxy( + new osgWidget::Input("unset"), + "osgWidget::Input", + "Object Drawable Geometry osgWidget::Widget osgWidget::Input", + &osgWidget_Input_readData, + &osgWidget_Input_writeData +); diff --git a/src/osgPlugins/osgWidget/Label.cpp b/src/osgPlugins/osgWidget/Label.cpp new file mode 100644 index 000000000..a0eee152d --- /dev/null +++ b/src/osgPlugins/osgWidget/Label.cpp @@ -0,0 +1,30 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Label.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include +#include +#include +#include +#include + +bool osgWidget_Label_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "Label read" << std::endl; + + return false; +} + +bool osgWidget_Label_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::Label& model = static_cast(obj); + + fw.indent() << fw.wrapString("Label stuff...") << std::endl; + + return true; +} + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_LabelProxy( + new osgWidget::Label("unset"), + "osgWidget::Label", + "Object Drawable Geometry osgWidget::Widget osgWidget::Label", + &osgWidget_Label_readData, + &osgWidget_Label_writeData +); diff --git a/src/osgPlugins/osgWidget/Table.cpp b/src/osgPlugins/osgWidget/Table.cpp new file mode 100644 index 000000000..33d52421f --- /dev/null +++ b/src/osgPlugins/osgWidget/Table.cpp @@ -0,0 +1,30 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Table.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include +#include +#include +#include +#include + +bool osgWidget_Table_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "Table read" << std::endl; + + return false; +} + +bool osgWidget_Table_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::Table& model = static_cast(obj); + + fw.indent() << fw.wrapString("Table stuff...") << std::endl; + + return true; +} + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_TableProxy( + new osgWidget::Table("unset"), + "osgWidget::Table", + "Object Node Group Transform MatrixTransform osgWidget::Table", + &osgWidget_Table_readData, + &osgWidget_Table_writeData +); diff --git a/src/osgPlugins/osgWidget/Widget.cpp b/src/osgPlugins/osgWidget/Widget.cpp new file mode 100644 index 000000000..a9258e677 --- /dev/null +++ b/src/osgPlugins/osgWidget/Widget.cpp @@ -0,0 +1,75 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Widget.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include +#include +#include +#include +#include +#include + +bool osgWidget_Widget_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "Widget read" << std::endl; + + return false; +} + +bool osgWidget_Widget_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::Widget& model = static_cast(obj); + + fw.indent() << fw.wrapString("Widget stuff...") << std::endl; + + return true; +} + +bool osgWidget_NotifyWidget_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "NotifyWidget read" << std::endl; + + return false; +} + +bool osgWidget_NotifyWidget_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::NotifyWidget& model = static_cast(obj); + + fw.indent() << fw.wrapString("NotifyWidget stuff...") << std::endl; + + return true; +} + +bool osgWidget_NullWidget_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "NullWidget read" << std::endl; + + return false; +} + +bool osgWidget_NullWidget_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::NullWidget& model = static_cast(obj); + + fw.indent() << fw.wrapString("NullWidget stuff...") << std::endl; + + return true; +} + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_WidgetProxy( + new osgWidget::Widget("unset"), + "osgWidget::Widget", + "Object Drawable Geometry osgWidget::Widget", + &osgWidget_Widget_readData, + &osgWidget_Widget_writeData +); + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_NotifyWidgetProxy( + new osgWidget::NotifyWidget("unset"), + "osgWidget::NotifyWidget", + "Object Drawable Geometry osgWidget::Widget osgWidget::NotifyWidget", + &osgWidget_NotifyWidget_readData, + &osgWidget_NotifyWidget_writeData +); + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_NullWidgetProxy( + new osgWidget::Widget("unset"), + "osgWidget::NullWidget", + "Object Drawable Geometry osgWidget::Widget osgWidget::NullWidget", + &osgWidget_NullWidget_readData, + &osgWidget_NullWidget_writeData +); diff --git a/src/osgPlugins/osgWidget/WindowManager.cpp b/src/osgPlugins/osgWidget/WindowManager.cpp new file mode 100644 index 000000000..bd1157bc5 --- /dev/null +++ b/src/osgPlugins/osgWidget/WindowManager.cpp @@ -0,0 +1,30 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: WindowManager.cpp 50 2008-05-06 05:06:36Z cubicool $ + +#include +#include +#include +#include +#include + +bool osgWidget_WindowManager_readData(osg::Object& obj, osgDB::Input& fr) { + osgWidget::warn() << "WindowManager read" << std::endl; + + return false; +} + +bool osgWidget_WindowManager_writeData(const osg::Object& obj, osgDB::Output& fw) { + const osgWidget::WindowManager& model = static_cast(obj); + + fw.indent() << fw.wrapString("WindowManager stuff...") << std::endl; + + return true; +} + +osgDB::RegisterDotOsgWrapperProxy g_osgWidget_WindowManagerProxy( + new osgWidget::WindowManager(), + "osgWidget::WindowManager", + "Object Node Group Switch osgWidget::WindowManager", + &osgWidget_WindowManager_readData, + &osgWidget_WindowManager_writeData +); diff --git a/src/osgWidget/Box.cpp b/src/osgWidget/Box.cpp new file mode 100644 index 000000000..fdc893c51 --- /dev/null +++ b/src/osgWidget/Box.cpp @@ -0,0 +1,194 @@ +// -*-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): +Window (name), +_boxType (bt), +_uniform (uniform), +_lastAdd (0) { +} + +Box::Box(const Box& box, const osg::CopyOp& co): +Window (box, co), +_boxType (box._boxType), +_uniform (box._uniform), +_lastAdd (box._lastAdd) { +} + +// TODO: Here's something to consider! If we resize the box by 1 every time, only the +// first resizable Widget will continue to get larger. This is really silly. +void Box::_resizeImplementation(point_type w, point_type h) { + // Get the number of Widgets that agree to fill. Also perfom some casting to integers + // in case we're being request to resize with pixel perfection. + point_type numFill = _getNumFill(); + int iw = static_cast(w); + int ih = static_cast(h); + int inumFill = static_cast(numFill); + int wrem = 0; + int hrem = 0; + + // If we have some widgets that fill, use these variables to keep a running count + // of what needs to be added. + if(inumFill) { + wrem = iw % inumFill; + hrem = ih % inumFill; + } + + // If we have any widgets that agree to fill and there has been an honest resize + // request, handle it here. The first case handles resizes where we have AT LEAST + // as many pixels to fill as we have objects. + if(numFill > 0.0f && (w != 0.0f || h != 0.0f)) { + unsigned int cur = 0; + + for(Iterator i = begin(); i != end(); i++) if(i->valid() && i->get()->canFill()) { + point_type addWidth = 0.0f; + point_type addHeight = 0.0f; + + // If our last added-to Widget was the last one, reset it to 0. + if(_lastAdd >= size()) _lastAdd = 0; + + // We EVENLY give any remaining space to all fillable Widgets. In the + // future we may want to be able to specify a fill "percent", which + // would be some portion of the total available space. + if(_boxType == HORIZONTAL) { + if(w) { + addWidth += static_cast(iw / inumFill); + + if(cur >= _lastAdd && wrem) { + _lastAdd++; + addWidth++; + wrem--; + } + } + + if(h) addHeight += h; + } + + else { + if(w) addWidth += w; + + if(h) { + addHeight += static_cast(ih / inumFill); + + if(cur >= _lastAdd && hrem) { + _lastAdd++; + addHeight++; + hrem--; + } + } + } + + if(addWidth != 0.0f) i->get()->addWidth(addWidth); + + if(addHeight != 0.0f) i->get()->addHeight(addHeight); + + cur++; + } + } + + // Get the width and height of our largest widgets; these values take + // into account the padding, and will be affected by any resizing that occured above. + point_type maxWidth = _getMaxWidgetWidthTotal(); + point_type maxHeight = _getMaxWidgetHeightTotal(); + + // Create counters for the various offsets as we position Widgets. + point_type xoff = 0.0f; + point_type yoff = 0.0f; + point_type xadd = 0.0f; + point_type yadd = 0.0f; + + for(Iterator i = begin(); i != end(); i++) { + Widget* widget = i->get(); + + // This positioning works by setting each Widget's unmodified origin and then + // letting Window::_positionWidget calculate the padding/fill. + if(_boxType == HORIZONTAL) { + // First, lets set it to the proper x offset, ignoring any padding. + widget->setOrigin(xoff, 0.0f); + + // Immediately reset our xoff for the next iteration. + if(_uniform) { + _positionWidget(widget, maxWidth, maxHeight); + + xadd = maxWidth; + } + + else { + _positionWidget(widget, widget->getWidthTotal(), maxHeight); + + xadd = widget->getWidthTotal(); + } + } + + else { + widget->setOrigin(0.0f, yoff); + + if(_uniform) { + _positionWidget(widget, maxWidth, maxHeight); + + yadd = maxHeight; + } + + else { + _positionWidget(widget, maxWidth, widget->getHeightTotal()); + + yadd = widget->getHeightTotal(); + } + } + + xoff += xadd; + yoff += yadd; + } +} + +Window::Sizes Box::_getWidthImplementation() const { + // The width of a horizontal box is all of the widgets added together. + if(_boxType == HORIZONTAL) { + // If we're a uniformly sized box, our width is our largest width plus our + // largest padding, multiplied times the number of widgets. Our minimum width + // is the size of the largest minWidth times the number of widgets. + if(_uniform) return Sizes( + _getMaxWidgetWidthTotal() * size(), + _getMaxWidgetMinWidthTotal() * size() + ); + + // Othweriwse, our width is all of the widths added together, and our minWidth + // is all of the minWidths added together. + else return Sizes( + _accumulate(&Widget::getWidthTotal), + _accumulate(&Widget::getMinWidthTotal) + ); + } + + // If we're a vertical Box, our width is the width of the larget Widget in the group. + // Our minWidth is the largest minWidth of the Widgets in the group. + else return Sizes( + _getMaxWidgetWidthTotal(), + _getMaxWidgetMinWidthTotal() + ); +} + +Window::Sizes Box::_getHeightImplementation() const { + if(_boxType == VERTICAL) { + if(_uniform) return Sizes( + _getMaxWidgetHeightTotal() * size(), + _getMaxWidgetMinHeightTotal() * size() + ); + + else return Sizes( + _accumulate(&Widget::getHeightTotal), + _accumulate(&Widget::getMinHeightTotal) + ); + } + + else return Sizes( + _getMaxWidgetHeightTotal(), + _getMaxWidgetMinHeightTotal() + ); +} + +} diff --git a/src/osgWidget/CMakeLists.txt b/src/osgWidget/CMakeLists.txt new file mode 100644 index 000000000..9ded1c2ea --- /dev/null +++ b/src/osgWidget/CMakeLists.txt @@ -0,0 +1,66 @@ +IF (DYNAMIC_OPENSCENEGRAPH) + ADD_DEFINITIONS(-DOSGWIDGET_LIBRARY) +ELSE (DYNAMIC_OPENSCENEGRAPH) + ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC) +ENDIF(DYNAMIC_OPENSCENEGRAPH) + +SET(LIB_NAME osgWidget) +SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME}) +SET(LIB_PUBLIC_HEADERS + ${HEADER_PATH}/Export + ${HEADER_PATH}/Box + ${HEADER_PATH}/Canvas + ${HEADER_PATH}/EventInterface + ${HEADER_PATH}/Frame + ${HEADER_PATH}/Input + ${HEADER_PATH}/Label + ${HEADER_PATH}/Lua + ${HEADER_PATH}/Python + ${HEADER_PATH}/ScriptEngine + ${HEADER_PATH}/StyleInterface + ${HEADER_PATH}/StyleManager + ${HEADER_PATH}/Table + ${HEADER_PATH}/Types + ${HEADER_PATH}/UIObjectParent + ${HEADER_PATH}/Util + ${HEADER_PATH}/Version + ${HEADER_PATH}/ViewerEventHandlers + ${HEADER_PATH}/Widget + ${HEADER_PATH}/Window + ${HEADER_PATH}/WindowManager +) + +# FIXME: For OS X, need flag for Framework or dylib +ADD_LIBRARY(${LIB_NAME} + ${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC} + ${LIB_PUBLIC_HEADERS} + Box.cpp + Canvas.cpp + CMakeLists.txt + Frame.cpp + Input.cpp + Label.cpp + Lua.cpp + Python.cpp + StyleManager.cpp + Table.cpp + Util.cpp + Version.cpp + ViewerEventHandlers.cpp + Widget.cpp + Window.cpp + WindowManager.cpp +) + + +SET(TARGET_LIBRARIES_VARS FREETYPE_LIBRARY ) +LINK_INTERNAL(${LIB_NAME} + osgText + osgViewer + osgDB + osg + OpenThreads +) +LINK_CORELIB_DEFAULT(${LIB_NAME}) + +INCLUDE(ModuleInstall OPTIONAL) diff --git a/src/osgWidget/Canvas.cpp b/src/osgWidget/Canvas.cpp new file mode 100644 index 000000000..e7a50f1a0 --- /dev/null +++ b/src/osgWidget/Canvas.cpp @@ -0,0 +1,32 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Canvas.cpp 66 2008-07-14 21:54:09Z cubicool $ + +#include + +namespace osgWidget { + +Canvas::Canvas(const std::string& name): +Window(name) { +} + +Canvas::Canvas(const Canvas& canvas, const osg::CopyOp& co): +Window(canvas, co) { +} + +void Canvas::_resizeImplementation(point_type w, point_type h) { + // A Canvas has no layout, so it doesn't really know how to honor a resize + // request. :) The best I could do here is store the differences and add them + // later to the calls to getWidth/getHeight. +} + +bool Canvas::addWidget(Widget* widget, point_type x, point_type y) { + if(Window::addWidget(widget)) { + widget->setOrigin(x, y); + + return true; + } + + return false; +} + +} diff --git a/src/osgWidget/Frame.cpp b/src/osgWidget/Frame.cpp new file mode 100644 index 000000000..ad180dc0b --- /dev/null +++ b/src/osgWidget/Frame.cpp @@ -0,0 +1,251 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Frame.cpp 59 2008-05-15 20:55:31Z cubicool $ + +#include +#include +#include + +namespace osgWidget { + +std::string Frame::cornerToString(CORNER c) { + if(c == CORNER_LOWER_LEFT) return "CornerLowerLeft"; + + else if(c == CORNER_LOWER_RIGHT) return "CornerLowerRight"; + + else if(c == CORNER_UPPER_RIGHT) return "CornerUpperRight"; + + else return "CornerUpperLeft"; +} + +std::string Frame::borderToString(BORDER b) { + if(b == BORDER_LEFT) return "BorderLeft"; + + else if(b == BORDER_RIGHT) return "BorderRight"; + + else if(b == BORDER_TOP) return "BorderTop"; + + 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(const Corner& corner, const osg::CopyOp& co): +Widget (corner, co), +_corner (corner._corner) { +} + +bool Frame::Corner::mouseDrag(double x, double y, WindowManager* wm) { + Window* parent = getParent(); + + if(!parent) return false; + + if(wm->isInvertedY()) { + if(_corner == CORNER_UPPER_LEFT) { + if(parent->resizeAdd(-x, -y)) parent->addOrigin(x, y); + } + + else if(_corner == CORNER_UPPER_RIGHT) { + if(parent->resizeAdd(x, -y)) parent->addY(y); + } + + else if(_corner == CORNER_LOWER_RIGHT) parent->resizeAdd(x, y); + + else { + if(parent->resizeAdd(-x, y)) parent->addX(x); + } + } + + // 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); + } + } + + parent->update(); + + return true; +} + +Frame::Border::Border(BORDER border, point_type width, point_type height): +Widget (borderToString(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) { +} + +bool Frame::Border::mouseDrag(double x, double y, WindowManager* wm) { + Window* parent = getParent(); + + if(!parent) 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(_border == BORDER_TOP) parent->addOrigin(x, y); + + else { + // The only BORDER that inverted-Y affects is this... + if(wm->isInvertedY()) parent->resizeAdd(0.0f, y); + + else { + if(parent->resizeAdd(0.0f, -y)) parent->addY(y); + } + } + + parent->update(); + + return true; +} + +Frame::Frame(const std::string& name): +Table(name, 3, 3) { +} + +Frame::Frame(const Frame& frame, const osg::CopyOp& co): +Table(frame, co) { +} + +Widget* Frame::_getCorner(CORNER c) const { + return const_cast(getByName(cornerToString(c))); +} + +Widget* Frame::_getBorder(BORDER b) const { + return const_cast(getByName(borderToString(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) { + if(!window) return false; + + EmbeddedWindow* ew = getEmbeddedWindow(); + + // If it's the first time setting the Window... + // if(!ew || !ew->getWindow()) return addWidget(window->embed(), 1, 1); + if(!ew) return addWidget(window->embed(), 1, 1); + + else return ew->setWindow(window); +} + +Frame* Frame::createSimpleFrame( + const std::string& name, + point_type cw, + point_type ch, + point_type w, + point_type h, + 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); + + 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); + + EmbeddedWindow* ew = new EmbeddedWindow(name, w, h); + + ew->setCanFill(true); + + frame->addWidget(ew, 1, 1); + + return frame; +} + +Frame* Frame::createSimpleFrameWithSingleTexture( + const std::string& name, + const std::string& texture, + point_type tw, + point_type th, + point_type cw, + point_type ch, + point_type w, + point_type h, + Frame* exFrame +) { + Frame* frame = 0; + + // The same as above... + if(!exFrame) frame = createSimpleFrame(name, cw, ch, w, h); + + else frame = createSimpleFrame(name, cw, ch, w, h, exFrame); + + for(unsigned int i = 0; i < 9; i++) frame->getObjects()[i]->setImage(texture); + + frame->getByRowCol(0, 0)->setTexCoordRegion(0.0f, th - ch, cw, ch); + frame->getByRowCol(0, 1)->setTexCoordRegion(cw, th - ch, tw - (cw * 2.0f), ch); + frame->getByRowCol(0, 2)->setTexCoordRegion(tw - cw, th - ch, cw, ch); + frame->getByRowCol(1, 0)->setTexCoordRegion(0.0f, ch, cw, th - (ch * 2.0f)); + frame->getByRowCol(1, 2)->setTexCoordRegion(tw - cw, ch, cw, th - (ch * 2.0f)); + frame->getByRowCol(2, 0)->setTexCoordRegion(0.0f, 0.0f, cw, ch); + frame->getByRowCol(2, 1)->setTexCoordRegion(cw, 0.0f, tw - (cw * 2.0f), ch); + frame->getByRowCol(2, 2)->setTexCoordRegion(tw - cw, 0.0f, cw, ch); + + frame->getEmbeddedWindow()->setTexCoordRegion(cw, ch, tw - (cw * 2.0f), th - (ch * 2.0f)); + + return frame; +} + +} diff --git a/src/osgWidget/Input.cpp b/src/osgWidget/Input.cpp new file mode 100644 index 000000000..abf00f958 --- /dev/null +++ b/src/osgWidget/Input.cpp @@ -0,0 +1,176 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Input.cpp 65 2008-07-14 16:29:28Z cubicool $ + +#include +#include +#include + +namespace osgWidget { + +Input::Input(const std::string& name, const std::string& label, unsigned int size): +Label (name, label), +_xoff (0.0f), +_yoff (0.0f), +_index (0), +_size (0), +_cursorIndex (0), +_maxSize (size), +_cursor (new Widget("cursor")) { + _text->setAlignment(osgText::Text::LEFT_BOTTOM_BASE_LINE); + _text->setKerningType(osgText::KERNING_NONE); + + // Make the cursor un-copyable. + _cursor->setCanClone(false); + _cursor->setDataVariance(osg::Object::DYNAMIC); + _cursor->setColor(0.0f, 0.0f, 0.0f, 0.0f); + + setEventMask( + // For showing/hiding the "cursor." + EVENT_MASK_FOCUS | + // For keypresses, obviously. + EVENT_MASK_KEY | + // For "click" focusing. + EVENT_MOUSE_PUSH + ); + + _offsets.resize(size, 0.0f); + + _text->getText().resize(size, ' '); + _text->update(); +} + +void Input::_calculateSize(const XYCoord& size) { + // An Input cannot currently set it's own size RELIABLY until the osgText implementation + // is dratiscally improved. I'm getting wildly crazy results. :( + // point_type height = size.y() > _cursor->getHeight() ? size.y() : _cursor->getHeight(); + point_type width = size.x() + _cursor->getWidth(); + point_type height = _cursor->getHeight(); + + if(width > getWidth()) setWidth(osg::round(width)); + + if(height > getHeight()) setHeight(osg::round(height)); +} + +void Input::_calculateCursorOffsets() { + // Determine the "offset" + const osgText::Text::TextureGlyphQuadMap& tgqm = _text->getTextureGlyphQuadMap(); + + const osgText::Text::TextureGlyphQuadMap::const_iterator tgqmi = tgqm.begin(); + + const osgText::Text::GlyphQuads& gq = tgqmi->second; + + point_type accum = 0.0f; + + 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)]; + + accum += osg::round(lr.x() - ll.x()); + + _offsets[i] = accum; + + os << _offsets[i] << " (" << static_cast(_text->getText()[i]) << ") "; + } + + os << "]" << std::endl; +} + +bool Input::focus(WindowManager*) { + _cursor->setColor(1.0f, 1.0f, 1.0f, 0.5f); + + return true; +} + +bool Input::unfocus(WindowManager*) { + _cursor->setColor(0.0f, 0.0f, 0.0f, 0.0f); + + return true; +} + +void Input::parented(Window* parent) { + Label::parented(parent); + + _cursor->setSize(2.0f, _text->getCharacterHeight()); + + if(_cursorIndex) parent->getGeode()->setDrawable(_cursorIndex, _cursor.get()); + + else _cursorIndex = parent->addDrawableAndGetIndex(_cursor.get()); +} + +void Input::positioned() { + point_type ln = static_cast(_text->getLineCount()); + + ln = ln == 0.0f ? 1.0f : ln; + + point_type th = + (_text->getCharacterHeight() * ln) + + (_text->getLineSpacing() * (ln - 1.0f)) + ; + + point_type x = getX() + _xoff; + point_type y = getY() + th + _yoff; + + // XYCoord size = getTextSize(); + + _text->setPosition(osg::Vec3(x, y, _calculateZ(LAYER_MIDDLE))); + + point_type xoffset = _index > 0 ? _offsets[_index - 1] : 0.0f; + + _cursor->setOrigin(x + xoffset + 1.0f, y - _cursor->getHeight() + 1.0f); + _cursor->setZ(_calculateZ(LAYER_MIDDLE)); +} + +bool Input::keyUp(int key, int mask, WindowManager*) { + return false; +} + +bool Input::keyDown(int key, int mask, WindowManager*) { + /* + osgText::String& s = _text->getText(); + + if(key == osgGA::GUIEventAdapter::KEY_BackSpace) { + if(_index >= 1) { + // s.erase(s.begin() + (_index - 1)); + + s[_index - 1] = ' '; + + _text->update(); + + _calculateCursorOffsets(); + + _index--; + } + } + + else { + if(key > 255 || _index >= _maxSize) return false; + + // else if(_index < s.size()) s.insert(s.begin() + _index, key); + // else if(_index == s.size()) s.push_back(key); + + s[_index] = key; + + _text->update(); + + _calculateCursorOffsets(); + + _index++; + } + + // _text->update(); + + _calculateSize(getTextSize()); + + getParent()->resize(); + */ + + warn() << "Input is disabled until someone can help me understand how to use osgText; sorry..." << std::endl; + + return false; +} + +} diff --git a/src/osgWidget/Label.cpp b/src/osgWidget/Label.cpp new file mode 100644 index 000000000..2618273cd --- /dev/null +++ b/src/osgWidget/Label.cpp @@ -0,0 +1,140 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Label.cpp 59 2008-05-15 20:55:31Z cubicool $ + +#include +#include +#include + +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->setAlignment(osgText::Text::LEFT_BOTTOM); + _text->setDataVariance(osg::Object::DYNAMIC); + + // TODO: Make a patch for this! + // If you're wondering why we don't use this let me explain... + // + // _text->setAlignment(osgText::Text::CENTER_CENTER); + // + // When you set the position of an osgText::Text object which has a CENTER_CENTER + // alignment, the internal implementation of osgText may give it values that have + // a "decimal" portion, which is NO GOOD on orthographic 2D displays where we + // want "pixel perfect" ratios. Thus, until I can remedy this internally with + // osgText::Text, I will need to calculate the center myself. + + setColor(0.0f, 0.0f, 0.0f, 0.0f); +} + +Label::Label(const Label& label, const osg::CopyOp& co): +Widget (label, co), +_textIndex (label._textIndex) { + _text = new osgText::Text(*label._text, co); +} + +void Label::_calculateSize(const XYCoord& size) { + if(size.x() && size.y()) setMinimumSize(size.x(), size.y()); + + if(getWidth() < size.x()) setWidth(size.x()); + + if(getHeight() < size.y()) setHeight(size.y()); +} + +// 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()); + + // Otherwise, add it as new. + else _textIndex = parent->addDrawableAndGetIndex(_text.get()); +} + +void Label::unparented(Window* parent) { + if(_textIndex) parent->getGeode()->removeDrawable(_text.get()); + + _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; + + 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; + warn() << "Label XY coords : " << getX() << " x " << getY() << std::endl; + warn() << "Label BB in size : " << size.x() << " x " << size.y() << std::endl; + warn() << "Label xy position : " << x << " y " << y << std::endl; + warn() << "------------------------------------" << std::endl; + */ + + _text->setPosition(osg::Vec3(x, y, _calculateZ(getLayer() + 1))); +} + +void Label::setLabel(const std::string& label) { + _text->setText(label); + + _calculateSize(getTextSize()); +} + +void Label::setFont(const std::string& font) { + _text->setFont(font); + + _calculateSize(getTextSize()); +} + +void Label::setFontSize(unsigned int size) { + _text->setCharacterSize(size); + _text->setFontResolution(size, size); + + _calculateSize(getTextSize()); +} + +void Label::setFontColor(const Color& c) { + _text->setColor(c); +} + +void Label::setShadow(point_type offset) { + _text->setBackdropType(osgText::Text::DROP_SHADOW_BOTTOM_RIGHT); + _text->setBackdropImplementation(osgText::Text::NO_DEPTH_BUFFER); + _text->setBackdropOffset(offset); + + _calculateSize(getTextSize()); +} + +XYCoord Label::getTextSize() const { + osg::BoundingBox bb = _text->getBound(); + + return XYCoord( + osg::round(bb.xMax() - bb.xMin()), + osg::round(bb.yMax() - bb.yMin()) + ); +} + +} diff --git a/src/osgWidget/Lua.cpp b/src/osgWidget/Lua.cpp new file mode 100644 index 000000000..972b1a46b --- /dev/null +++ b/src/osgWidget/Lua.cpp @@ -0,0 +1,171 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: Lua.cpp 2 2008-01-24 16:11:26Z cubicool $ + +#include +#include +#include +#include + +// If you want to build with LUA, include it--otherwise, typedef some of the data types +// so that we don't pollute our code too much with conditional includes. +#ifdef OSGWIDGET_USELUA +extern "C" { +#include +#include +#include +} +#endif + +namespace osgWidget { + +// This namespace will include all of our Lua library functions. Otherwise, it'll be +// an empty namespace. This is 100% for code clarity, as this namespace is internal and +// not visible to the outside C/C++ world. +namespace lua { +#ifdef OSGWIDGET_USELUA + +// Strings representing our global REGISTRY values. +const char* G_WM = "osgWidget_G_WindowManager"; + +WindowManager* getWindowManager(lua_State* L) { + lua_pushstring(L, G_WM); + lua_gettable(L, LUA_REGISTRYINDEX); + + return reinterpret_cast(lua_touserdata(L, -1)); +} + +int newWindow(lua_State* L) { + osg::ref_ptr w = new Box("testLUA", Box::HORIZONTAL); + + lua_pushstring(L, w->getName().c_str()); + + return 1; +} + +int newWidget(lua_State* L) { + osg::ref_ptr w = new Widget("testLUA", 0.0f, 0.0f); + + lua_pushstring(L, w->getName().c_str()); + + return 1; +} + +int getWindow(lua_State* L) { + WindowManager* wm = getWindowManager(L); + + lua_pushlightuserdata(L, wm); + + return 1; +} + +#endif +} + +// A helper function for all those cases where we need to inform the user that there isn't +// a LUA engine available. +bool noLuaFail(const std::string& err) { + warn() << err << "; Lua not compiled in library." << std::endl; + + return false; +} + +// Our "private", internal data. +struct LuaEngineData { +#ifdef OSGWIDGET_USELUA + LuaEngineData(): + lua(0) { + } + + lua_State* lua; +#endif +}; + +LuaEngine::LuaEngine(WindowManager* wm): +_wm(wm) { +#ifdef OSGWIDGET_USELUA + _data = new LuaEngineData(); + +#else + _data = 0; +#endif +} + +bool LuaEngine::initialize() { +#ifdef OSGWIDGET_USELUA + _data->lua = lua_open(); + + luaL_openlibs(_data->lua); + + static const struct luaL_reg library[] = { + {"newWindow", lua::newWindow}, + {"newWidget", lua::newWidget}, + {"getWindow", lua::getWindow}, + {0, 0} + }; + + luaL_openlib(_data->lua, "osgwidget", library, 0); + + // An alternative to using the Registry here would be to pass the WindowManager + // as a userdata "closure" (pvalue). Please see the following doc on more info: + // http://www.lua.org/pil/27.3.3.html + lua_pushstring(_data->lua, lua::G_WM); + lua_pushlightuserdata(_data->lua, _wm); + lua_settable(_data->lua, LUA_REGISTRYINDEX); + + return true; + +#else + return noLuaFail("Can't initialize the LuaEngine"); +#endif +} + +bool LuaEngine::close() { +#ifdef OSGWIDGET_USELUA + lua_close(_data->lua); + + delete _data; + + return true; + +#else + return noLuaFail("Can't close the LuaEngine"); +#endif +} + +bool LuaEngine::eval(const std::string& code) { +#ifdef OSGWIDGET_USELUA + if(luaL_dostring(_data->lua, code.c_str())) { + warn() << "LuaEngine::eval - " << lua_tostring(_data->lua, -1) << std::endl; + + return false; + } + + return true; + +#else + return noLuaFail("Can't evaluate code in LuaEngine"); +#endif +} + +bool LuaEngine::runFile(const std::string& filePath) { +#ifdef OSGWIDGET_USELUA + if(!osgDB::fileExists(filePath)) { + warn() << "Couldn't find file \"" << filePath << "\" for LuaEngine." << std::endl; + + return false; + } + + if(luaL_dofile(_data->lua, filePath.c_str())) { + warn() << "LuaEngine::runFile - " << lua_tostring(_data->lua, -1) << std::endl; + + return false; + } + + return true; + +#else + return noLuaFail("Can't run file in LuaEngine"); +#endif +} + +} diff --git a/src/osgWidget/Python.cpp b/src/osgWidget/Python.cpp new file mode 100644 index 000000000..e5fb28711 --- /dev/null +++ b/src/osgWidget/Python.cpp @@ -0,0 +1,215 @@ +// -*-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 +#include +#endif + +#include +#include +#include +#include + +namespace osgWidget { + +// Our Python library. +namespace py { +#ifdef OSGWIDGET_USEPYTHON + +// TODO: Until I can find a way to move data around inside of the context, this will +// have to do. I don't really like it, but I've got no choice. +static PyObject* G_ERR = 0; + +PyObject* newWindow(PyObject* self, PyObject* args) { + PyObject* buffer = 0; + const char* name = 0; + int width = 0; + int height = 0; + + /* + if(PyArg_ParseTuple(args, "sO!ii", &name, &PyBuffer_Type, &buffer, &width, &height)) { + const void* buf = 0; + int len = 0; + + if(!PyObject_AsReadBuffer(buffer, &buf, &len)) { + // if(Database::instance().add(name, buf, width, height)) + return Py_BuildValue("i", len); + + // else PyErr_SetString(G_ERR, "Couldn't add image to database."); + } + + else PyErr_SetString(G_ERR, "Couldn't read buffer data."); + + return 0; + } + */ + + PyErr_SetString(G_ERR, "still testing..."); + + return 0; +} + +static PyMethodDef methods[] = { + { + "newWindow", newWindow, METH_VARARGS, + "docstring" + }, + { 0, 0, 0, 0 } +}; + +#endif +} + +// A helper function for all those cases where we need to inform the user that there isn't +// a LUA engine available. +bool noPythonFail(const std::string& err) { + warn() << err << "; Python not compiled in library." << std::endl; + + return false; +} + +// Our "private", internal data. +struct PythonEngineData { +#ifdef OSGWIDGET_USEPYTHON + PythonEngineData(): + mod (0), + err (0), + main (0) { + } + + bool valid() const { + return mod && err && main; + } + + PyObject* mod; + PyObject* err; + PyObject* main; +#endif +}; + +PythonEngine::PythonEngine(WindowManager* wm): +_wm(wm) { +#ifdef OSGWIDGET_USEPYTHON + _data = new PythonEngineData(); + +#else + _data = 0; +#endif +} + +bool PythonEngine::initialize() { +#ifdef OSGWIDGET_USEPYTHON + Py_InitializeEx(0); + + if(!_data->valid()) { + _data->mod = Py_InitModule3("osgwidget", py::methods, "main docstring"); + _data->err = PyErr_NewException((char*)("osgwidget.error"), 0, 0); + _data->main = PyModule_GetDict(PyImport_AddModule("__main__")); + + Py_INCREF(_data->err); + + // TODO: ...sigh... + py::G_ERR = _data->err; + + PyModule_AddObject(_data->mod, "error", _data->err); + } + + return true; + +#else + return noPythonFail("Can't initialize the PythonEngine"); +#endif +} + +bool PythonEngine::close() { +#ifdef OSGWIDGET_USEPYTHON + if(_data->valid()) { + Py_DECREF(_data->err); + + Py_Finalize(); + } + + delete _data; + + return true; + +#else + return noPythonFail("Can't close the PythonEngine"); +#endif +} + +bool PythonEngine::eval(const std::string& code) { +#ifdef OSGWIDGET_USEPYTHON + PyObject* r = PyRun_String(code.c_str(), Py_file_input, _data->main, _data->main); + + if(!r) { + r = PyErr_Occurred(); + + if(r) { + PyErr_Print(); + PyErr_Clear(); + } + + return false; + } + + return true; + +#else + return noPythonFail("Can't evaluate code in PythonEngine"); +#endif +} + +bool PythonEngine::runFile(const std::string& filePath) { +#ifdef OSGWIDGET_USEPYTHON + if(!osgDB::fileExists(filePath)) { + warn() + << "Couldn't find file \"" << filePath << "\" for PythonEngine." + << std::endl + ; + + return false; + } + + FILE* f = fopen(filePath.c_str(), "r"); + PyObject* r = PyRun_File(f, filePath.c_str(), Py_file_input, _data->main, _data->main); + + fclose(f); + + if(!r) { + r = PyErr_Occurred(); + + if(r) { + // The following snippet lets us get the return code. That is: if the + // script is stopped with sys.exit() or similar. We could use this + // return code to do something sensible... later. + if(PyErr_ExceptionMatches(PyExc_SystemExit)) { + PyObject* ty = 0; + PyObject* er = 0; + PyObject* tr = 0; + + PyErr_Fetch(&ty, &er, &tr); + + Py_DECREF(ty); + Py_DECREF(er); + Py_DECREF(er); + } + + else { + PyErr_Print(); + PyErr_Clear(); + } + } + + return false; + } + + return true; + +#else + return noPythonFail("Can't evaluate code in PythonEngine"); +#endif +} + +} diff --git a/src/osgWidget/StyleManager.cpp b/src/osgWidget/StyleManager.cpp new file mode 100644 index 000000000..fbe0345b2 --- /dev/null +++ b/src/osgWidget/StyleManager.cpp @@ -0,0 +1,376 @@ +// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 +// $Id: StyleManager.cpp 55 2008-05-12 19:14:42Z cubicool $ + +#include +#include +#include + +namespace osgWidget { + +Style::Style(const std::string& name, const std::string& style): +_style(style) { + setName(name); +} + +Style::Style(const Style& style, const osg::CopyOp& co): +osg::Object (style, co), +_style (style._style) { +} + +bool Style::applyStyle(Widget* widget, Reader r) { + std::string str; + osg::Vec2 vec2; + osg::Vec3 vec3; + osg::Vec4 vec4; + float f; + + if(_match("pos %i %i", r) || _match("pos %f %f", r)) { + r.readSequence(vec2); + + widget->setOrigin(vec2); + } + + else if(_match("pos-x %i", r) || _match("pos-x %f", r)) { + r.readSequence(f); + + widget->setX(f); + } + + else if(_match("pos-y %i", r) || _match("pos-y %f", r)) { + r.readSequence(f); + + widget->setY(f); + } + + else if(_match("size %i %i", r) || _match("size %f %f", r)) { + r.readSequence(vec2); + + widget->setSize(vec2); + } + + else if(_match("width %i", r) || _match("width %f", r)) { + r.readSequence(f); + + widget->setWidth(f); + } + + else if(_match("height %i", r) || _match("height %f", r)) { + r.readSequence(f); + + widget->setHeight(f); + } + + // Color using 4x 0-255 integers. + else if(_match("color %i %i %i %i", r)) { + r.readSequence(vec4); + + widget->setColor(vec4 / 255.0f); + } + + // Color using 3x 0-255 integers with a default alpha of 255. + else if(_match("color %i %i %i", r)) { + r.readSequence(vec3); + + widget->setColor(osg::Vec4(vec3[0], vec3[1], vec3[2], 255.0f) / 255.0f); + } + + // Color using 4x 0.0f-1.0f floats. + else if(_match("color %f %f %f %f", r)) { + r.readSequence(vec4); + + widget->setColor(vec4); + } + + // Color using 3x 0.0f-1.0f floats with a default alpha of 1.0f. + else if(_match("color %f %f %f", r)) { + r.readSequence(vec3); + + widget->setColor(osg::Vec4(vec3[0], vec3[1], vec3[2], 1.0f)); + } + + // Set padding uniformly. + else if(_match("padding %i", r)) { + r.readSequence(f); + + widget->setPadding(f); + } + + // Set left padding. + else if(_match("padding-left %i", r)) { + r.readSequence(f); + + widget->setPadLeft(f); + } + + // Set right padding. + else if(_match("padding-right %i", r)) { + r.readSequence(f); + + widget->setPadRight(f); + } + + // Set top padding. + else if(_match("padding-top %i", r)) { + r.readSequence(f); + + widget->setPadTop(f); + } + + // Set bottom padding. + else if(_match("padding-bottom %i", r)) { + r.readSequence(f); + + widget->setPadBottom(f); + } + + else if(_match("layer %w", r)) { + r.readSequence(str); + + widget->setLayer(strToLayer(str)); + } + + else if(_match("valign %w", r)) { + r.readSequence(str); + + widget->setAlignVertical(strToVAlign(str)); + } + + else if(_match("halign %w", r)) { + r.readSequence(str); + + widget->setAlignHorizontal(strToHAlign(str)); + } + + else if(_match("coordmode %w", r)) { + r.readSequence(str); + + widget->setCoordinateMode(strToCoordMode(str)); + } + + else if(_match("fill %w", r)) { + r.readSequence(str); + + widget->setCanFill(strToFill(str)); + } + + else if(_match("image %s", r)) { + r.readSequence(str); + + widget->setImage(str, true); + } + + // Otherwise, increment the stream pointer. + else return false; + + return true; +} + +bool Style::applyStyle(Label* label, Reader r) { + return false; +} + +bool Style::applyStyle(Input* input, Reader r) { + return false; +} + +bool Style::applyStyle(Window* window, Reader r) { + osg::Vec2 vec2; + float f; + + if(_match("pos %i %i", r) || _match("pos %f %f", r)) { + r.readSequence(vec2); + + window->setOrigin(vec2.x(), vec2.y()); + } + + else if(_match("pos-x %i", r) || _match("pos-x %f", r)) { + r.readSequence(f); + + window->setX(f); + } + + else if(_match("pos-y %i", r) || _match("pos-y %f", r)) { + r.readSequence(f); + + window->setY(f); + } + + else if(_match("size %i %i", r) || _match("size %f %f", r)) { + r.readSequence(vec2); + + window->resize(vec2.x(), vec2.y()); + } + + else if(_match("width %i", r) || _match("width %f", r)) { + r.readSequence(f); + + window->resize(f); + } + + else if(_match("height %i", r) || _match("height %f", r)) { + r.readSequence(f); + + window->resize(0.0f, f); + } + + else return false; + + return true; +} + +bool Style::applyStyle(Window::EmbeddedWindow*, Reader r) { + return false; +} + +bool Style::applyStyle(Box* box, Reader r) { + if(applyStyle(static_cast(box), r)) return true; + + return false; +} + +bool Style::applyStyle(Frame::Corner*, Reader r) { + return false; +} + +bool Style::applyStyle(Frame::Border*, Reader r) { + return false; +} + +Widget::LAYER Style::strToLayer(const std::string& layer) { + std::string l = lowerCase(layer); + + if(l == "top") return Widget::LAYER_TOP; + + else if(l == "high") return Widget::LAYER_HIGH; + + else if(l == "middle") return Widget::LAYER_MIDDLE; + + else if(l == "low") return Widget::LAYER_LOW; + + else if(l == "bg") return Widget::LAYER_BG; + + else { + warn() << "Unkown Layer name [" << layer << "]; using LAYER_MIDDLE." << std::endl; + + return Widget::LAYER_MIDDLE; + } +} + +Widget::VERTICAL_ALIGNMENT Style::strToVAlign(const std::string& valign) { + std::string va = lowerCase(valign); + + if(va == "center") return Widget::VA_CENTER; + + else if(va == "top") return Widget::VA_TOP; + + else if(va == "bottom") return Widget::VA_BOTTOM; + + else { + warn() << "Unkown VAlign name [" << valign << "]; using VA_CENTER." << std::endl; + + return Widget::VA_CENTER; + } +} + +Widget::HORIZONTAL_ALIGNMENT Style::strToHAlign(const std::string& halign) { + std::string ha = lowerCase(halign); + + if(ha == "center") return Widget::HA_CENTER; + + else if(ha == "left") return Widget::HA_LEFT; + + else if(ha == "right") return Widget::HA_RIGHT; + + else { + warn() << "Unkown HAlign name [" << halign << "]; using HA_CENTER." << std::endl; + + return Widget::HA_CENTER; + } +} + +Widget::COORDINATE_MODE Style::strToCoordMode(const std::string& coordmode) { + std::string cm = lowerCase(coordmode); + + if(cm == "absolute") return Widget::CM_ABSOLUTE; + + else if(cm == "relative") return Widget::CM_RELATIVE; + + else { + warn() + << "Unkown CoordMode name [" << coordmode + << "]; using CM_ABSOLUTE." << std::endl + ; + + return Widget::CM_ABSOLUTE; + } +} + +bool Style::strToFill(const std::string& fill) { + std::string cm = lowerCase(fill); + + if(cm == "true") return true; + + else if(cm == "false") return false; + + else { + warn() + << "Unkown Fill name [" << fill + << "]; using false." << std::endl + ; + + return false; + } +} + +StyleManager::StyleManager() { +} + +StyleManager::StyleManager(const StyleManager& manager, const osg::CopyOp& co): +osg::Object(manager, co) { + for(ConstIterator i = _styles.begin(); i != _styles.end(); i++) if(i->second.valid()) { + _styles[i->first] = new Style(*i->second.get(), osg::CopyOp::DEEP_COPY_ALL); + } +} + +bool StyleManager::_applyStyleToObject(osg::Object* obj, const std::string& style) { + std::string c = obj->className(); + + if(!std::string("Widget").compare(c)) return _coerceAndApply( + obj, + style, + c + ); + + else if(!std::string("Label").compare(c)) return _coerceAndApply