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
This commit is contained in:
Robert Osfield
2008-07-15 17:21:25 +00:00
parent 0c3d119cea
commit c2b77aa08e
77 changed files with 9643 additions and 15 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/FileUtils>
#include <osgWidget/Box>
bool osgWidget_Box_readData(osg::Object& obj, osgDB::Input& fr) {
/*
osgWidget::Box& box = static_cast<osgWidgegt::Box&>(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<const osgWidget::Box&>(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<osgCal::Model&>(obj);
osgCal::osgWidget_Box* core = static_cast<osgCal::osgWidget_Box*>(
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<const osgCal::Model&>(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
);

View File

@@ -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)

View File

@@ -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 <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/FileUtils>
#include <osgWidget/Window>
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<const osgWidget::Window::EmbeddedWindow&>(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
);

View File

@@ -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 <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/FileUtils>
#include <osgWidget/Frame>
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<const osgWidget::Frame&>(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
);

View File

@@ -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 <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/FileUtils>
#include <osgWidget/Input>
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<const osgWidget::Input&>(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
);

View File

@@ -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 <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/FileUtils>
#include <osgWidget/Label>
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<const osgWidget::Label&>(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
);

View File

@@ -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 <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/FileUtils>
#include <osgWidget/Table>
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<const osgWidget::Table&>(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
);

View File

@@ -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 <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/FileUtils>
#include <osgWidget/Util>
#include <osgWidget/Widget>
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<const osgWidget::Widget&>(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<const osgWidget::NotifyWidget&>(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<const osgWidget::NullWidget&>(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
);

View File

@@ -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 <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/FileUtils>
#include <osgWidget/WindowManager>
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<const osgWidget::WindowManager&>(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
);

194
src/osgWidget/Box.cpp Normal file
View File

@@ -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 <osgWidget/Box>
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<int>(w);
int ih = static_cast<int>(h);
int inumFill = static_cast<int>(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<point_type>(iw / inumFill);
if(cur >= _lastAdd && wrem) {
_lastAdd++;
addWidth++;
wrem--;
}
}
if(h) addHeight += h;
}
else {
if(w) addWidth += w;
if(h) {
addHeight += static_cast<point_type>(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<Plus>(&Widget::getWidthTotal),
_accumulate<Plus>(&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<Plus>(&Widget::getHeightTotal),
_accumulate<Plus>(&Widget::getMinHeightTotal)
);
}
else return Sizes(
_getMaxWidgetHeightTotal(),
_getMaxWidgetMinHeightTotal()
);
}
}

View File

@@ -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)

32
src/osgWidget/Canvas.cpp Normal file
View File

@@ -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 <osgWidget/Canvas>
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;
}
}

251
src/osgWidget/Frame.cpp Normal file
View File

@@ -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 <osgDB/ReadFile>
#include <osgWidget/WindowManager>
#include <osgWidget/Frame>
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<Widget*>(getByName(cornerToString(c)));
}
Widget* Frame::_getBorder(BORDER b) const {
return const_cast<Widget*>(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;
}
}

176
src/osgWidget/Input.cpp Normal file
View File

@@ -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 <osg/io_utils>
#include <osgWidget/WindowManager>
#include <osgWidget/Input>
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<char>(_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<point_type>(_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;
}
}

140
src/osgWidget/Label.cpp Normal file
View File

@@ -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 <osg/Math>
#include <osgWidget/WindowManager>
#include <osgWidget/Label>
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())
);
}
}

171
src/osgWidget/Lua.cpp Normal file
View File

@@ -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 <osgDB/FileUtils>
#include <osgWidget/Lua>
#include <osgWidget/Box>
#include <osgWidget/WindowManager>
// 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 <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#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<WindowManager*>(lua_touserdata(L, -1));
}
int newWindow(lua_State* L) {
osg::ref_ptr<Window> w = new Box("testLUA", Box::HORIZONTAL);
lua_pushstring(L, w->getName().c_str());
return 1;
}
int newWidget(lua_State* L) {
osg::ref_ptr<Widget> 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
}
}

215
src/osgWidget/Python.cpp Normal file
View File

@@ -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 <Python.h>
#endif
#include <osgDB/FileUtils>
#include <osgWidget/Python>
#include <osgWidget/Box>
#include <osgWidget/WindowManager>
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
}
}

View File

@@ -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 <sstream>
#include <osg/io_utils>
#include <osgWidget/StyleManager>
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<Window*>(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<Widget>(
obj,
style,
c
);
else if(!std::string("Label").compare(c)) return _coerceAndApply<Label>(
obj,
style,
c
);
else if(!std::string("Box").compare(c)) return _coerceAndApply<Box>(
obj,
style,
c
);
else warn()
<< "StyleManager does not support coercion of objects of type "
<< c << "." << std::endl
;
return false;
}
bool StyleManager::addStyle(Style* style) {
if(!style || style->getName().empty()) {
warn() << "Cannot add a NULL or nameless Style object." << std::endl;
return false;
}
_styles[style->getName()] = style;
return true;
}
}

225
src/osgWidget/Table.cpp Normal file
View File

@@ -0,0 +1,225 @@
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
// $Id: Table.cpp 48 2008-05-05 14:13:20Z cubicool $
#include <osgWidget/Table>
namespace osgWidget {
// TODO: There is a serious, outstanding bug with regards to USING a table before ALL Widgets
// are set! FIX THIS!!!
Table::Table(const std::string& name, unsigned int rows, unsigned int cols):
Window (name),
_rows (rows),
_cols (cols),
_lastRowAdd (0),
_lastColAdd (0) {
_objects.resize(_rows * _cols);
}
Table::Table(const Table& table, const osg::CopyOp& co):
Window (table, co),
_rows (table._rows),
_cols (table._cols),
_lastRowAdd (table._lastRowAdd),
_lastColAdd (table._lastColAdd) {
}
unsigned int Table::_calculateIndex(unsigned int row, unsigned int col) const {
return (row * _cols) + col;
}
void Table::_getRows(CellSizes& rows, Getter get) const {
for(unsigned int i = 0; i < _rows; i++) rows.push_back(
_compare<Greater>(get, i * _cols, (i * _cols) + _cols)
);
}
void Table::_getColumns(CellSizes& cols, Getter get) const {
for(unsigned int i = 0; i < _cols; i++) cols.push_back(
_compare<Greater>(get, i, 0, _cols)
);
}
void Table::_resizeImplementation(point_type width, point_type height) {
// We use these vectors so that we don't have to repeatedly call isFillable
// all the time. Usage such as this can really generate a lot of moronic,
// misinformed opposition, but until std::bit_vector is available, this is
// what we get. Deal with it.
std::vector<bool> rowFills;
std::vector<bool> colFills;
point_type numRowFills = 0.0f;
point_type numColFills = 0.0f;
// Enumerate each row and determine whether it can fill. If so, increment
// our numRowFills variable and set the position in rowFills to "true."
for(unsigned int row = 0; row < _rows; row++) {
bool fill = isRowVerticallyFillable(row);
if(fill) numRowFills++;
rowFills.push_back(fill);
}
// Enumerate each column and determine whether it can fill. If so, increment
// our numColFills variable and set the position in colFills to "true."
for(unsigned int col = 0; col < _cols; col++) {
bool fill = isColumnHorizontallyFillable(col);
if(fill) numColFills++;
colFills.push_back(fill);
}
int wrem = 0;
int hrem = 0;
if(numRowFills > 0.0f) {
hrem = static_cast<int>(height) % static_cast<int>(numRowFills);
unsigned int cur = 0;
for(unsigned int row = 0; row < _rows; row++) {
point_type h = height / numRowFills;
if(cur >= _lastRowAdd && hrem) {
_lastRowAdd++;
h++;
hrem--;
}
if(rowFills[row]) addHeightToRow(row, h);
cur++;
}
}
if(numColFills > 0.0f) {
wrem = static_cast<int>(width) % static_cast<int>(numColFills);
unsigned int cur = 0;
for(unsigned int col = 0; col < _cols; col++) {
point_type w = width / numColFills;
if(cur >= _lastColAdd && wrem) {
_lastColAdd++;
w++;
wrem--;
}
if(colFills[col]) addWidthToColumn(col, w);
cur++;
}
}
CellSizes rowHeights;
CellSizes colWidths;
getRowHeights(rowHeights);
getColumnWidths(colWidths);
point_type y = 0.0f;
for(unsigned int row = 0; row < _rows; row++) {
point_type x = 0.0f;
for(unsigned int col = 0; col < _cols; col++) {
Widget* widget = _objects[_calculateIndex(row, col)].get();
if(widget) {
widget->setOrigin(x, y);
_positionWidget(widget, colWidths[col], rowHeights[row]);
}
x += colWidths[col];
}
y += rowHeights[row];
}
}
Window::Sizes Table::_getWidthImplementation() const {
CellSizes cols;
CellSizes minCols;
getColumnWidths(cols);
getColumnMinWidths(minCols);
return Sizes(
std::accumulate(cols.begin(), cols.end(), 0.0f, Plus()),
std::accumulate(minCols.begin(), minCols.end(), 0.0f, Plus())
);
}
Window::Sizes Table::_getHeightImplementation() const {
CellSizes rows;
CellSizes minRows;
getRowHeights(rows);
getRowMinHeights(minRows);
return Sizes(
std::accumulate(rows.begin(), rows.end(), 0.0f, Plus()),
std::accumulate(minRows.begin(), minRows.end(), 0.0f, Plus())
);
}
bool Table::addWidget(Widget* widget) {
return addWidget(widget, 0, 0);
}
bool Table::addWidget(Widget* widget, unsigned int row, unsigned int col) {
return Window::insertWidget(widget, _calculateIndex(row, col));
}
void Table::getRowHeights(CellSizes& rowHeights) const {
_getRows(rowHeights, &Widget::getHeightTotal);
}
void Table::getRowMinHeights(CellSizes& rowMinHeights) const {
_getRows(rowMinHeights, &Widget::getMinHeightTotal);
}
void Table::getColumnWidths(CellSizes& colWidths) const {
_getColumns(colWidths, &Widget::getWidthTotal);
}
void Table::getColumnMinWidths(CellSizes& colMinWidths) const {
_getColumns(colMinWidths, &Widget::getMinWidthTotal);
}
void Table::addHeightToRow(unsigned int row, point_type height) {
for(
Iterator i = begin() + (row * _cols);
i != begin() + ((row * _cols) + _cols);
i++
) if(i->valid()) i->get()->addHeight(height);
}
void Table::addWidthToColumn(unsigned int col, point_type width) {
// See the documentation in include/osgWidget/Window::_forEachApplyOrAssign if you want
// to know why we need this variable.
unsigned int c = col;
for(Iterator i = begin() + col; i < end(); c += _cols) {
if(i->valid()) i->get()->addWidth(width);
if((c + _cols) < size()) i += _cols;
else i = end();
}
}
bool Table::isRowVerticallyFillable(unsigned int row) const {
return static_cast<point_type>(_cols) == _getNumFill(row * _cols, (row * _cols) + _cols);
}
bool Table::isColumnHorizontallyFillable(unsigned int col) const {
return static_cast<point_type>(_rows) == _getNumFill(col, 0, _cols);
}
}

176
src/osgWidget/Util.cpp Normal file
View File

@@ -0,0 +1,176 @@
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
// $Id: Util.cpp 59 2008-05-15 20:55:31Z cubicool $
#include <osg/io_utils>
#include <osgGA/TrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <osgDB/FileUtils>
#include <osgDB/WriteFile>
#include <osgViewer/ViewerEventHandlers>
#include <osgWidget/Util>
#include <osgWidget/ViewerEventHandlers>
#include <osgWidget/WindowManager>
namespace osgWidget {
std::string getFilePath(const std::string& filename) {
osgDB::FilePathList path;
char* fp = getenv("OSGWIDGET_FILE_PATH");
osgDB::convertStringPathIntoFilePathList(fp ? fp : ".", path);
return osgDB::findFileInPath(filename, path);
}
std::string generateRandomName(const std::string& base) {
static unsigned int count = 0;
std::stringstream ss;
ss << base << "_" << count;
count++;
return ss.str();
}
osg::Matrix createInvertedYOrthoProjectionMatrix(matrix_type width, matrix_type height) {
osg::Matrix m = osg::Matrix::ortho2D(0.0f, width, 0.0f, height);
osg::Matrix s = osg::Matrix::scale(1.0f, -1.0f, 1.0f);
osg::Matrix t = osg::Matrix::translate(0.0f, -height, 0.0f);
return t * s * m;
}
osg::Camera* createOrthoCamera(matrix_type width, matrix_type height) {
osg::Camera* camera = new osg::Camera();
camera->getOrCreateStateSet()->setMode(
GL_LIGHTING,
osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF
);
camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0, width, 0.0f, height));
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
camera->setViewMatrix(osg::Matrix::identity());
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
camera->setRenderOrder(osg::Camera::POST_RENDER);
return camera;
}
osg::Camera* createInvertedYOrthoCamera(matrix_type width, matrix_type height) {
osg::Camera* camera = createOrthoCamera(width, height);
camera->setProjectionMatrix(createInvertedYOrthoProjectionMatrix(width, height));
return camera;
}
osg::Group* _createExampleCommon(osgViewer::View* view, WindowManager* wm, osg::Node* node) {
if(!wm) return 0;
view->setUpViewInWindow(
0,
0,
static_cast<int>(wm->getWidth()),
static_cast<int>(wm->getHeight())
);
osg::Group* group = new osg::Group();
osg::Camera* camera = wm->createParentOrthoCamera();
group->addChild(camera);
if(node) group->addChild(node);
view->addEventHandler(new osgWidget::MouseHandler(wm));
view->addEventHandler(new osgWidget::KeyboardHandler(wm));
view->addEventHandler(new osgWidget::ResizeHandler(wm, camera));
view->addEventHandler(new osgViewer::StatsHandler());
view->addEventHandler(new osgViewer::WindowSizeHandler());
view->addEventHandler(new osgGA::StateSetManipulator(
view->getCamera()->getOrCreateStateSet()
));
wm->resizeAllWindows();
return group;
}
int createExample(osgViewer::Viewer& viewer, WindowManager* wm, osg::Node* node) {
osg::Group* group = _createExampleCommon(&viewer, wm, node);
viewer.setSceneData(group);
return viewer.run();
}
// TODO: This function is totally broken; I don't really have any idea of how to do this.
// Incredibly frustrating stuff.
int createCompositeExample(
osgViewer::CompositeViewer& viewer,
osgViewer::View* view,
WindowManager* wm,
osg::Node* node
) {
osg::Group* group = _createExampleCommon(view, wm, node);
osg::MatrixTransform* watcher = new osg::MatrixTransform();
watcher->addChild(wm);
// Setup the main 2D view.
viewer.addView(view);
view->setSceneData(group);
// The view that "watches" the main view.
osgViewer::View* viewWatcher = new osgViewer::View();
viewer.addView(viewWatcher);
int w = static_cast<int>(wm->getWidth());
int h = static_cast<int>(wm->getHeight());
viewWatcher->setUpViewInWindow(0, 0, w, h);
// Setup our parent MatrixTransform so things look right in perspective.
watcher->setMatrix(
osg::Matrix::scale(1.0f, -1.0f, 1000.0f) *
osg::Matrix::rotate(osg::DegreesToRadians(90.0f), osg::Vec3d(1.0f, 0.0f, 0.0f))
);
watcher->getOrCreateStateSet()->setAttributeAndModes(
new osg::Scissor(0, 0, w, h),
osg::StateAttribute::OVERRIDE
);
osgGA::TrackballManipulator* tb = new osgGA::TrackballManipulator();
warn() << watcher->getMatrix() << std::endl;
/*
const osg::BoundingSphere& bs = watcher->getBound();
tb->setHomePosition(
bs.center() + osg::Vec3(0.0f, -3.5f * bs.radius(), 0.0f),
bs.center(),
osg::Vec3(0.0f, 1.0f, 0.0f)
);
*/
viewWatcher->setSceneData(watcher);
viewWatcher->setCameraManipulator(tb);
return viewer.run();
}
bool writeWindowManagerNode(WindowManager* wm) {
osgDB::writeNodeFile(*wm->getParent(0), "osgWidget.osg");
return true;
}
}

