1
0
Fork 0

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:
Thomas Geymayer 2013-06-06 22:32:09 +02:00
parent 53c3033135
commit 326ee0c5cf
4 changed files with 193 additions and 19 deletions

View file

@ -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,9 +352,9 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
continue;
float margin = window->isResizable() ? resize_margin_pos : 0;
if( window->getRegion().contains( event->getScreenX(),
event->getScreenY(),
margin ) )
if( window->getScreenRegion().contains( event->getScreenX(),
event->getScreenY(),
margin ) )
{
window_at_cursor = window;
break;
@ -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;
}

View file

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

View file

@ -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:
simgear::canvas::Image _image;
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

View file

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