Add window decoration support to Canvas GUI.
canvas::Window now optionally creates a second canvas for showing window decoration. After setting its dimensions with the property "decoration-border" a Nasal based window decorator should add the required elements to the decoration canvas. Using the properties "shadow-radius" and "shadow-inset" a drop shadow can be added to the window.
This commit is contained in:
parent
53c3033135
commit
326ee0c5cf
4 changed files with 193 additions and 19 deletions
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/canvas/CanvasPlacement.hxx>
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
|
||||
#include <osg/BlendFunc>
|
||||
#include <osgViewer/Viewer>
|
||||
|
@ -351,7 +352,7 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
|
|||
continue;
|
||||
|
||||
float margin = window->isResizable() ? resize_margin_pos : 0;
|
||||
if( window->getRegion().contains( event->getScreenX(),
|
||||
if( window->getScreenRegion().contains( event->getScreenX(),
|
||||
event->getScreenY(),
|
||||
margin ) )
|
||||
{
|
||||
|
@ -366,7 +367,7 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
|
|||
|
||||
if( window_at_cursor )
|
||||
{
|
||||
const SGRect<float>& reg = window_at_cursor->getRegion();
|
||||
const SGRect<float>& reg = window_at_cursor->getScreenRegion();
|
||||
|
||||
if( window_at_cursor->isResizable()
|
||||
&& ( ea.getEventType() == osgGA::GUIEventAdapter::MOVE
|
||||
|
@ -459,6 +460,8 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
|
|||
{
|
||||
sc::MouseEventPtr move_event( new sc::MouseEvent(*event) );
|
||||
move_event->type = sc::Event::MOUSE_LEAVE;
|
||||
move_event->client_pos -= toOsg(last_mouse_over->getPosition());
|
||||
move_event->local_pos = move_event->client_pos;
|
||||
|
||||
last_mouse_over->handleMouseEvent(move_event);
|
||||
}
|
||||
|
@ -482,7 +485,11 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
|
|||
}
|
||||
|
||||
if( target_window )
|
||||
{
|
||||
event->client_pos -= toOsg(target_window->getPosition());
|
||||
event->local_pos = event->client_pos;
|
||||
return target_window->handleMouseEvent(event);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -16,11 +16,15 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include "canvas_mgr.hxx"
|
||||
#include "window.hxx"
|
||||
#include <Main/globals.hxx>
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
|
||||
#include <osgGA/GUIEventHandler>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace canvas
|
||||
|
@ -28,9 +32,8 @@ namespace canvas
|
|||
//----------------------------------------------------------------------------
|
||||
Window::Window(SGPropertyNode* node):
|
||||
PropertyBasedElement(node),
|
||||
_image( simgear::canvas::CanvasPtr(),
|
||||
node,
|
||||
simgear::canvas::Style() ),
|
||||
_attributes_dirty(0),
|
||||
_image(simgear::canvas::CanvasPtr(), node),
|
||||
_resizable(false),
|
||||
_capture_events(true),
|
||||
_resize_top(node, "resize-top"),
|
||||
|
@ -41,12 +44,6 @@ namespace canvas
|
|||
{
|
||||
_image.removeListener();
|
||||
|
||||
// TODO probably better remove default position and size
|
||||
node->setFloatValue("x", 50);
|
||||
node->setFloatValue("y", 100);
|
||||
node->setFloatValue("size[0]", 400);
|
||||
node->setFloatValue("size[1]", 300);
|
||||
|
||||
node->setFloatValue("source/right", 1);
|
||||
node->setFloatValue("source/bottom", 1);
|
||||
node->setBoolValue("source/normalized", true);
|
||||
|
@ -55,13 +52,59 @@ namespace canvas
|
|||
//----------------------------------------------------------------------------
|
||||
Window::~Window()
|
||||
{
|
||||
|
||||
if( _canvas_decoration )
|
||||
_canvas_decoration->destroy();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::update(double delta_time_sec)
|
||||
{
|
||||
_image.update(delta_time_sec);
|
||||
|
||||
if( _attributes_dirty & SHADOW )
|
||||
{
|
||||
float radius = get<float>("shadow-radius"),
|
||||
inset = get<float>("shadow-inset"),
|
||||
slice_width = radius + inset;
|
||||
|
||||
if( slice_width <= 1 || _canvas_content.expired() )
|
||||
{
|
||||
if( _image_shadow )
|
||||
{
|
||||
getGroup()->removeChild(_image_shadow->getMatrixTransform());
|
||||
_image_shadow.reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !_image_shadow )
|
||||
{
|
||||
_image_shadow.reset(new simgear::canvas::Image(
|
||||
_canvas_content,
|
||||
_node->getChild("image-shadow", 0, true)
|
||||
));
|
||||
_image_shadow->set<std::string>("file", "gui/images/shadow.png");
|
||||
_image_shadow->set<float>("slice", 7);
|
||||
_image_shadow->set<std::string>("fill", "#000000");
|
||||
getGroup()->insertChild(0, _image_shadow->getMatrixTransform());
|
||||
}
|
||||
|
||||
simgear::canvas::CanvasPtr canvas = _canvas_decoration
|
||||
? _canvas_decoration
|
||||
: _canvas_content.lock();
|
||||
|
||||
_image_shadow->set<float>("slice-width", slice_width);
|
||||
_image_shadow->set<int>("x", -radius);
|
||||
_image_shadow->set<int>("y", -radius);
|
||||
_image_shadow->set<int>("size[0]", canvas->getViewWidth() + 2 * radius);
|
||||
_image_shadow->set<int>("size[1]", canvas->getViewHeight()+ 2 * radius);
|
||||
}
|
||||
|
||||
_attributes_dirty &= ~SHADOW;
|
||||
}
|
||||
|
||||
if( _image_shadow )
|
||||
_image_shadow->update(delta_time_sec);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -71,12 +114,17 @@ namespace canvas
|
|||
if( node->getParent() == _node )
|
||||
{
|
||||
handled = true;
|
||||
if( node->getNameString() == "raise-top" )
|
||||
const std::string& name = node->getNameString();
|
||||
if( name == "raise-top" )
|
||||
doRaise(node);
|
||||
else if( node->getNameString() == "resize" )
|
||||
else if( name == "resize" )
|
||||
_resizable = node->getBoolValue();
|
||||
else if( node->getNameString() == "capture-events" )
|
||||
else if( name == "capture-events" )
|
||||
_capture_events = node->getBoolValue();
|
||||
else if( name == "decoration-border" )
|
||||
parseDecorationBorder(node->getStringValue());
|
||||
else if( boost::starts_with(name, "shadow-") )
|
||||
_attributes_dirty |= SHADOW;
|
||||
else
|
||||
handled = false;
|
||||
}
|
||||
|
@ -85,6 +133,18 @@ namespace canvas
|
|||
_image.valueChanged(node);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
_image.childAdded(parent, child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
_image.childRemoved(parent, child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Group* Window::getGroup()
|
||||
{
|
||||
|
@ -97,9 +157,23 @@ namespace canvas
|
|||
return _image.getRegion();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const SGVec2<float> Window::getPosition() const
|
||||
{
|
||||
const osg::Matrix& m = _image.getMatrixTransform()->getMatrix();
|
||||
return SGVec2<float>( m(3, 0), m(3, 1) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const SGRect<float> Window::getScreenRegion() const
|
||||
{
|
||||
return getPosition() + getRegion();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::setCanvas(simgear::canvas::CanvasPtr canvas)
|
||||
{
|
||||
_canvas_content = canvas;
|
||||
_image.setSrcCanvas(canvas);
|
||||
}
|
||||
|
||||
|
@ -109,6 +183,12 @@ namespace canvas
|
|||
return _image.getSrcCanvas();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
simgear::canvas::CanvasPtr Window::getCanvasDecoration()
|
||||
{
|
||||
return _canvas_decoration;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Window::isVisible() const
|
||||
{
|
||||
|
@ -180,4 +260,67 @@ namespace canvas
|
|||
node_raise->setBoolValue(false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::parseDecorationBorder( const std::string& str )
|
||||
{
|
||||
_decoration_border = simgear::CSSBorder::parse(str);
|
||||
if( _decoration_border.isNone() )
|
||||
{
|
||||
simgear::canvas::CanvasPtr canvas_content = _canvas_content.lock();
|
||||
_image.setSrcCanvas(canvas_content);
|
||||
_image.set<int>("size[0]", canvas_content->getViewWidth());
|
||||
_image.set<int>("size[1]", canvas_content->getViewHeight());
|
||||
|
||||
_image_content.reset();
|
||||
_canvas_decoration->destroy();
|
||||
_canvas_decoration.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
simgear::canvas::CanvasPtr content = _canvas_content.lock();
|
||||
if( !_canvas_decoration )
|
||||
{
|
||||
CanvasMgr* mgr =
|
||||
dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas"));
|
||||
|
||||
if( !mgr )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!");
|
||||
return;
|
||||
}
|
||||
|
||||
_canvas_decoration = mgr->createCanvas("window-decoration");
|
||||
_canvas_decoration->getProps()->setStringValue("background", "rgba(0,0,0,0)");
|
||||
_image.setSrcCanvas(_canvas_decoration);
|
||||
|
||||
// Decoration should be drawn first...
|
||||
_canvas_decoration->createGroup("decoration");
|
||||
|
||||
// ...to allow drawing the actual content on top of the decoration
|
||||
_image_content =
|
||||
boost::dynamic_pointer_cast<simgear::canvas::Image>(
|
||||
_canvas_decoration->getRootGroup()->createChild("image", "content")
|
||||
);
|
||||
_image_content->setSrcCanvas(content);
|
||||
}
|
||||
|
||||
simgear::CSSBorder::Offsets const border =
|
||||
_decoration_border.getAbsOffsets(content->getViewport());
|
||||
|
||||
int outer_width = border.l + content->getViewWidth() + border.r,
|
||||
outer_height = border.t + content->getViewHeight() + border.b;
|
||||
|
||||
_canvas_decoration->setSizeX( outer_width );
|
||||
_canvas_decoration->setSizeY( outer_height );
|
||||
_canvas_decoration->setViewWidth( outer_width );
|
||||
_canvas_decoration->setViewHeight( outer_height );
|
||||
|
||||
_image.set<int>("size[0]", outer_width);
|
||||
_image.set<int>("size[1]", outer_height);
|
||||
|
||||
assert(_image_content);
|
||||
_image_content->set<int>("x", border.l);
|
||||
_image_content->set<int>("y", border.t);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <simgear/canvas/MouseEvent.hxx>
|
||||
#include <simgear/props/PropertyBasedElement.hxx>
|
||||
#include <simgear/props/propertyObject.hxx>
|
||||
#include <simgear/misc/CSSBorder.hxx>
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
|
@ -49,13 +50,19 @@ namespace canvas
|
|||
|
||||
virtual void update(double delta_time_sec);
|
||||
virtual void valueChanged(SGPropertyNode* node);
|
||||
virtual void childAdded(SGPropertyNode* parent, SGPropertyNode* child);
|
||||
virtual void childRemoved(SGPropertyNode* parent, SGPropertyNode* child);
|
||||
|
||||
osg::Group* getGroup();
|
||||
const SGRect<float>& getRegion() const;
|
||||
const SGVec2<float> getPosition() const;
|
||||
const SGRect<float> getScreenRegion() const;
|
||||
|
||||
void setCanvas(simgear::canvas::CanvasPtr canvas);
|
||||
simgear::canvas::CanvasWeakPtr getCanvas() const;
|
||||
|
||||
simgear::canvas::CanvasPtr getCanvasDecoration();
|
||||
|
||||
bool isVisible() const;
|
||||
bool isResizable() const;
|
||||
bool isCapturingEvents() const;
|
||||
|
@ -68,7 +75,20 @@ namespace canvas
|
|||
|
||||
protected:
|
||||
|
||||
enum Attributes
|
||||
{
|
||||
SHADOW = 1
|
||||
};
|
||||
|
||||
uint32_t _attributes_dirty;
|
||||
|
||||
simgear::canvas::CanvasPtr _canvas_decoration;
|
||||
simgear::canvas::CanvasWeakPtr _canvas_content;
|
||||
|
||||
simgear::canvas::Image _image;
|
||||
simgear::canvas::ImagePtr _image_content,
|
||||
_image_shadow;
|
||||
|
||||
bool _resizable,
|
||||
_capture_events;
|
||||
|
||||
|
@ -78,6 +98,9 @@ namespace canvas
|
|||
_resize_left,
|
||||
_resize_status;
|
||||
|
||||
simgear::CSSBorder _decoration_border;
|
||||
|
||||
void parseDecorationBorder(const std::string& str);
|
||||
};
|
||||
} // namespace canvas
|
||||
|
||||
|
|
|
@ -232,7 +232,8 @@ naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave)
|
|||
.method("getNearestCursor", &sc::Text::getNearestCursor);
|
||||
|
||||
NasalWindow::init("canvas.Window")
|
||||
.member("_node_ghost", &elementGetNode<canvas::Window>);
|
||||
.member("_node_ghost", &elementGetNode<canvas::Window>)
|
||||
.method("_getCanvasDecoration", &canvas::Window::getCanvasDecoration);
|
||||
|
||||
nasal::Hash globals_module(globals, c),
|
||||
canvas_module = globals_module.createHash("canvas");
|
||||
|
|
Loading…
Reference in a new issue