83
src/osgWidget/Version.cpp Normal file
View File

@@ -0,0 +1,83 @@
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
// $Id: Version.cpp 64 2008-06-30 21:32:00Z cubicool $
#include <sstream>
#include <osgWidget/Version>
extern "C" {
const unsigned int OSGWIDGET_MAJOR_VERSION = 0;
const unsigned int OSGWIDGET_MINOR_VERSION = 1;
const unsigned int OSGWIDGET_PATCH_VERSION = 8;
const char* OSGWIDGET_EXTRA_TEXT = "(pre-merge)";
unsigned int osgWidgetGetMajorVersion() {
return OSGWIDGET_MAJOR_VERSION;
}
unsigned int osgWidgetGetMinorVersion() {
return OSGWIDGET_MINOR_VERSION;
}
unsigned int osgWidgetGetPatchVersion() {
return OSGWIDGET_PATCH_VERSION;
}
const char* osgWidgetGetExtraText() {
return OSGWIDGET_EXTRA_TEXT;
}
const char* osgWidgetGetVersion() {
static std::string version;
static bool versionInit = true;
if(versionInit) {
std::stringstream stream;
stream.str(std::string());
stream
<< OSGWIDGET_MAJOR_VERSION << "."
<< OSGWIDGET_MINOR_VERSION << "."
<< OSGWIDGET_PATCH_VERSION << " "
<< OSGWIDGET_EXTRA_TEXT
;
version = stream.str();
versionInit = false;
}
return version.c_str();
}
const char* osgWidgetGetLibraryName() {
static std::string name("OpenSceneGraph Widget Library");
return name.c_str();
}
bool osgWidgetVersionMinimum(unsigned int major, unsigned int minor, unsigned int patch) {
return
OSGWIDGET_MAJOR_VERSION >= major &&
OSGWIDGET_MINOR_VERSION >= minor &&
OSGWIDGET_PATCH_VERSION >= patch
;
}
bool osgWidgetVersionMaximum(unsigned int major, unsigned int minor, unsigned int patch) {
return
// OSGWIDGET_MAJOR_VERSION <= major &&
OSGWIDGET_MINOR_VERSION <= minor &&
OSGWIDGET_PATCH_VERSION <= patch
;
}
bool osgWidgetVersionRequired(unsigned int major, unsigned int minor, unsigned int patch) {
return
OSGWIDGET_MAJOR_VERSION == major &&
OSGWIDGET_MINOR_VERSION == minor &&
OSGWIDGET_PATCH_VERSION == patch
;
}
}

View File

