#include "gui_mgr.hxx"
#include <Canvas/window.hxx>
+#include <Main/fg_os.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Viewer/CameraGroup.hxx>
osg::Object*,
osg::NodeVisitor* )
{
+ if( ea.getHandled() )
+ return false;
return _gui_mgr->handleEvent(ea);
}
_event_handler( new GUIEventHandler(this) ),
_transform( new osg::MatrixTransform ),
_width(_props, "size[0]"),
- _height(_props, "size[1]")
+ _height(_props, "size[1]"),
+ _resize(canvas::Window::NONE),
+ _last_cursor(MOUSE_CURSOR_NONE),
+ _last_scroll_time(0)
{
_width = _height = -1;
globals->get_renderer()
->getViewer()
- ->addEventHandler( _event_handler );
+ ->getEventHandlers()
+ // GUI is on top of everything so lets install as first event handler
+ .push_front( _event_handler );
}
//------------------------------------------------------------------------------
ea.getWindowY(),
ea.getWindowWidth(),
ea.getWindowHeight() );
- return true;
+ return false; // Let other event handlers also consume resize events
default:
return false;
}
return placements;
}
+/*
+RESIZE AREAS
+============
+
+| || | _ inside corner region (L-shaped part inside margin) both
+|___||_|_ _ _/ directions can be resized (outside only one axis)
+| || | |
+| || |
+| || |_____|__ _
+| || | } margin_neg \
+| ========|== <-- window border |_ area where resize
+| | } margin_pos | can be initiated
+|____________|__/ _/
+|<- corner ->|
+*/
+const float resize_margin_pos = 12;
+const float resize_margin_neg = 2;
+const float resize_corner = 20;
+
//------------------------------------------------------------------------------
bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
{
event->button = ea.getButton();
event->state = ea.getButtonMask();
event->mod = ea.getModKeyMask();
- //event->scroll = ea.getScrollingMotion();
+
+ static simgear::Rect<float> resize_region;
+
+ if( !_resize_window.expired() )
+ {
+ switch( ea.getEventType() )
+ {
+ case osgGA::GUIEventAdapter::RELEASE:
+ _resize_window.lock()->handleResize(canvas::Window::NONE);
+ _resize_window.reset();
+ break;
+ case osgGA::GUIEventAdapter::DRAG:
+ _resize_window.lock()->handleResize(_resize, event->delta);
+ return true;
+ default:
+ return false;
+ }
+ }
canvas::WindowPtr window_at_cursor;
for( int i = _transform->getNumChildren() - 1; i >= 0; --i )
canvas::WindowPtr window =
static_cast<WindowUserData*>(layer->getChild(j)->getUserData())
->window.lock();
+ float margin = window->isResizable() ? resize_margin_pos : 0;
if( window->getRegion().contains( event->getScreenX(),
- event->getScreenY() ) )
+ event->getScreenY(),
+ margin ) )
{
window_at_cursor = window;
break;
break;
}
+ if( window_at_cursor )
+ {
+ const simgear::Rect<float>& reg = window_at_cursor->getRegion();
+
+ if( window_at_cursor->isResizable()
+ && ( ea.getEventType() == osgGA::GUIEventAdapter::MOVE
+ || ea.getEventType() == osgGA::GUIEventAdapter::PUSH
+ || ea.getEventType() == osgGA::GUIEventAdapter::RELEASE
+ )
+ && !reg.contains( event->getScreenX(),
+ event->getScreenY(),
+ -resize_margin_neg ) )
+ {
+ if( !_last_cursor )
+ _last_cursor = fgGetMouseCursor();
+
+ _resize = 0;
+
+ if( event->getScreenX() <= reg.l() + resize_corner )
+ _resize |= canvas::Window::LEFT;
+ else if( event->getScreenX() >= reg.r() - resize_corner )
+ _resize |= canvas::Window::RIGHT;
+
+ if( event->getScreenY() <= reg.t() + resize_corner )
+ _resize |= canvas::Window::TOP;
+ else if( event->getScreenY() >= reg.b() - resize_corner )
+ _resize |= canvas::Window::BOTTOM;
+
+ static const int cursor_mapping[] =
+ {
+ 0, MOUSE_CURSOR_LEFTSIDE, MOUSE_CURSOR_RIGHTSIDE, 0,
+ MOUSE_CURSOR_TOPSIDE, MOUSE_CURSOR_TOPLEFT, MOUSE_CURSOR_TOPRIGHT, 0,
+ MOUSE_CURSOR_BOTTOMSIDE, MOUSE_CURSOR_BOTTOMLEFT, MOUSE_CURSOR_BOTTOMRIGHT,
+ };
+
+ if( !cursor_mapping[_resize] )
+ return false;
+
+ fgSetMouseCursor(cursor_mapping[_resize]);
+
+ if( ea.getEventType() == osgGA::GUIEventAdapter::PUSH )
+ {
+ _resize_window = window_at_cursor;
+ window_at_cursor->doRaise();
+ window_at_cursor->handleResize( _resize | canvas::Window::INIT,
+ event->delta );
+ }
+
+ return true;
+ }
+ }
+
+ if( _last_cursor )
+ {
+ fgSetMouseCursor(_last_cursor);
+ _last_cursor = 0;
+ return true;
+ }
+
canvas::WindowPtr target_window = window_at_cursor;
switch( ea.getEventType() )
{
_last_push = window_at_cursor;
event->type = sc::Event::MOUSE_DOWN;
break;
-// case osgGA::GUIEventAdapter::SCROLL:
-// event->type = sc::Event::SCROLL;
-// break;
+ case osgGA::GUIEventAdapter::SCROLL:
+ switch( ea.getScrollingMotion() )
+ {
+ case osgGA::GUIEventAdapter::SCROLL_UP:
+ event->delta.y() = 1;
+ break;
+ case osgGA::GUIEventAdapter::SCROLL_DOWN:
+ event->delta.y() = -1;
+ break;
+ default:
+ return false;
+ }
+
+ // osg sends two events for every scrolling motion. We don't need
+ // duplicate events, so lets ignore the second event with the same
+ // timestamp.
+ if( _last_scroll_time == ea.getTime() )
+ return true;
+ _last_scroll_time = ea.getTime();
+
+ event->type = sc::Event::WHEEL;
+ break;
case osgGA::GUIEventAdapter::MOVE:
{
canvas::WindowPtr last_mouse_over = _last_mouse_over.lock();
sc::MouseEventPtr move_event( new sc::MouseEvent(*event) );
move_event->type = sc::Event::MOUSE_LEAVE;
- // Let the event position be always relative to the top left window corner
+ // Let the event position be always relative to the top left window
+ // corner
move_event->client_pos.x() -= last_mouse_over->getRegion().x();
move_event->client_pos.y() -= last_mouse_over->getRegion().y();
PropertyBasedElement(node),
_image( simgear::canvas::CanvasPtr(),
node,
- simgear::canvas::Style() )
+ simgear::canvas::Style() ),
+ _resizable(false),
+ _resize_top(node, "resize-top"),
+ _resize_right(node, "resize-right"),
+ _resize_bottom(node, "resize-bottom"),
+ _resize_left(node, "resize-left"),
+ _resize_status(node, "resize-status")
{
_image.removeListener();
//----------------------------------------------------------------------------
void Window::valueChanged(SGPropertyNode * node)
{
- if( node->getParent() == _node && node->getNameString() == "raise-top" )
- doRaise(node);
- else
+ bool handled = false;
+ if( node->getParent() == _node )
+ {
+ handled = true;
+ if( node->getNameString() == "raise-top" )
+ doRaise(node);
+ else if( node->getNameString() == "resize" )
+ _resizable = node->getBoolValue();
+ else
+ handled = false;
+ }
+
+ if( !handled )
_image.valueChanged(node);
}
return _image.getSrcCanvas();
}
+ //----------------------------------------------------------------------------
+ bool Window::isResizable() const
+ {
+ return _resizable;
+ }
+
//----------------------------------------------------------------------------
bool Window::handleMouseEvent(const simgear::canvas::MouseEventPtr& event)
{
return false;
}
+ //----------------------------------------------------------------------------
+ void Window::handleResize(uint8_t mode, const osg::Vec2f& delta)
+ {
+ if( mode == NONE )
+ {
+ _resize_status = 0;
+ return;
+ }
+ else if( mode & INIT )
+ {
+ _resize_top = getRegion().t();
+ _resize_right = getRegion().r();
+ _resize_bottom = getRegion().b();
+ _resize_left = getRegion().l();
+ _resize_status = 1;
+ }
+
+ if( mode & BOTTOM )
+ _resize_bottom += delta.y();
+ else if( mode & TOP )
+ _resize_top += delta.y();
+
+ if( mode & canvas::Window::RIGHT )
+ _resize_right += delta.x();
+ else if( mode & canvas::Window::LEFT )
+ _resize_left += delta.x();
+ }
+
//----------------------------------------------------------------------------
void Window::doRaise(SGPropertyNode* node_raise)
{
- if( !node_raise->getBoolValue() )
+ if( node_raise && !node_raise->getBoolValue() )
return;
BOOST_FOREACH(osg::Group* parent, getGroup()->getParents())
parent->addChild(getGroup());
}
- node_raise->setBoolValue(false);
+ if( node_raise )
+ node_raise->setBoolValue(false);
}
} // namespace canvas