The attached osgWidget source solves three compilation warnings on VC 7.1 on WindowsXP (OSG 2.5.5). BTW the construct is absolutely legal C++, but VC 7.1 has a different idea...
Hope it helps
                           mario

--
Ing. Mario Valle
Data Analysis and Visualization Services         | http://www.cscs.ch/~mvalle
Swiss National Supercomputing Centre (CSCS)      | Tel:  +41 (91) 610.82.60
v. Cantonale Galleria 2, 6928 Manno, Switzerland | Fax:  +41 (91) 610.82.82

// -*-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/VeraMono.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 it = begin(); it != end(); it++) if(it->valid()) {
                Window* w = it->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;
}

}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to