@@ -0,0 +1,190 @@
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
// $Id: ViewerEventHandlers.cpp 59 2008-05-15 20:55:31Z cubicool $
#include <osgWidget/ViewerEventHandlers>
namespace osgWidget {
MouseHandler::MouseHandler(WindowManager* wm):
_wm(wm) {
}
bool MouseHandler::handle(
const osgGA::GUIEventAdapter& gea,
osgGA::GUIActionAdapter& gaa,
osg::Object* obj,
osg::NodeVisitor* nv
) {
osgGA::GUIEventAdapter::EventType ev = gea.getEventType();
MouseAction ma = _isMouseEvent(ev);
if(ma) {
// If we're scrolling, we need to inform the WindowManager of that.
_wm->setScrollingMotion(gea.getScrollingMotion());
return (this->*ma)(gea.getX(), gea.getY(), gea.getButton());
}
return false;
}
bool MouseHandler::_handleMousePush(float x, float y, int button) {
if(button == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) return _doMouseEvent(
x,
y,
&WindowManager::mousePushedLeft
);
else if(button == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) return _doMouseEvent(
x,
y,
&WindowManager::mousePushedRight
);
else if(button == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON) return _doMouseEvent(
x,
y,
&WindowManager::mousePushedMiddle
);
else return false;
}
bool MouseHandler::_handleMouseRelease(float x, float y, int button) {
if(button == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) return _doMouseEvent(
x,
y,
&WindowManager::mouseReleasedLeft
);
else if(button == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) return _doMouseEvent(
x,
y,
&WindowManager::mouseReleasedRight
);
else if(button == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON) return _doMouseEvent(
x,
y,
&WindowManager::mouseReleasedMiddle
);
else return false;
}
bool MouseHandler::_handleMouseDoubleClick(float x, float y, int button) {
return false;
}
bool MouseHandler::_handleMouseDrag(float x, float y, int button) {
return _doMouseEvent(x, y, &WindowManager::pointerDrag);
}
bool MouseHandler::_handleMouseMove(float x, float y, int button) {
return _doMouseEvent(x, y, &WindowManager::pointerMove);
}
bool MouseHandler::_handleMouseScroll(float x, float y, int) {
return _doMouseEvent(x, y, &WindowManager::mouseScroll);
}
MouseHandler::MouseAction MouseHandler::_isMouseEvent(
osgGA::GUIEventAdapter::EventType ev
) const {
if(ev == osgGA::GUIEventAdapter::PUSH) return
&MouseHandler::_handleMousePush
;
else if(ev == osgGA::GUIEventAdapter::RELEASE) return
&MouseHandler::_handleMouseRelease
;
else if(ev == osgGA::GUIEventAdapter::DOUBLECLICK) return
&MouseHandler::_handleMouseDoubleClick
;
else if(ev == osgGA::GUIEventAdapter::DRAG) return
&MouseHandler::_handleMouseDrag
;
else if(ev == osgGA::GUIEventAdapter::MOVE) return
&MouseHandler::_handleMouseMove
;
else if(ev == osgGA::GUIEventAdapter::SCROLL) return
&MouseHandler::_handleMouseScroll
;
else return 0;
}
bool MouseHandler::_doMouseEvent(float x, float y, MouseEvent me) {
bool handled = (_wm.get()->*me)(x, y);
// This is called LAST for things like drag, which needs to calculate a mouse difference.
_wm->setPointerXY(x, y);
return handled;
}
KeyboardHandler::KeyboardHandler(WindowManager* wm):
_wm(wm) {
}
bool KeyboardHandler::handle(
const osgGA::GUIEventAdapter& gea,
osgGA::GUIActionAdapter& gaa,
osg::Object* obj,
osg::NodeVisitor* nv
) {
osgGA::GUIEventAdapter::EventType ev = gea.getEventType();
if(
ev != osgGA::GUIEventAdapter::KEYDOWN &&
ev != osgGA::GUIEventAdapter::KEYUP
) return false;
int key = gea.getKey();
int keyMask = gea.getModKeyMask();
// -1 is the "key invalid" return code.
if(key == -1) return false;
if(ev == osgGA::GUIEventAdapter::KEYDOWN) return _wm->keyDown(key, keyMask);
else if(ev == osgGA::GUIEventAdapter::KEYUP) return _wm->keyUp(key, keyMask);
return false;
}
ResizeHandler::ResizeHandler(WindowManager* wm, osg::Camera* camera):
_wm (wm),
_camera (camera) {
}
bool ResizeHandler::handle(
const osgGA::GUIEventAdapter& gea,
osgGA::GUIActionAdapter& gaa,
osg::Object* obj,
osg::NodeVisitor* nv
) {
osgGA::GUIEventAdapter::EventType ev = gea.getEventType();
if(ev != osgGA::GUIEventAdapter::RESIZE) return false;
osg::Matrix::value_type w = gea.getWindowWidth();
osg::Matrix::value_type h = gea.getWindowHeight();
if(_wm->isInvertedY()) _camera->setProjectionMatrix(
createInvertedYOrthoProjectionMatrix(w, h)
);
else _camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0f, w, 0.0f, h));
_wm->setSize(w, h);
_wm->resizeAllWindows();
return true;
}
}

524
src/osgWidget/Widget.cpp Normal file
View File

@@ -0,0 +1,524 @@
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
// $Id: Widget.cpp 64 2008-06-30 21:32:00Z cubicool $
#include <osg/io_utils>
#include <osg/Math>
#include <osg/BlendFunc>
#include <osg/TexMat>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgWidget/WindowManager>
// Don't use these macros! :) They're simply for internal optimization!
#define MACRO_WIDGET_X(v) (*v)[LL].x()
#define MACRO_WIDGET_Y(v) (*v)[LL].y()
#define MACRO_WIDGET_W(v) (*v)[LR].x() - (*v)[LL].x()
#define MACRO_WIDGET_H(v) (*v)[UL].y() - (*v)[LL].y()
namespace osgWidget {
osg::ref_ptr<PointArray> Widget::_norms;
Widget::Widget(const std::string& name, point_type w, point_type h):
_parent (0),
_index (0),
_layer (LAYER_LOW),
_padLeft (0.0f),
_padRight (0.0f),
_padTop (0.0f),
_padBottom (0.0f),
_valign (VA_CENTER),
_halign (HA_CENTER),
_coordMode (CM_ABSOLUTE),
_canFill (false),
_canClone (true),
_isManaged (false),
_isStyled (false),
_minWidth (w),
_minHeight (h) {
_name = name.size() ? name : generateRandomName("Widget");
if(!_norms.valid()) {
_norms = new PointArray(1);
(*_norms)[0].set(0.0f, 0.0f, 1.0f);
(*_norms)[0].normalize();
}
TexCoordArray* texs = new TexCoordArray(4);
// Fill our texture coordinates with null stuff for now, since we aren't using them
// until an Image is set at some later point.
std::fill(texs->begin(), texs->end(), osg::Vec2(0.0f, 0.0f));
setUseDisplayList(false);
setDataVariance(osg::Object::DYNAMIC);
setVertexArray(new PointArray(4));
setColorArray(new ColorArray(4));
setNormalArray(_norms.get());
setTexCoordArray(0, texs);
setNormalBinding(osg::Geometry::BIND_OVERALL);
setColorBinding(osg::Geometry::BIND_PER_VERTEX);
addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
setDimensions(0.0f, 0.0f, w, h);
setColor(1.0f, 1.0f, 1.0f, 1.0f);
getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
}
Widget::Widget(const Widget& widget, const osg::CopyOp& co):
osg::Geometry (widget, co),
EventInterface (widget),
StyleInterface (widget),
_parent (0),
_index (0),
_layer (widget._layer),
_padLeft (widget._padLeft),
_padRight (widget._padRight),
_padTop (widget._padTop),
_padBottom (widget._padBottom),
_valign (widget._valign),
_halign (widget._halign),
_coordMode (widget._coordMode),
_canFill (widget._canFill),
_canClone (widget._canClone),
_isManaged (false),
_isStyled (widget._isStyled),
_minWidth (widget._minWidth),
_minHeight (widget._minHeight) {
}
// This takes an integer value and translates it into a value that will be added to
// the parent window's Z value.
point_type Widget::_calculateZ(unsigned int layer) const {
point_type zRange = 0.0f;
if(_parent) zRange = _parent->getZRange();
return (static_cast<point_type>(layer) / static_cast<point_type>(LAYER_TOP + 1)) * zRange;
}
WindowManager* Widget::_getWindowManager() const {
if(!_parent) return 0;
return _parent->getWindowManager();
}
osg::Image* Widget::_getImage() const {
const osg::Texture2D* texture = _texture();
if(texture) return const_cast<osg::Image*>(texture->getImage(0));
return 0;
}
void Widget::managed(WindowManager* wm) {
if(!wm->isInvertedY()) return;
osg::Matrix s = osg::Matrix::scale(1.0f, -1.0f, 1.0f);
osg::Matrix t = osg::Matrix::translate(0.0f, -1.0, 0.0f);
getOrCreateStateSet()->setTextureAttributeAndModes(
0,
new osg::TexMat(t * s),
osg::StateAttribute::ON
);
}
void Widget::setDimensions(point_type x, point_type y, point_type w, point_type h, point_type z) {
if(w != -1.0f && w < _minWidth) {
warn()
<< "Widget [" << _name
<< "] was asked to set it's width to " << w
<< ", but the minimum width is " << _minWidth
<< "." << std::endl
;
w = _minWidth;
}
if(h != -1.0f && h < _minHeight) {
warn()
<< "Widget [" << _name
<< "] was asked to set it's height to " << h
<< ", but the minimum height is " << _minHeight
<< "." << std::endl
;
h = _minHeight;
}
PointArray* verts = _verts();
if(_coordMode == CM_ABSOLUTE) {
// If any of our values are 0, replace them with the current value.
// We could just call getWidth(), etc., but all those dynamic_casts could eventually
// get expensive, so we just use the already-created verts() array directly.
if(x < 0.0f) x = MACRO_WIDGET_X(verts);
if(y < 0.0f) y = MACRO_WIDGET_Y(verts);
if(w < 0.0f) w = MACRO_WIDGET_W(verts);
if(h < 0.0f) h = MACRO_WIDGET_H(verts);
}
else {
if(x < 0.0f) x = _relCoords[0];
if(y < 0.0f) y = _relCoords[1];
if(w < 0.0f) w = _relCoords[2];
if(h < 0.0f) h = _relCoords[3];
}
if(z < 0.0f) z = _calculateZ(_layer);
// Now, we need to determine if the dimensions are actually percentage of the parent's
// size, rather than an absolute values. The Widget must be parented for this to be
// valid, however.
if(_coordMode == CM_RELATIVE) {
XYCoord size;
if(_parent) size = _parent->getSize();
if(x >= 0.0f && x <= 1.0f) {
_relCoords[0] = x;
x = size.x() * x;
}
if(y >= 0.0f && y <= 1.0f) {
_relCoords[1] = y;
y = size.y() * y;
}
if(w >= 0.0f && w <= 1.0f) {
_relCoords[2] = w;
w = size.x() * w;
}
if(h >= 0.0f && h <= 1.0f) {
_relCoords[3] = h;
h = size.y() * h;
}
}
(*verts)[LL].set(x, y, z);
(*verts)[LR].set(x + w, y, z);
(*verts)[UR].set(x + w, y + h, z);
(*verts)[UL].set(x, y + h, z);
}
void Widget::setColor(color_type r, color_type g, color_type b, color_type a, POINT p) {
ColorArray* cols = _cols();
if(p == ALL_POINTS) {
(*cols)[LL].set(r, g, b, a);
(*cols)[LR].set(r, g, b, a);
(*cols)[UR].set(r, g, b, a);
(*cols)[UL].set(r, g, b, a);
}
else (*cols)[convertPoint(p)].set(r, g, b, a);
}
void Widget::addColor(color_type r, color_type g, color_type b, color_type a, POINT p) {
ColorArray* cols = _cols();
if(p == ALL_POINTS) {
(*cols)[LL] += Color(r, g, b, a);
(*cols)[LR] += Color(r, g, b, a);
(*cols)[UR] += Color(r, g, b, a);
(*cols)[UL] += Color(r, g, b, a);
}
else (*cols)[convertPoint(p)] += Color(r, g, b, a);
}
void Widget::setTexCoord(texcoord_type tx, texcoord_type ty, POINT p) {
TexCoordArray* texs = _texs();
if(p == ALL_POINTS) {
(*texs)[LL].set(tx, ty);
(*texs)[LR].set(tx, ty);
(*texs)[UR].set(tx, ty);
(*texs)[UL].set(tx, ty);
}
else (*texs)[convertPoint(p)].set(tx, ty);
}
void Widget::setTexCoordRegion(point_type x, point_type y, point_type w, point_type h) {
osg::Image* image = _image();
if(!image) return;
point_type tw = image->s();
point_type th = image->t();
TexCoordArray* texs = _texs();
// Set the LOWER_LEFT point.
XYCoord t(x / tw, y / tw);
(*texs)[UL] = t;
// Set the LOWER_RIGHT point.
t += XYCoord(w / tw, 0.0f);
(*texs)[UR] = t;
// Set the UPPER_RIGHT point.
t += XYCoord(0.0f, h / th);
(*texs)[LR] = t;
// Set the UPPER_LEFT point.
t += XYCoord(-(w / tw), 0.0f);
(*texs)[LL] = t;
}
void Widget::setTexCoordWrapHorizontal() {
osg::Image* image = _image();
osg::Texture2D* texture = _texture();
if(!image || !texture || image->s() == 0.0f) return;
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
setTexCoord(getWidth() / image->s(), 0.0f, LOWER_RIGHT);
setTexCoord(getWidth() / image->s(), 1.0f, UPPER_RIGHT);
}
void Widget::setTexCoordWrapVertical() {
osg::Image* image = _image();
osg::Texture2D* texture = _texture();
if(!image || !texture || image->t() == 0.0f) return;
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
setTexCoord(0.0f, getHeight() / image->t(), UPPER_LEFT);
setTexCoord(1.0f, getHeight() / image->t(), UPPER_RIGHT);
}
XYCoord Widget::localXY(double _x, double _y) const {
if(!_parent) return XYCoord(_x, _y);
return _parent->localXY(_x, _y) - getOrigin();
}
bool Widget::setImage(osg::Image* image, bool setTexCoords) {
if(!image) {
warn() << "Widget [" << _name << "] cannot use a NULL image." << std::endl;
return false;
}
osg::Texture2D* texture = new osg::Texture2D();
texture->setDataVariance(osg::Object::DYNAMIC);
texture->setImage(0, image);
getOrCreateStateSet()->setTextureAttributeAndModes(
0,
texture,
osg::StateAttribute::ON
);
if(setTexCoords) {
setTexCoord(0.0f, 0.0f, LOWER_LEFT);
setTexCoord(1.0f, 0.0f, LOWER_RIGHT);
setTexCoord(1.0f, 1.0f, UPPER_RIGHT);
setTexCoord(0.0f, 1.0f, UPPER_LEFT);
}
return true;
}
bool Widget::setImage(const std::string& filePath, bool setTexCoords) {
if(!osgDB::findDataFile(filePath).size()) {
warn()
<< "Widget [" << _name
<< "] cannot find file " << filePath
<< " to set as it's Image." << std::endl
;
return false;
}
return setImage(osgDB::readImageFile(filePath), setTexCoords);
}
void Widget::setPadding(point_type pad) {
_padLeft = _padRight = _padTop = _padBottom = pad;
}
void Widget::addX(point_type x) {
if(_coordMode == CM_ABSOLUTE) setDimensions(MACRO_WIDGET_X(_verts()) + x);
else setDimensions(_relCoords[0] + x);
}
void Widget::addY(point_type y) {
if(_coordMode == CM_ABSOLUTE) setDimensions(-1.0f, MACRO_WIDGET_Y(_verts()) + y);
else setDimensions(-1.0f, _relCoords[1] + y);
}
void Widget::addWidth(point_type w) {
if(_coordMode == CM_ABSOLUTE) setDimensions(-1.0f, -1.0f, MACRO_WIDGET_W(_verts()) + w);
else setDimensions(-1.0f, -1.0f, _relCoords[2] + w);
}
void Widget::addHeight(point_type h) {
if(_coordMode == CM_ABSOLUTE) setDimensions(
-1.0f,
-1.0f,
-1.0f,
MACRO_WIDGET_H(_verts()) + h
);
else setDimensions(-1.0f, -1.0f, -1.0f, _relCoords[3] + h);
}
void Widget::addOrigin(point_type x, point_type y) {
if(_coordMode == CM_ABSOLUTE) {
PointArray* verts = _verts();
setDimensions(
MACRO_WIDGET_X(verts) + x,
MACRO_WIDGET_Y(verts) + y
);
}
else setDimensions(_relCoords[0] + x, _relCoords[1] + y);
}
void Widget::addSize(point_type w, point_type h) {
if(_coordMode == CM_ABSOLUTE) {
PointArray* verts = _verts();
setDimensions(
-1.0f,
-1.0f,
MACRO_WIDGET_W(verts) + w,
MACRO_WIDGET_H(verts) + h
);
}
else setDimensions(-1.0f, -1.0f, _relCoords[2] + w, _relCoords[3] + h);
}
point_type Widget::getWidth() const {
const PointArray* verts = _verts();
return MACRO_WIDGET_W(verts);
}
point_type Widget::getHeight() const {
const PointArray* verts = _verts();
return MACRO_WIDGET_H(verts);
}
point_type Widget::getX() const {
return MACRO_WIDGET_X(_verts());
}
point_type Widget::getY() const {
return MACRO_WIDGET_Y(_verts());
}
point_type Widget::getZ() const {
return (*_verts())[LL].z();
}
point_type Widget::getPadHorizontal() const {
return _padLeft + _padRight;
}
point_type Widget::getPadVertical() const {
return _padTop + _padBottom;
}
const Point& Widget::getPoint(POINT p) const {
POINT point = p;
if(p == ALL_POINTS) point = UPPER_LEFT;
return (*_verts())[convertPoint(point)];
}
const Color& Widget::getColor(POINT p) const {
POINT point = p;
if(p == ALL_POINTS) point = UPPER_LEFT;
return (*_cols())[convertPoint(point)];
}
const TexCoord& Widget::getTexCoord(POINT p) const {
POINT point = p;
if(p == ALL_POINTS) point = UPPER_LEFT;
return (*_texs())[convertPoint(point)];
}
// This converts our points back and forth depding on whether or not we're in an
// inverted-Y WindowManager.
Widget::POINT Widget::convertPoint(POINT p) const {
const WindowManager* wm = getWindowManager();
if(!wm || !wm->isInvertedY()) return p;
if(p == UPPER_LEFT) return LOWER_LEFT;
else if(p == UPPER_RIGHT) return LOWER_RIGHT;
else if(p == LOWER_LEFT) return UPPER_LEFT;
else if(p == LOWER_RIGHT) return UPPER_RIGHT;
else return p;
}
Color Widget::getImageColorAtXY(point_type x, point_type y) const {
const osg::Image* image = _image();
if(!image) return Color();
const TexCoordArray* texs = _texs();
/*
How do we do this? First we need to make sure our right side is larger
than our left side and that the top side is larger the bottom; otherwise,
they're using strange tex coords.
Then, we find the percent area being used in both dimensions. We multiply
the XY values by those ratios and then add those values to the "offsets."
*/
point_type width = fabs((*texs)[LR].x() - (*texs)[LL].x());
point_type height = fabs((*texs)[LR].y() - (*texs)[UR].y());
point_type X = ((x / getWidth()) * width) + (*texs)[LL].x();
point_type Y = (((getHeight() - y) / getHeight()) * height) + (*texs)[UR].y();
return image->getColor(TexCoord(X, Y));
}
bool Widget::isPaddingUniform() const {
return
_padLeft == _padRight &&
_padLeft == _padTop &&
_padLeft == _padBottom
;
}
}

959
src/osgWidget/Window.cpp Normal file
View File

@@ -0,0 +1,959 @@
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
// $Id: Window.cpp 66 2008-07-14 21:54:09Z cubicool $
#include <algorithm>
#include <osgGA/GUIEventAdapter>
#include <osgWidget/WindowManager>
namespace osgWidget {
bool callbackWindowMove(Event& ev) {
if(!ev.getWindow() || !ev.getWindowManager()->isLeftMouseButtonDown()) return false;
ev.getWindow()->addOrigin(ev.x, ev.y);
ev.getWindow()->update();
return true;
}
bool callbackWindowRotate(Event& ev) {
if(!ev.getWindow() || !ev.getWindowManager()->isRightMouseButtonDown()) return false;
ev.getWindow()->addRotate(ev.y);
ev.getWindow()->update();
return true;
}
bool callbackWindowScale(Event& ev) {
if(!ev.getWindow() || !ev.getWindowManager()->isMiddleMouseButtonDown()) return false;
ev.getWindow()->addScale(ev.y);
ev.getWindow()->update();
return true;
}
bool callbackWindowTabFocus(Event& ev) {
if(!ev.getWindow() || ev.key != osgGA::GUIEventAdapter::KEY_Tab) return false;
return ev.getWindow()->setNextFocusable();
}
Window::EmbeddedWindow::EmbeddedWindow(const std::string& name, point_type w, point_type h):
Widget(name, w, h) {
}
Window::EmbeddedWindow::EmbeddedWindow(const EmbeddedWindow& wiw, const osg::CopyOp& co):
Widget(wiw, co) {
// TODO: Get this!
// _window = 0;
}
void Window::EmbeddedWindow::parented(Window* parent) {
if(!_window.valid()) return;
if(!_window->_parent) {
_window->_parent = parent;
// Add this Window to the Window, on the same level as a Window's
// internal Geode. This will require special handling of events!
parent->addChild(_window.get());
}
else warn()
<< "EmbeddedWindow Widget [" << _name
<< "] cannot embed itself in Window [" << _window->getName()
<< "], since it is already a child of [" << _window->_parent->getName()
<< "]" << std::endl
;
}
void Window::EmbeddedWindow::unparented(Window*) {
// TODO: Figure out what's necessary here...
}
void Window::EmbeddedWindow::managed(WindowManager* wm) {
if(!_window.valid()) return;
_window->setNodeMask(wm->getNodeMask());
_window->managed(wm);
}
void Window::EmbeddedWindow::unmanaged(WindowManager* wm) {
_window->unmanaged(wm);
}
void Window::EmbeddedWindow::positioned() {
if(!_window.valid()) return;
point_type x = getX();
point_type y = getY();
point_type w = getWidth();
point_type h = getHeight();
// If the widget is fillable, ask the internal Window to resize itself.
// Whether or not the Window honors this reqest will be up to it.
_window->setOrigin(x, y);
_window->setVisibleArea(0, 0, static_cast<int>(w), static_cast<int>(h));
_window->resize(w, h);
}
bool Window::EmbeddedWindow::setWindow(Window* win) {
if(!win) {
warn()
<< "EmbeddedWindow [" << _name
<< "] attempted to set a NULL Window." << std::endl
;
return false;
}
// TODO: I need to handle there already being a Window here.
_window = win;
_window->resize();
_window->setVisibilityMode(VM_PARTIAL);
if(_parent) parented(_parent);
WindowManager* wm = _getWindowManager();
if(wm) managed(wm);
return true;
}
Window::Window(const std::string& name):
_parent (0),
_wm (0),
_index (0),
_x (0.0f),
_y (0.0f),
_z (0.0f),
_zRange (0.0f),
_strata (STRATA_NONE),
_vis (VM_FULL),
_r (0.0f),
_s (1.0f),
_scaleDenom (100.0f),
_vAnchor (VA_NONE),
_hAnchor (HA_NONE) {
_name = name.size() ? name : generateRandomName("Window");
// TODO: Fix the "bg" name.
osg::Geode* geode = new osg::Geode();
Widget* bg = new Widget(name + "bg", 0.0f, 0.0f);
bg->setLayer(Widget::LAYER_BG);
bg->setColor(0.0f, 0.0f, 0.0f, 0.5f);
_setParented(bg);
geode->addDrawable(bg);
addChild(geode);
setDataVariance(osg::Object::DYNAMIC);
setEventMask(EVENT_ALL);
getOrCreateStateSet()->setAttributeAndModes(
new osg::Scissor(0, 0, 0, 0),
osg::StateAttribute::ON
);
}
Window::Window(const Window& window, const osg::CopyOp& co):
MatrixTransform (window, co),
EventInterface (window),
StyleInterface (window),
_parent (0),
_wm (0),
_x (window._x),
_y (window._y),
_z (window._z),
_zRange (window._zRange),
_strata (window._strata),
_vis (window._vis),
_r (window._r),
_s (window._s),
_scaleDenom (window._scaleDenom),
_width (window._width),
_height (window._height),
_vAnchor (window._vAnchor),
_hAnchor (window._hAnchor),
_visibleArea (window._visibleArea) {
// Construct our vector of Widgets for easier use. :)
// TODO: I almost certainly will need to use the getPosition() thing here eventually
// for things to work 100% properly. For example, some Geodes may contain labels,
// etc. Also, any widget that doesn't support simple addWidget probably won't
// work (Table?)
osg::Geode* geode = _geode();
Widget* bg = dynamic_cast<Widget*>(geode->getDrawable(0));
if(bg) {
_setParented(bg);
// TODO: This is silly...
bg->setName(_name + "bg");
}
for(unsigned int i = 1; i < geode->getNumDrawables(); i++) {
Widget* widget = dynamic_cast<Widget*>(geode->getDrawable(i));
if(!widget || !widget->canClone()) continue;
_setParented(widget);
_objects.push_back(widget);
}
geode->setName(_name);
}
// This is the method by which all Windows are redrawn/resized. Keep in mind that not all
// Windows are required to absolutely honor a resize request, which is why we call the
// _getWidthImplementation() and _getHeightImplementation() functions instead of using the
// values passed in.
bool Window::resize(point_type width, point_type height) {
// First, we query and store what sizes the Window currently is.
_setWidthAndHeight();
// Second, we determine if there is a difference between what the size currently
// is and what the user has requested.
point_type diffWidth = width > 0.0f ? width - _width.cur : 0.0f;
point_type diffHeight = height > 0.0f ? height - _height.cur : 0.0f;
return resizeAdd(diffWidth, diffHeight);
}
bool Window::resizeAdd(point_type diffWidth, point_type diffHeight) {
if(
_width.cur + diffWidth < _width.min ||
_height.cur + diffHeight < _height.min
) {
warn()
<< "Window [" << _name << "] can't call resizeAdd() with the "
<< "values " << diffWidth << " and " << diffHeight << std::endl
;
return false;
}
// Now we initiate the resize, which may or may not succeed.
_resizeImplementation(diffWidth, diffHeight);
// Inform each widget that it has been positioned.
for(Iterator i = begin(); i != end(); i++) if(i->valid()) {
i->get()->dirtyBound();
i->get()->setDimensions();
i->get()->positioned();
}
_setWidthAndHeight();
Widget* bg = _bg();
bg->setSize(_width.cur, _height.cur);
bg->dirtyBound();
bg->positioned();
update();
return true;
}
bool Window::resizePercent(point_type width, point_type height) {
if(!_parent && !_wm) {
warn()
<< "Window [" << _name
<< "] cannot resizePercent without being managed or parented."
<< std::endl
;
return false;
}
if(!_parent) return resize(
_wm->getWidth() * (width / 100.0f),
_wm->getHeight() * (height / 100.0f)
);
else return resize(
_parent->getWidth() * (width / 100.0f),
_parent->getHeight() * (height / 100.0f)
);
}
void Window::update() {
// Update all embedded children; the zRange values continue to decrease in precision
// as you add more and more embedded Windows.
WindowList wl;
getEmbeddedList(wl);
// Each child Window gets half the zRange of it's parent Window. This means the more
// you embed Windows into other Windows, the less depth precision you're going to have.
for(WindowList::iterator w = wl.begin(); w != wl.end(); w++) {
Window* win = w->get();
win->_z = _zRange / 2.0f;
win->_zRange = _zRange / 2.0f;
win->update();
}
matrix_type x = _x;
matrix_type y = _y;
XYCoord xy = getAbsoluteOrigin();
// We only honor ANCHOR requests on topmost Windows, not embedded ones.
if((_vAnchor != VA_NONE || _hAnchor != HA_NONE) && !_parent && _wm) {
if(_vAnchor == VA_TOP) y = 0.0f;
else if(_vAnchor == VA_CENTER) y = osg::round(_wm->getHeight() / 2.0f);
else if(_vAnchor == VA_BOTTOM) y = _wm->getHeight() - _height.cur;
if(_hAnchor == HA_LEFT) x = 0.0f;
else if(_hAnchor == HA_CENTER) x = osg::round(_wm->getWidth() / 2.0f);
else if(_hAnchor == HA_RIGHT) x = _wm->getWidth() - _width.cur + _visibleArea[2];
xy.set(x, y);
}
// Update the Window itself, setting it's matrix according to translate, rotate, and
// scale values.
osg::Matrix r = osg::Matrix::rotate(
osg::DegreesToRadians(_r),
osg::Vec3d(0.0f, 0.0f, 1.0f)
);
osg::Matrix s = osg::Matrix::scale(_s, _s, 1.0f);
osg::Matrix t = osg::Matrix::translate(x - _visibleArea[0], y - _visibleArea[1], _z);
setMatrix(r * s * t);
// We can't do proper scissoring until we have access to our parent WindowManager.
if(_wm) {
int x = static_cast<int>(xy.x());
int y = static_cast<int>(xy.y());
int w = static_cast<int>(_width.cur);
int h = static_cast<int>(_height.cur);
int wmh = static_cast<int>(_wm->getHeight());
int nx = x;
int ny = y;
int nw = w;
int nh = h;
// This sets the Scissor area to the full size of the Window.
if(_vis == VM_FULL && _wm->isInvertedY()) ny = wmh - h - y;
// This sets the Scissor area to some offset defined by the user.
else if(_vis == VM_PARTIAL) {
if(_wm->isInvertedY()) ny = wmh - y - static_cast<int>(_visibleArea[3]);
// else ny = static_cast<int>(_visibleArea[3]);
nw = static_cast<int>(_visibleArea[2]);
nh = static_cast<int>(_visibleArea[3]);
}
// Otherwise, use the size of the WindowManager itself.
else {
nx = 0;
ny = 0;
nw = static_cast<int>(_wm->getWidth());
nh = wmh;
}
_scissor()->setScissor(nx, ny, nw, nh);
}
}
void Window::_setWidthAndHeightUnknownSizeError(const std::string& size, point_type val) {
warn()
<< "Window [" << _name << "] doesn't know its " << size
<< " (" << val << ")." << std::endl
;
}
void Window::_setWidthAndHeightNotPAError(const std::string& size, point_type val) {
warn()
<< "Window [" << _name
<< "] should be pixel-aligned, but a remainder was detected for it's "
<< size << " (" << val << ")." << std::endl
;
}
// Since there is so much error-checking associated with setting the width and height properly
// of a Window, this function attempts to abstract some of that tedium.
void Window::_setWidthAndHeight() {
_width = _getWidthImplementation();
_height = _getHeightImplementation();
if(_width.cur < 0.0f) _setWidthAndHeightUnknownSizeError("current width", _width.cur);
if(_width.min < 0.0f) _setWidthAndHeightUnknownSizeError("minimum width", _width.min);
if(_height.cur < 0.0f) _setWidthAndHeightUnknownSizeError("current height", _height.cur);
if(_height.min < 0.0f) _setWidthAndHeightUnknownSizeError("minimum height", _height.min);
if(hasDecimal(_width.cur)) _setWidthAndHeightNotPAError("current width", _width.cur);
if(hasDecimal(_width.min)) _setWidthAndHeightNotPAError("minimum width", _width.min);
if(hasDecimal(_height.cur)) _setWidthAndHeightNotPAError("current height", _height.cur);
if(hasDecimal(_height.min)) _setWidthAndHeightNotPAError("minimum height", _height.min);
}
void Window::_removeFromGeode(Widget* widget) {
if(!widget) return;
widget->_index = -1;
_setParented(widget, true);
_geode()->removeDrawable(widget);
}
// This is a somewhat complicated function designed to only be called by derived classes,
// allowing them to insert Widgets (which can be added to the Window in any way the derived
// class sees fit) into the REAL internal _objects container.
// TODO: This doesn't handle insertion properly!!!
bool Window::_setWidget(Widget* widget, int index) {
if(!widget) {
warn() << "Window [" << _name << "] called addWidget with NULL." << std::endl;
return false;
}
if(widget->_parent) {
warn()
<< "Window [" << _name
<< "] attempted to parent Widget [" << widget->getName()
<< "], which is already parented by [" << widget->_parent->getName()
<< "]." << std::endl
;
return false;
}
if(index >= 0 && index >= static_cast<int>(size())) {
warn()
<< "Window [" << _name
<< "] attempted to manually insert the Widget [" << widget->getName()
<< "] at position " << index
<< ", but there is not enough space available."
<< std::endl
;
return false;
}
// If we're just appending another widget...
if(index < 0) _objects.push_back(widget);
// Otherwise, we're inserting and need to call removeWidget on the old
// one (if valid)...
else {
if(_objects[index].valid()) _removeFromGeode(_objects[index].get());
_objects[index] = widget;
}
osg::Geode* geode = _geode();
widget->_index = geode->getNumDrawables();
geode->addDrawable(widget);
_setParented(widget);
_setManaged(widget);
_setStyled(widget);
// We make sure and resize after every added Widget. This ensures the most
// accurate geometry...
resize();
return true;
}
bool Window::_setVisible(bool visible) {
if(!_wm) return false;
_wm->setValue(_index, visible);
return true;
}
void Window::_setFocused(Widget* widget) {
if(widget && _wm) {
Event ev(_wm);
ev._window = this;
if(_focused.valid()) {
ev._widget = _focused.get();
_focused->callMethodAndCallbacks(ev.makeType(EVENT_UNFOCUS));
}
_focused = widget;
ev._widget = widget;
_focused->callMethodAndCallbacks(ev.makeType(EVENT_FOCUS));
}
}
void Window::_setStyled(Widget* widget) {
if(!widget || !_wm) return;
if(!widget->_isStyled) return;
widget->_isStyled = true;
_wm->getStyleManager()->applyStyles(widget);
}
void Window::_setParented(Widget* widget, bool setUnparented) {
if(!widget) return;
if(!setUnparented) {
widget->_parent = this;
widget->parented(this);
}
else {
widget->_parent = 0;
widget->unparented(this);
}
}
void Window::_setManaged(Widget* widget, bool setUnmanaged) {
if(!widget || !_wm) return;
// Tell the widget it's managed if it isn't already...
if(!setUnmanaged) {
if(widget->_isManaged) return;
widget->_isManaged = true;
widget->managed(_wm);
}
// Otherwise, make sure it IS managed and tell it that it no longer will be. :)
else {
if(!widget->_isManaged) return;
widget->_isManaged = false;
widget->unmanaged(_wm);
}
}
Widget* Window::_getBackground() const {
const osg::Geode* geode = _geode();
// lol...
if(geode) return dynamic_cast<Widget*>(const_cast<osg::Drawable*>(geode->getDrawable(0)));
return 0;
}
Window* Window::_getTopmostParent() const {
WindowList windowList;
getParentList(windowList);
return windowList.back().get();
}
// This will position a widget based on the amount of width and height it has
// to fill. The x/y values should already be set, since we will be adding here.
// However, the width and height can be anything and will be adjusted accordingly.
void Window::_positionWidget(Widget* widget, point_type width, point_type height) {
point_type w = widget->getWidth();
point_type h = widget->getHeight();
point_type pl = widget->getPadLeft();
point_type pr = widget->getPadRight();
point_type pt = widget->getPadTop();
point_type pb = widget->getPadBottom();
if(widget->canFill()) {
point_type nw = osg::round(width - pr - pl);
point_type nh = osg::round(height - pt - pb);
widget->addOrigin(pl, pb);
if(w != nw) widget->setWidth(nw);
if(h != nh) widget->setHeight(nh);
return;
}
point_type ha = osg::round((width - w - pl - pr) / 2.0f);
point_type va = osg::round((height - h - pt - pb) / 2.0f);
// Handle HORIZONTAL alignment.
if(widget->getAlignHorizontal() == Widget::HA_LEFT) widget->addX(pl);
else if(widget->getAlignHorizontal() == Widget::HA_RIGHT) widget->addX(width - w - pr);
else widget->addX(ha + pl);
// Handle VERTICAL alignment.
if(widget->getAlignVertical() == Widget::VA_BOTTOM) widget->addY(height - h - pt);
else if(widget->getAlignVertical() == Widget::VA_TOP) widget->addY(pb);
else widget->addY(va + pb);
}
bool Window::isVisible() const {
if(!_wm) return false;
return _wm->getValue(_index);
}
bool Window::isXYWithinVisible(float x, float y) const {
return
(x >= _visibleArea[0] && x <= (_visibleArea[0] + _visibleArea[2])) &&
(y >= _visibleArea[1] && y <= (_visibleArea[1] + _visibleArea[3]))
;
}
void Window::setVisibleArea(int x, int y, int w, int h) {
_visibleArea[0] = x;
_visibleArea[1] = y;
_visibleArea[2] = w;
_visibleArea[3] = h;
}
void Window::addVisibleArea(int x, int y, int w, int h) {
_visibleArea[0] += x;
_visibleArea[1] += y;
_visibleArea[2] += w;
_visibleArea[3] += h;
}
bool Window::setFocused(const Widget* widget) {
// TODO: I've turned on the warn() here, but perhaps I shouldn't? I need to define
// the conditions under which it's okay to call setFocus() with a NULL widget.
if(!widget) {
warn() << "Window [" << _name << "] can't focus a NULL Widget." << std::endl;
return false;
}
ConstIterator i = std::find(begin(), end(), widget);
if(i == end()) {
warn()
<< "Window [" << _name
<< "] couldn't find the Widget [" << widget->getName()
<< "] in it's object list." << std::endl
;
return false;
}
_setFocused(i->get());
return true;
}
bool Window::setFocused(const std::string& name) {
Widget* w = getByName(name);
if(!w) {
warn()
<< "Window [" << _name
<< "] couldn't find a Widget named [" << name
<< "] to set as it's focus." << std::endl
;
return false;
}
_setFocused(w);
return true;
}
bool Window::setFirstFocusable() {
WidgetList focusList;
if(getFocusList(focusList)) {
_setFocused(focusList.front().get());
return true;
}
return false;
}
bool Window::setNextFocusable() {
WidgetList focusList;
if(!getFocusList(focusList)) return false;
WidgetList::iterator w = focusList.begin();
// TODO: This needs to be a more complicated object, since the focus may be
// in a child Window instead of a Widget.
unsigned int focusedIndex = 0;
for(unsigned int i = 0; w != focusList.end(); w++, i++) if(*w == _focused) {
focusedIndex = i;
break;
}
if(focusedIndex < focusList.size() - 1) _setFocused((++w)->get());
else _setFocused(focusList.front().get());
return true;
}
XYCoord Window::localXY(double absx, double absy) const {
XYCoord xy = getAbsoluteOrigin();
double x = absx - xy.x();
double y = absy - xy.y();
if(_wm && _wm->isInvertedY()) y = (_wm->getHeight() - absy) - xy.y();
return XYCoord(x + _visibleArea[0], y + _visibleArea[1]);
}
XYCoord Window::getAbsoluteOrigin() const {
XYCoord xy(0, 0);
WindowList windowList;
getParentList(windowList);
for(WindowList::iterator i = windowList.begin(); i != windowList.end(); i++) {
if(!i->valid()) continue;
xy.x() += static_cast<int>(i->get()->getX());
xy.y() += static_cast<int>(i->get()->getY());
}
return xy;
}
Window::EmbeddedWindow* Window::embed() {
EmbeddedWindow* ew = new EmbeddedWindow(_name + "Embedded", getWidth(), getHeight());
ew->setWindow(this);
ew->setSize(getWidth(), getHeight());
ew->setMinimumSize(getMinWidth(), getMinHeight());
ew->setCanFill(true);
return ew;
}
bool Window::getFocusList(WidgetList& wl) const {
for(ConstIterator i = begin(); i != end(); i++) if(i->valid()) {
EmbeddedWindow* ew = dynamic_cast<EmbeddedWindow*>(i->get());
if(!ew) {
if(i->get()->canFocus()) wl.push_back(i->get());
}
else {
if(ew->getWindow()) ew->getWindow()->getFocusList(wl);
}
}
return wl.size() != 0;
}
bool Window::getEmbeddedList(WindowList& wl) const {
for(ConstIterator i = begin(); i != end(); i++) if(i->valid()) {
EmbeddedWindow* ew = dynamic_cast<EmbeddedWindow*>(i->get());
if(!ew || !ew->getWindow()) continue;
wl.push_back(ew->getWindow());
}
return wl.size() != 0;
}
void Window::getParentList(WindowList& wl) const {
const Window* current = this;
while(current) {
wl.push_back(const_cast<Window*>(current));
if(current->_parent) current = current->_parent;
else current = 0;
}
}
void Window::managed(WindowManager* wm) {
_wm = wm;
for(Iterator i = begin(); i != end(); i++) {
_setManaged(i->get());
_setStyled(i->get());
}
setFirstFocusable();
resize();
update();
}
void Window::unmanaged(WindowManager* wm) {
for(Iterator i = begin(); i != end(); i++) _setManaged(i->get(), true);
_wm = 0;
}
bool Window::addWidget(Widget* widget) {
return _setWidget(widget);
}
bool Window::insertWidget(Widget* widget, unsigned int pos) {
return _setWidget(widget, pos);
}
bool Window::removeWidget(Widget* widget) {
if(!widget) return false;
if(_remove(widget)) {
_removeFromGeode(widget);
resize();
return true;
}
return false;
}
bool Window::replaceWidget(Widget* oldWidget, Widget* newWidget) {
return false;
}
unsigned int Window::addDrawableAndGetIndex(osg::Drawable* drawable) {
osg::Geode* geode = _geode();
if(geode->addDrawable(drawable)) return geode->getDrawableIndex(drawable);
// 0 is a valid error return code here, since our background widget should be
// the first child.
return 0;
}
// All of the subsequent functions are very boring and uninteresting, although hopefully
// self-explanatory. They simply wrap calls to _compare<>() with the proper templates, and
// forward the optional iteration ranges...
point_type Window::_getMinWidgetWidth(int begin, int end, int add) const {
return _compare<Less>(&Widget::getWidth, begin, end, add);
}
point_type Window::_getMinWidgetHeight(int begin, int end, int add) const {
return _compare<Less>(&Widget::getHeight, begin, end, add);
}
point_type Window::_getMaxWidgetWidth(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getWidth, begin, end, add);
}
point_type Window::_getMaxWidgetHeight(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getHeight, begin, end, add);
}
point_type Window::_getMinWidgetMinWidth(int begin, int end, int add) const {
return _compare<Less>(&Widget::getMinWidth, begin, end, add);
}
point_type Window::_getMinWidgetMinHeight(int begin, int end, int add) const {
return _compare<Less>(&Widget::getMinHeight, begin, end, add);
}
point_type Window::_getMaxWidgetMinWidth(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getMinWidth, begin, end, add);
}
point_type Window::_getMaxWidgetMinHeight(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getMinHeight, begin, end, add);
}
point_type Window::_getMinWidgetWidthTotal(int begin, int end, int add) const {
return _compare<Less>(&Widget::getWidthTotal, begin, end, add);
}
point_type Window::_getMinWidgetHeightTotal(int begin, int end, int add) const {
return _compare<Less>(&Widget::getHeightTotal, begin, end, add);
}
point_type Window::_getMaxWidgetWidthTotal(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getWidthTotal, begin, end, add);
}
point_type Window::_getMaxWidgetHeightTotal(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getHeightTotal, begin, end, add);
}
point_type Window::_getMinWidgetMinWidthTotal(int begin, int end, int add) const {
return _compare<Less>(&Widget::getMinWidthTotal, begin, end, add);
}
point_type Window::_getMinWidgetMinHeightTotal(int begin, int end, int add) const {
return _compare<Less>(&Widget::getMinHeightTotal, begin, end, add);
}
point_type Window::_getMaxWidgetMinWidthTotal(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getMinWidthTotal, begin, end, add);
}
point_type Window::_getMaxWidgetMinHeightTotal(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getMinHeightTotal, begin, end, add);
}
point_type Window::_getMinWidgetPadHorizontal(int begin, int end, int add) const {
return _compare<Less>(&Widget::getPadHorizontal, begin, end, add);
}
point_type Window::_getMinWidgetPadVertical(int begin, int end, int add) const {
return _compare<Less>(&Widget::getPadVertical, begin, end, add);
}
point_type Window::_getMaxWidgetPadHorizontal(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getPadHorizontal, begin, end, add);
}
point_type Window::_getMaxWidgetPadVertical(int begin, int end, int add) const {
return _compare<Greater>(&Widget::getPadVertical, begin, end, add);
}
point_type Window::_getNumFill(int begin, int end, int add) const {
return _accumulate<Plus>(&Widget::getFillAsNumeric, begin, end, add);
}
Window::Sizes Window::_getWidthImplementation() const {
osg::BoundingBox bb = getGeode()->getBoundingBox();
point_type w = osg::round(bb.xMax() - bb.xMin());
return Sizes(w, w);
}
Window::Sizes Window::_getHeightImplementation() const {
osg::BoundingBox bb = getGeode()->getBoundingBox();
point_type h = osg::round(bb.yMax() - bb.yMin());
return Sizes(h, h);
}
}

View File

@@ -0,0 +1,587 @@
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
// $Id: WindowManager.cpp 66 2008-07-14 21:54:09Z cubicool $
#include <iostream>
#include <algorithm>
#include <osg/io_utils>
#include <osgWidget/Types>
#include <osgWidget/Util>
#include <osgWidget/WindowManager>
#include <osgWidget/Lua>
#include <osgWidget/Python>
#include <osgWidget/Box>
#include <osgWidget/Label>
namespace osgWidget {
WindowManager::WindowManager(
osgViewer::View* view,
point_type width,
point_type height,
unsigned int nodeMask,
unsigned int flags
):
_width (width),
_height (height),
_zNear (0.0f),
_zFar (-1.0f),
_numForeground (0.0f),
_numBackground (0.0f),
_flags (flags),
_nodeMask (nodeMask),
_view (view),
_lastX (0.0f),
_lastY (0.0f),
_lastEvent (0),
_lastPush (0),
_lastVertical (PD_NONE),
_lastHorizontal (PD_NONE),
_focusMode (PFM_FOCUS),
_leftDown (false),
_middleDown (false),
_rightDown (false),
_scrolling (osgGA::GUIEventAdapter::SCROLL_NONE),
_styleManager (new StyleManager()) {
_name = generateRandomName("WindowManager");
if(_flags & WM_USE_LUA) {
_lua = new LuaEngine(this);
if(!_lua->initialize()) warn() << "Error creating LuaEngine." << std::endl;
}
if(_flags & WM_USE_PYTHON) {
_python = new PythonEngine(this);
if(!_python->initialize()) warn() << "Error creating PythonEngine." << std::endl;
}
// Setup our picking debug (is debug the right word here?) Window...
if(_flags & WM_PICK_DEBUG) {
_pickWindow = new Box("PickWindow", Box::VERTICAL);
Label* label = new Label("PickLabel");
label->setFontSize(13);
label->setFontColor(1.0f, 1.0f, 1.0f, 1.0f);
label->setFont("fonts/monospace.ttf");
label->setPadding(5.0f);
label->setCanFill(true);
_pickWindow->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.85f);
_pickWindow->addWidget(label);
_pickWindow->setNodeMask(~_nodeMask);
_pickWindow->removeEventMask(EVENT_MASK_FOCUS);
_pickWindow->setStrata(Window::STRATA_FOREGROUND);
addChild(_pickWindow.get());
_updatePickWindow(0, 0, 0);
}
if(!(_flags & WM_NO_BETA_WARN)) {
Box* box = new Box("BetaWarningBox", Box::VERTICAL);
Label* label = new Label("BetaWarning");
label->setFontSize(15);
label->setFontColor(0.0f, 0.0f, 1.0f, 1.0f);
label->setFont("fonts/arial.ttf");
label->setPadding(5.0f);
label->setCanFill(true);
label->setLabel("This is BETA software! Please see: http://osgwidget.googlecode.com");
box->getBackground()->setColor(1.0f, 0.7f, 0.0f, 1.0f);
box->addWidget(label);
box->setNodeMask(~_nodeMask);
box->removeEventMask(EVENT_MASK_FOCUS);
box->setStrata(Window::STRATA_BACKGROUND);
box->setOrigin(0.0f, 0.0f);
addChild(box);
box->resizePercent(100.0f, 0.0f);
}
}
WindowManager::WindowManager(const WindowManager& wm, const osg::CopyOp& co):
osg::Switch(wm, co) {
}
WindowManager::~WindowManager() {
if(_flags & WM_USE_LUA) _lua->close();
if(_flags & WM_USE_PYTHON) _python->close();
}
void WindowManager::setEventFromInterface(Event& ev, EventInterface* ei) {
Widget* widget = dynamic_cast<Widget*>(ei);
Window* window = dynamic_cast<Window*>(ei);
if(widget) {
ev._window = widget->getParent();
ev._widget = widget;
}
else if(window) ev._window = window;
}
bool WindowManager::_handleMousePushed(float x, float y, bool& down) {
down = true;
Event ev(this, EVENT_MOUSE_PUSH);
WidgetList widgetList;
if(!pickAtXY(x, y, widgetList)) return false;
ev.makeMouse(x, y);
_lastPush = getFirstEventInterface(widgetList, ev);
if(!_lastPush) return false;
bool handled = _lastPush->callMethodAndCallbacks(ev);
if(_focusMode != PFM_SLOPPY) {
if(ev._window) {
Window* topmostWindow = ev._window->getTopmostParent();
setFocused(topmostWindow);
if(ev._widget) topmostWindow->setFocused(ev._widget);
}
// If the user wants to be able to "unfocus" the last Window.
else if(_focusMode == PFM_UNFOCUS) setFocused(0);
}
return handled;
}
bool WindowManager::_handleMouseReleased(float x, float y, bool& down) {
down = false;
// If were were in a drag state, reset our boolean flag.
// if(_lastDrag) _lastDrag = 0;
if(!_lastPush) return false;
// By design, we can only release an EventInterface we previously pressed.
// Whether or not we're ON the EventInterface when the release occurs isn't important.
Event ev(this, EVENT_MOUSE_RELEASE);
setEventFromInterface(ev, _lastPush);
bool handled = _lastPush->callMethodAndCallbacks(ev);
_lastPush = 0;
return handled;
}
void WindowManager::_getPointerXYDiff(float& x, float& y) {
x -= _lastX;
if(isInvertedY()) y = -(y - _lastY);
else y -= _lastY;
}
void WindowManager::_updatePickWindow(const WidgetList* wl, point_type x, point_type y) {
Label* label = dynamic_cast<Label*>(_pickWindow->getByName("PickLabel"));
if(!wl) {
setValue(0, false);
return;
}
setValue(0, true);
std::stringstream ss;
point_type xdiff = x;
point_type ydiff = y;
_getPointerXYDiff(xdiff, ydiff);
ss
<< "At XY Coords: " << x << ", " << _height - y
<< " ( diff " << xdiff << ", " << ydiff << " )"
<< std::endl
;
const Window* parent = wl->back()->getParent();
ss
<< "Window: " << parent->getName()
<< " ( xyz " << parent->getPosition() << " )"
<< " { zRange " << parent->getZRange() << " }"
<< " < size " << parent->getSize() << " >"
<< " EventMask: " << std::hex << parent->getEventMask()
<< std::endl
;
for(WidgetList::const_iterator i = wl->begin(); i != wl->end(); i++) {
Widget* widget = i->get();
ss
<< " - " << widget->getName()
<< " ( xyz " << widget->getPosition() << " )"
<< " [ XYZ " << widget->getPosition() * parent->getMatrix()
<< " ] < size " << widget->getSize() << " >"
<< " EventMask: " << std::hex << widget->getEventMask()
<< std::endl
;
}
label->setLabel(ss.str());
XYCoord size = label->getTextSize();
_pickWindow->resize(size.x() + 10.0f, size.y() + 10.0f);
_pickWindow->setOrigin(5.0f, _height - _pickWindow->getHeight() - 5.0f);
_pickWindow->update();
}
void WindowManager::childInserted(unsigned int i) {
Window* window = dynamic_cast<Window*>(getChild(i));
if(!window) return;
_objects.push_back(window);
window->_index = i;
setFocused(window);
window->setNodeMask(_nodeMask);
window->managed(this);
for(Window::Iterator w = window->begin(); w != window->end(); w++) if(w->valid()) {
_styleManager->applyStyles(w->get());
}
_styleManager->applyStyles(window);
}
void WindowManager::childRemoved(unsigned int start, unsigned int end) {
while(start < end) {
Window* window = getByIndex(start);
if(!window) continue;
if(_remove(window)) {
window->_index = -1;
window->unmanaged(this);
}
start++;
}
}
// This method performs intersection testing at the given XY coords, and returns true if
// any intersections were found. It will break after processing the first pickable Window
// it finds.
bool WindowManager::pickAtXY(float x, float y, WidgetList& wl) {
Intersections intr;
if(_view->computeIntersections(x, y, intr, _nodeMask)) {
// Get the first Window at the XY coordinates; if you want a Window to be
// non-pickable, set the NodeMask to something else.
Window* activeWin = 0;
// Iterate over every picked result and create a list of Widgets that belong
// to that Window.
for(Intersections::iterator i = intr.begin(); i != intr.end(); i++) {
Window* win = dynamic_cast<Window*>(i->nodePath.back()->getParent(0));
// Make sure that our window is valid, and that our pick is within the
// "visible area" of the Window.
if(
(!win || win->getVisibilityMode() == Window::VM_PARTIAL) &&
!win->isPointerXYWithinVisible(x, y)
) continue;
// Set our activeWin, so that we know when we've got all the Widgets
// that belong to it.
if(!activeWin) activeWin = win;
// If we've found a new Widnow, break out!
else if(activeWin != win) break;
Widget* widget = dynamic_cast<Widget*>(i->drawable.get());
if(!widget) continue;
// We need to return a list of every Widget that was picked, so
// that the handler can operate on it accordingly.
else wl.push_back(widget);
}
if(wl.size()) {
// Potentially VERY expensive; only to be used for debugging. :)
if(_flags & WM_PICK_DEBUG) _updatePickWindow(&wl, x, y);
return true;
}
}
if(_flags & WM_PICK_DEBUG) _updatePickWindow(0, x, y);
return false;
}
bool WindowManager::setFocused(Window* window) {
Event ev(this);
ev._window = window;
// Inform the previously focused Window that it is going to be unfocused.
if(_focused.valid()) _focused->callMethodAndCallbacks(ev.makeType(EVENT_UNFOCUS));
_focused = window;
if(!window || !window->canFocus()) return false;
// Build a vector of every Window that is focusable, in the foreground, and in the
// background. All these Windows are handled differently.
Vector focusable;
Vector bg;
Vector fg;
for(ConstIterator i = begin(); i != end(); i++) if(i->valid()) {
Window* w = i->get();
if(w->getStrata() == Window::STRATA_FOREGROUND) fg.push_back(w);
else if(w->getStrata() == Window::STRATA_BACKGROUND) bg.push_back(w);
else focusable.push_back(w);
}
// After this call to sort, the internal objects will be arranged such that the
// previously focused window is the first, followed by all other Windows in
// descending order.
std::sort(focusable.begin(), focusable.end(), WindowZCompare());
// This is the depth range for each Window. Each Window object must be informed of
// the Z space allocated to it so that it can properly arrange it's children. We
// add 2 additional Windows here for anything that should appear in the background
// and foreground areas.
matrix_type zRange = (_zNear - _zFar) / (focusable.size() + 2.0f);
// Our offset for the following for() loop.
unsigned int i = 3;
// Handle all of our focusable Windows.
for(Iterator w = focusable.begin(); w != focusable.end(); w++) {
Window* win = w->get();
// Set our newly focused Window as the topmost element.
if(*w == window) win->_z = -zRange * 2.0f;
// Set the current Z of the remaining Windows and set their zRange so that
// they can update their own children.
else {
win->_z = -zRange * i;
i++;
}
}
// Handled our special BACKGROUND Windows.
for(Iterator w = bg.begin(); w != bg.end(); w++) w->get()->_z = -zRange * i;
// Handle our special FOREGOUND Windows.
for(Iterator w = fg.begin(); w != fg.end(); w++) w->get()->_z = -zRange;
// Update every window, regardless.
for(Iterator w = begin(); w != end(); w++) {
Window* win = w->get();
win->_zRange = zRange;
win->update();
}
_focused->callMethodAndCallbacks(ev.makeType(EVENT_FOCUS));
return true;
}
void WindowManager::setPointerXY(float x, float y) {
float xdiff = x;
float ydiff = y;
_getPointerXYDiff(xdiff, ydiff);
// If ydiff isn't NEAR 0 (floating point booleans aren't 100% reliable, but that
// doesn't matter in our case), assume we have either up or down movement.
if(ydiff != 0.0f) _lastVertical = ydiff > 0.0f ? PD_UP : PD_DOWN;
else _lastVertical = PD_NONE;
// If xdiff isn't 0, assume we have either left or right movement.
if(xdiff != 0.0f) _lastHorizontal = xdiff > 0.0f ? PD_RIGHT : PD_LEFT;
else _lastHorizontal = PD_NONE;
_lastX = x;
_lastY = y;
}
void WindowManager::setStyleManager(StyleManager* sm) {
_styleManager = sm;
for(Iterator i = begin(); i != end(); i++) if(i->valid()) {
Window* window = i->get();
for(Window::Iterator w = window->begin(); w != window->end(); w++) {
if(!w->valid()) continue;
_styleManager->applyStyles(w->get());
}
_styleManager->applyStyles(window);
}
}
void WindowManager::resizeAllWindows(bool visible) {
for(Iterator i = begin(); i != end(); i++) if(i->valid()) {
if(visible && !getValue(i->get()->_index)) continue;
i->get()->resize();
}
}
// This is called by a ViewerEventHandler/MouseHandler (or whatever) as the pointer moves
// around and intersects with objects. It also resets our state data (_widget, _leftDown,
// etc.) The return value of this method is mostly useless.
bool WindowManager::pointerMove(float x, float y) {
WidgetList wl;
Event ev(this);
if(!pickAtXY(x, y, wl)) {
if(_lastEvent) {
setEventFromInterface(ev.makeMouse(x, y, EVENT_MOUSE_LEAVE), _lastEvent);
_lastEvent->callMethodAndCallbacks(ev);
}
if(_focusMode == PFM_SLOPPY) setFocused(0);
_lastEvent = 0;
_leftDown = 0;
_middleDown = 0;
_rightDown = 0;
return false;
}
EventInterface* ei = getFirstEventInterface(wl, ev.makeMouse(x, y, EVENT_MOUSE_OVER));
if(!ei) return false;
if(_lastEvent != ei) {
if(_lastEvent) {
Event evLeave(this);
evLeave.makeMouse(x, y, EVENT_MOUSE_LEAVE);
setEventFromInterface(evLeave, _lastEvent);
_lastEvent->callMethodAndCallbacks(evLeave);
}
_lastEvent = ei;
if(_focusMode == PFM_SLOPPY && ev._window) setFocused(ev._window);
_lastEvent->callMethodAndCallbacks(ev.makeMouse(x, y, EVENT_MOUSE_ENTER));
}
ei->callMethodAndCallbacks(ev.makeMouse(x, y, EVENT_MOUSE_OVER));
return true;
}
bool WindowManager::pointerDrag(float x, float y) {
WidgetList widgetList;
Event ev(this);
float xdiff = x;
float ydiff = y;
_getPointerXYDiff(xdiff, ydiff);
ev.makeMouse(xdiff, ydiff, EVENT_MOUSE_DRAG);
// If we're still in the drag state...
if(_lastPush) {
setEventFromInterface(ev, _lastPush);
return _lastPush->callMethodAndCallbacks(ev);
}
return false;
}
bool WindowManager::mouseScroll(float x, float y) {
WidgetList wl;
if(!pickAtXY(x, y, wl)) return false;
Event ev(this, EVENT_MOUSE_SCROLL);
EventInterface* ei = getFirstEventInterface(wl, ev);
if(!ei) return false;
return ei->callMethodAndCallbacks(ev);
}
// Keypresses only go the focused Window.
bool WindowManager::keyDown(int key, int mask) {
if(_focused.valid()) {
Event ev(this, EVENT_KEY_DOWN);
ev.makeKey(key, mask);
Widget* focusedWidget = _focused->getFocused();
ev._window = _focused.get();
ev._widget = focusedWidget;
bool handled = false;
if(focusedWidget) handled = focusedWidget->callMethodAndCallbacks(ev);
if(!handled) return _focused->callMethodAndCallbacks(ev);
else return true;
}
return false;
}
bool WindowManager::keyUp(int key, int mask) {
return true;
}
// A convenience wrapper for creating a proper orthographic camera using the current
// width and height.
osg::Camera* WindowManager::createParentOrthoCamera() {
osg::Camera* camera = 0;
if(isInvertedY()) camera = createInvertedYOrthoCamera(_width, _height);
else camera = createOrthoCamera(_width, _height);
camera->addChild(this);
return camera;
}
}