Canvas: basic layouting system.
Support for vertical and horizontal layouts. More layouts and widgets can be created using Nasal.
This commit is contained in:
@@ -32,5 +32,6 @@ set(SOURCES
|
|||||||
add_subdirectory(ShivaVG/src)
|
add_subdirectory(ShivaVG/src)
|
||||||
add_subdirectory(elements)
|
add_subdirectory(elements)
|
||||||
add_subdirectory(events)
|
add_subdirectory(events)
|
||||||
|
add_subdirectory(layout)
|
||||||
|
|
||||||
simgear_scene_component(canvas canvas "${SOURCES}" "${HEADERS}")
|
simgear_scene_component(canvas canvas "${SOURCES}" "${HEADERS}")
|
||||||
|
|||||||
@@ -191,6 +191,14 @@ namespace canvas
|
|||||||
return _root_group;
|
return _root_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Canvas::setLayout(const LayoutRef& layout)
|
||||||
|
{
|
||||||
|
_layout = layout;
|
||||||
|
_layout->setCanvas(this);
|
||||||
|
_status |= LAYOUT_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::enableRendering(bool force)
|
void Canvas::enableRendering(bool force)
|
||||||
{
|
{
|
||||||
@@ -202,11 +210,10 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::update(double delta_time_sec)
|
void Canvas::update(double delta_time_sec)
|
||||||
{
|
{
|
||||||
if( (!_texture.serviceable() && _status != STATUS_DIRTY)
|
if( _status & (CREATE_FAILED | MISSING_SIZE) )
|
||||||
|| (_status & CREATE_FAILED) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( _status == STATUS_DIRTY )
|
if( _status & STATUS_DIRTY )
|
||||||
{
|
{
|
||||||
_texture.setSize(_size_x, _size_y);
|
_texture.setSize(_size_x, _size_y);
|
||||||
|
|
||||||
@@ -248,6 +255,17 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( _layout )
|
||||||
|
{
|
||||||
|
if( (_status & LAYOUT_DIRTY) )
|
||||||
|
{
|
||||||
|
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
|
||||||
|
_status &= ~LAYOUT_DIRTY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_layout->update();
|
||||||
|
}
|
||||||
|
|
||||||
if( _visible || _render_always )
|
if( _visible || _render_always )
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(CanvasWeakPtr canvas_weak, _child_canvases)
|
BOOST_FOREACH(CanvasWeakPtr canvas_weak, _child_canvases)
|
||||||
@@ -392,6 +410,7 @@ namespace canvas
|
|||||||
if( _view_width == w )
|
if( _view_width == w )
|
||||||
return;
|
return;
|
||||||
_view_width = w;
|
_view_width = w;
|
||||||
|
_status |= LAYOUT_DIRTY;
|
||||||
|
|
||||||
_texture.setViewSize(_view_width, _view_height);
|
_texture.setViewSize(_view_width, _view_height);
|
||||||
}
|
}
|
||||||
@@ -402,6 +421,7 @@ namespace canvas
|
|||||||
if( _view_height == h )
|
if( _view_height == h )
|
||||||
return;
|
return;
|
||||||
_view_height = h;
|
_view_height = h;
|
||||||
|
_status |= LAYOUT_DIRTY;
|
||||||
|
|
||||||
_texture.setViewSize(_view_width, _view_height);
|
_texture.setViewSize(_view_width, _view_height);
|
||||||
}
|
}
|
||||||
@@ -657,7 +677,7 @@ namespace canvas
|
|||||||
_status_msg = "Missing size-y";
|
_status_msg = "Missing size-y";
|
||||||
else if( _status & CREATE_FAILED )
|
else if( _status & CREATE_FAILED )
|
||||||
_status_msg = "Creating render target failed";
|
_status_msg = "Creating render target failed";
|
||||||
else if( _status == STATUS_DIRTY )
|
else if( _status & STATUS_DIRTY )
|
||||||
_status_msg = "Creation pending...";
|
_status_msg = "Creation pending...";
|
||||||
else
|
else
|
||||||
_status_msg = "Ok";
|
_status_msg = "Ok";
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "ODGauge.hxx"
|
#include "ODGauge.hxx"
|
||||||
|
|
||||||
#include <simgear/canvas/elements/CanvasGroup.hxx>
|
#include <simgear/canvas/elements/CanvasGroup.hxx>
|
||||||
|
#include <simgear/canvas/layout/Layout.hxx>
|
||||||
#include <simgear/math/SGRect.hxx>
|
#include <simgear/math/SGRect.hxx>
|
||||||
#include <simgear/props/PropertyBasedElement.hxx>
|
#include <simgear/props/PropertyBasedElement.hxx>
|
||||||
#include <simgear/props/propertyObject.hxx>
|
#include <simgear/props/propertyObject.hxx>
|
||||||
@@ -48,9 +49,11 @@ namespace canvas
|
|||||||
enum StatusFlags
|
enum StatusFlags
|
||||||
{
|
{
|
||||||
STATUS_OK,
|
STATUS_OK,
|
||||||
STATUS_DIRTY = 1,
|
STATUS_DIRTY = 1,
|
||||||
MISSING_SIZE_X = STATUS_DIRTY << 1,
|
LAYOUT_DIRTY = STATUS_DIRTY << 1,
|
||||||
|
MISSING_SIZE_X = LAYOUT_DIRTY << 1,
|
||||||
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
|
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
|
||||||
|
MISSING_SIZE = MISSING_SIZE_X | MISSING_SIZE_Y,
|
||||||
CREATE_FAILED = MISSING_SIZE_Y << 1
|
CREATE_FAILED = MISSING_SIZE_Y << 1
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -121,6 +124,12 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
GroupPtr getRootGroup();
|
GroupPtr getRootGroup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the layout of the canvas (the layout will automatically update with
|
||||||
|
* the viewport size of the canvas)
|
||||||
|
*/
|
||||||
|
void setLayout(const LayoutRef& layout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable rendering for the next frame
|
* Enable rendering for the next frame
|
||||||
*
|
*
|
||||||
@@ -195,7 +204,9 @@ namespace canvas
|
|||||||
_visible;
|
_visible;
|
||||||
|
|
||||||
ODGauge _texture;
|
ODGauge _texture;
|
||||||
GroupPtr _root_group;
|
|
||||||
|
GroupPtr _root_group;
|
||||||
|
LayoutRef _layout;
|
||||||
|
|
||||||
CullCallbackPtr _cull_callback;
|
CullCallbackPtr _cull_callback;
|
||||||
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
||||||
|
|||||||
@@ -125,6 +125,11 @@ namespace canvas
|
|||||||
void Window::setCanvasContent(CanvasPtr canvas)
|
void Window::setCanvasContent(CanvasPtr canvas)
|
||||||
{
|
{
|
||||||
_canvas_content = canvas;
|
_canvas_content = canvas;
|
||||||
|
if( _layout )
|
||||||
|
{
|
||||||
|
canvas->setLayout(_layout);
|
||||||
|
_layout.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if( _image_content )
|
if( _image_content )
|
||||||
// Placement within decoration canvas
|
// Placement within decoration canvas
|
||||||
@@ -139,6 +144,16 @@ namespace canvas
|
|||||||
return _canvas_content;
|
return _canvas_content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Window::setLayout(const LayoutRef& layout)
|
||||||
|
{
|
||||||
|
CanvasPtr canvas = _canvas_content.lock();
|
||||||
|
if( canvas )
|
||||||
|
canvas->setLayout(layout);
|
||||||
|
else
|
||||||
|
_layout = layout; // keep layout until content canvas is set
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
CanvasPtr Window::getCanvasDecoration() const
|
CanvasPtr Window::getCanvasDecoration() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#define CANVAS_WINDOW_HXX_
|
#define CANVAS_WINDOW_HXX_
|
||||||
|
|
||||||
#include <simgear/canvas/elements/CanvasImage.hxx>
|
#include <simgear/canvas/elements/CanvasImage.hxx>
|
||||||
|
#include <simgear/canvas/layout/Layout.hxx>
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||||
#include <simgear/props/PropertyBasedElement.hxx>
|
#include <simgear/props/PropertyBasedElement.hxx>
|
||||||
#include <simgear/props/propertyObject.hxx>
|
#include <simgear/props/propertyObject.hxx>
|
||||||
@@ -34,7 +35,8 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
|
|
||||||
class Window:
|
class Window:
|
||||||
public Image
|
public Image,
|
||||||
|
public LayoutItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const std::string TYPE_NAME;
|
static const std::string TYPE_NAME;
|
||||||
@@ -75,6 +77,8 @@ namespace canvas
|
|||||||
void setCanvasContent(CanvasPtr canvas);
|
void setCanvasContent(CanvasPtr canvas);
|
||||||
simgear::canvas::CanvasWeakPtr getCanvasContent() const;
|
simgear::canvas::CanvasWeakPtr getCanvasContent() const;
|
||||||
|
|
||||||
|
void setLayout(const LayoutRef& layout);
|
||||||
|
|
||||||
CanvasPtr getCanvasDecoration() const;
|
CanvasPtr getCanvasDecoration() const;
|
||||||
|
|
||||||
bool isResizable() const;
|
bool isResizable() const;
|
||||||
@@ -101,6 +105,7 @@ namespace canvas
|
|||||||
|
|
||||||
CanvasPtr _canvas_decoration;
|
CanvasPtr _canvas_decoration;
|
||||||
CanvasWeakPtr _canvas_content;
|
CanvasWeakPtr _canvas_content;
|
||||||
|
LayoutRef _layout;
|
||||||
|
|
||||||
ImagePtr _image_content,
|
ImagePtr _image_content,
|
||||||
_image_shadow;
|
_image_shadow;
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ namespace canvas
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get bounding box (may not be as tight as bounding box returned by
|
* Get bounding box (may not be as tight as bounding box returned by
|
||||||
* #getTightBounds)
|
* #getTightBoundingBox)
|
||||||
*/
|
*/
|
||||||
osg::BoundingBox getBoundingBox() const;
|
osg::BoundingBox getBoundingBox() const;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
// Align items horizontally or vertically in a box
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#include "BoxLayout.hxx"
|
||||||
|
#include <simgear/canvas/Canvas.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
namespace canvas
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
BoxLayout::BoxLayout(Direction dir):
|
||||||
|
_padding(5)
|
||||||
|
{
|
||||||
|
setDirection(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void BoxLayout::addItem(const LayoutItemRef& item)
|
||||||
|
{
|
||||||
|
return addItem(item, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
|
||||||
|
{
|
||||||
|
ItemData item_data = {0};
|
||||||
|
item_data.layout_item = item;
|
||||||
|
item_data.stretch = std::max(0, stretch);
|
||||||
|
|
||||||
|
item->setCanvas(_canvas);
|
||||||
|
item->setParent(this);
|
||||||
|
|
||||||
|
_layout_items.push_back(item_data);
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void BoxLayout::setStretch(size_t index, int stretch)
|
||||||
|
{
|
||||||
|
if( index >= _layout_items.size() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_layout_items.at(index).stretch = std::max(0, stretch);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
int BoxLayout::stretch(size_t index) const
|
||||||
|
{
|
||||||
|
if( index >= _layout_items.size() )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return _layout_items.at(index).stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void BoxLayout::setSpacing(int spacing)
|
||||||
|
{
|
||||||
|
if( spacing == _padding )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_padding = spacing;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
int BoxLayout::spacing() const
|
||||||
|
{
|
||||||
|
return _padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void BoxLayout::setDirection(Direction dir)
|
||||||
|
{
|
||||||
|
_get_layout_coord = &SGVec2i::x;
|
||||||
|
_get_fixed_coord = &SGVec2i::y;
|
||||||
|
|
||||||
|
if( dir == TopToBottom || dir == BottomToTop )
|
||||||
|
std::swap(_get_layout_coord, _get_fixed_coord);
|
||||||
|
|
||||||
|
_reverse = (dir == RightToLeft || dir == BottomToTop );
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
BoxLayout::Direction BoxLayout::direction() const
|
||||||
|
{
|
||||||
|
if( _get_layout_coord == static_cast<CoordGetter>(&SGVec2i::x) )
|
||||||
|
return _reverse ? RightToLeft : LeftToRight;
|
||||||
|
else
|
||||||
|
return _reverse ? BottomToTop : TopToBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void BoxLayout::setCanvas(const CanvasWeakPtr& canvas)
|
||||||
|
{
|
||||||
|
_canvas = canvas;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
|
_layout_items[i].layout_item->setCanvas(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void BoxLayout::updateSizeHints() const
|
||||||
|
{
|
||||||
|
SGVec2i min_size(0, 0),
|
||||||
|
max_size(0, 0),
|
||||||
|
size_hint(0, 0);
|
||||||
|
|
||||||
|
_layout_data.reset();
|
||||||
|
bool is_first = true;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
|
{
|
||||||
|
// TODO check visible
|
||||||
|
|
||||||
|
ItemData& item_data = _layout_items[i];
|
||||||
|
LayoutItem const& item = *item_data.layout_item;
|
||||||
|
|
||||||
|
item_data.min_size = (item.minimumSize().*_get_layout_coord)();
|
||||||
|
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
|
||||||
|
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
|
||||||
|
|
||||||
|
if( is_first )
|
||||||
|
{
|
||||||
|
item_data.padding_orig = 0;
|
||||||
|
is_first = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
item_data.padding_orig = _padding;
|
||||||
|
|
||||||
|
_layout_data.padding += item_data.padding_orig;
|
||||||
|
|
||||||
|
// Add sizes of all children in layout direction
|
||||||
|
safeAdd(min_size.x(), item_data.min_size);
|
||||||
|
safeAdd(max_size.x(), item_data.max_size);
|
||||||
|
safeAdd(size_hint.x(), item_data.size_hint);
|
||||||
|
|
||||||
|
// Take maximum in fixed (non-layouted) direction
|
||||||
|
min_size.y() = std::max( min_size.y(),
|
||||||
|
(item.minimumSize().*_get_fixed_coord)() );
|
||||||
|
max_size.y() = std::max( max_size.y(),
|
||||||
|
(item.maximumSize().*_get_fixed_coord)() );
|
||||||
|
size_hint.y() = std::max( min_size.y(),
|
||||||
|
(item.sizeHint().*_get_fixed_coord)() );
|
||||||
|
}
|
||||||
|
|
||||||
|
safeAdd(min_size.x(), _layout_data.padding);
|
||||||
|
safeAdd(max_size.x(), _layout_data.padding);
|
||||||
|
safeAdd(size_hint.x(), _layout_data.padding);
|
||||||
|
|
||||||
|
_layout_data.min_size = min_size.x();
|
||||||
|
_layout_data.max_size = max_size.x();
|
||||||
|
_layout_data.size_hint = size_hint.x();
|
||||||
|
|
||||||
|
_min_size.x() = (min_size.*_get_layout_coord)();
|
||||||
|
_max_size.x() = (max_size.*_get_layout_coord)();
|
||||||
|
_size_hint.x() = (size_hint.*_get_layout_coord)();
|
||||||
|
|
||||||
|
_min_size.y() = (min_size.*_get_fixed_coord)();
|
||||||
|
_max_size.y() = (max_size.*_get_fixed_coord)();
|
||||||
|
_size_hint.y() = (size_hint.*_get_fixed_coord)();
|
||||||
|
|
||||||
|
_flags &= ~SIZE_INFO_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i BoxLayout::sizeHintImpl() const
|
||||||
|
{
|
||||||
|
updateSizeHints();
|
||||||
|
return _size_hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i BoxLayout::minimumSizeImpl() const
|
||||||
|
{
|
||||||
|
updateSizeHints();
|
||||||
|
return _min_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i BoxLayout::maximumSizeImpl() const
|
||||||
|
{
|
||||||
|
updateSizeHints();
|
||||||
|
return _max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void BoxLayout::doLayout(const SGRecti& geom)
|
||||||
|
{
|
||||||
|
if( _flags & SIZE_INFO_DIRTY )
|
||||||
|
updateSizeHints();
|
||||||
|
|
||||||
|
_layout_data.size = (geom.size().*_get_layout_coord)();
|
||||||
|
distribute(_layout_items, _layout_data);
|
||||||
|
|
||||||
|
int fixed_size = (geom.size().*_get_fixed_coord)();
|
||||||
|
SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
|
||||||
|
(geom.pos().*_get_fixed_coord)() );
|
||||||
|
if( _reverse )
|
||||||
|
cur_pos.x() += (geom.size().*_get_layout_coord)();
|
||||||
|
|
||||||
|
// TODO handle reverse layouting (rtl/btt)
|
||||||
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
|
{
|
||||||
|
ItemData const& data = _layout_items[i];
|
||||||
|
cur_pos.x() += _reverse ? -data.padding - data.size : data.padding;
|
||||||
|
|
||||||
|
SGVec2i size(
|
||||||
|
data.size,
|
||||||
|
std::min( (data.layout_item->maximumSize().*_get_fixed_coord)(),
|
||||||
|
fixed_size )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Center in fixed direction (TODO allow specifying alignment)
|
||||||
|
int offset_fixed = (fixed_size - size.y()) / 2;
|
||||||
|
cur_pos.y() += offset_fixed;
|
||||||
|
|
||||||
|
data.layout_item->setGeometry(SGRecti(
|
||||||
|
(cur_pos.*_get_layout_coord)(),
|
||||||
|
(cur_pos.*_get_fixed_coord)(),
|
||||||
|
(size.*_get_layout_coord)(),
|
||||||
|
(size.*_get_fixed_coord)()
|
||||||
|
));
|
||||||
|
|
||||||
|
if( !_reverse )
|
||||||
|
cur_pos.x() += data.size;
|
||||||
|
cur_pos.y() -= offset_fixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
HBoxLayout::HBoxLayout():
|
||||||
|
BoxLayout(LeftToRight)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
VBoxLayout::VBoxLayout():
|
||||||
|
BoxLayout(TopToBottom)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace canvas
|
||||||
|
} // namespace simgear
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
// Align items horizontally or vertically in a box
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#ifndef SG_CANVAS_BOX_LAYOUT_HXX_
|
||||||
|
#define SG_CANVAS_BOX_LAYOUT_HXX_
|
||||||
|
|
||||||
|
#include "Layout.hxx"
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
namespace canvas
|
||||||
|
{
|
||||||
|
|
||||||
|
class BoxLayout:
|
||||||
|
public Layout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Direction
|
||||||
|
{
|
||||||
|
LeftToRight,
|
||||||
|
RightToLeft,
|
||||||
|
TopToBottom,
|
||||||
|
BottomToTop
|
||||||
|
};
|
||||||
|
|
||||||
|
BoxLayout(Direction dir);
|
||||||
|
|
||||||
|
virtual void addItem(const LayoutItemRef& item);
|
||||||
|
|
||||||
|
void addItem(const LayoutItemRef& item, int stretch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the stretch factor of the item at position @a index to @a stretch.
|
||||||
|
*/
|
||||||
|
void setStretch(size_t index, int stretch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stretch factor of the item at position @a index
|
||||||
|
*/
|
||||||
|
int stretch(size_t index) const;
|
||||||
|
|
||||||
|
virtual void setSpacing(int spacing);
|
||||||
|
virtual int spacing() const;
|
||||||
|
|
||||||
|
void setDirection(Direction dir);
|
||||||
|
Direction direction() const;
|
||||||
|
|
||||||
|
virtual void setCanvas(const CanvasWeakPtr& canvas);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
typedef const int& (SGVec2i::*CoordGetter)() const;
|
||||||
|
CoordGetter _get_layout_coord, //<! getter for coordinate in layout
|
||||||
|
// direction
|
||||||
|
_get_fixed_coord; //<! getter for coordinate in secondary
|
||||||
|
// (fixed) direction
|
||||||
|
|
||||||
|
int _padding;
|
||||||
|
bool _reverse; //<! if true, right-to-left/bottom-to-top layouting
|
||||||
|
|
||||||
|
mutable std::vector<ItemData> _layout_items;
|
||||||
|
mutable ItemData _layout_data;
|
||||||
|
|
||||||
|
void updateSizeHints() const;
|
||||||
|
|
||||||
|
virtual SGVec2i sizeHintImpl() const;
|
||||||
|
virtual SGVec2i minimumSizeImpl() const;
|
||||||
|
virtual SGVec2i maximumSizeImpl() const;
|
||||||
|
|
||||||
|
virtual void doLayout(const SGRecti& geom);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut for creating a horizontal box layout
|
||||||
|
*/
|
||||||
|
class HBoxLayout:
|
||||||
|
public BoxLayout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HBoxLayout();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shortcut for creating a vertical box layout
|
||||||
|
*/
|
||||||
|
class VBoxLayout:
|
||||||
|
public BoxLayout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VBoxLayout();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace canvas
|
||||||
|
} // namespace simgear
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SG_CANVAS_BOX_LAYOUT_HXX_ */
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
include (SimGearComponent)
|
||||||
|
|
||||||
|
set(HEADERS
|
||||||
|
BoxLayout.hxx
|
||||||
|
Layout.hxx
|
||||||
|
LayoutItem.hxx
|
||||||
|
NasalWidget.hxx
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
BoxLayout.cxx
|
||||||
|
Layout.cxx
|
||||||
|
LayoutItem.cxx
|
||||||
|
NasalWidget.cxx
|
||||||
|
)
|
||||||
|
|
||||||
|
simgear_scene_component(canvas-layout canvas/layout "${SOURCES}" "${HEADERS}")
|
||||||
|
|
||||||
|
add_boost_test(canvas_layout
|
||||||
|
SOURCES canvas_layout_test.cxx
|
||||||
|
LIBRARIES ${TEST_LIBS}
|
||||||
|
)
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
// Basic class for canvas layouts
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#include "Layout.hxx"
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
namespace canvas
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Layout::update()
|
||||||
|
{
|
||||||
|
if( !(_flags & (LAYOUT_DIRTY | SIZE_INFO_DIRTY)) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
doLayout(_geometry);
|
||||||
|
|
||||||
|
_flags &= ~LAYOUT_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Layout::invalidate()
|
||||||
|
{
|
||||||
|
LayoutItem::invalidate();
|
||||||
|
_flags |= LAYOUT_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Layout::setGeometry(const SGRecti& geom)
|
||||||
|
{
|
||||||
|
if( geom == _geometry )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_geometry = geom;
|
||||||
|
_flags |= LAYOUT_DIRTY;
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Layout::ItemData::reset()
|
||||||
|
{
|
||||||
|
layout_item = 0;
|
||||||
|
size_hint = 0;
|
||||||
|
min_size = 0;
|
||||||
|
max_size = 0;
|
||||||
|
padding_orig= 0;
|
||||||
|
padding = 0;
|
||||||
|
size = 0;
|
||||||
|
stretch = 0;
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Layout::safeAdd(int& a, int b)
|
||||||
|
{
|
||||||
|
if( SGLimits<int>::max() - b < a )
|
||||||
|
a = SGLimits<int>::max();
|
||||||
|
else
|
||||||
|
a += b;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
|
||||||
|
{
|
||||||
|
const int num_children = static_cast<int>(items.size());
|
||||||
|
_num_not_done = num_children;
|
||||||
|
|
||||||
|
SG_LOG( SG_GUI,
|
||||||
|
SG_DEBUG,
|
||||||
|
"Layout::distribute(" << num_children << " items)" );
|
||||||
|
|
||||||
|
if( space.size < space.min_size )
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
SG_LOG( SG_GUI, SG_WARN, "Layout: not enough size (not implemented)");
|
||||||
|
}
|
||||||
|
else if( space.size < space.max_size )
|
||||||
|
{
|
||||||
|
_sum_stretch = 0;
|
||||||
|
_space_stretch = 0;
|
||||||
|
|
||||||
|
bool less_then_hint = space.size < space.size_hint;
|
||||||
|
|
||||||
|
// Give min_size/size_hint to all items
|
||||||
|
_space_left = space.size
|
||||||
|
- (less_then_hint ? space.min_size : space.size_hint);
|
||||||
|
for(int i = 0; i < num_children; ++i)
|
||||||
|
{
|
||||||
|
ItemData& d = items[i];
|
||||||
|
d.size = less_then_hint ? d.min_size : d.size_hint;
|
||||||
|
d.padding = d.padding_orig;
|
||||||
|
d.done = d.size >= (less_then_hint ? d.size_hint : d.max_size);
|
||||||
|
|
||||||
|
if( d.done )
|
||||||
|
{
|
||||||
|
_num_not_done -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( d.stretch > 0 )
|
||||||
|
{
|
||||||
|
_sum_stretch += d.stretch;
|
||||||
|
_space_stretch += d.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distribute remaining space to increase the size of each item up to its
|
||||||
|
// size_hint/max_size
|
||||||
|
while( _space_left > 0 )
|
||||||
|
{
|
||||||
|
if( _num_not_done <= 0 )
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GUI, SG_WARN, "space left, but no more items?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int space_per_element = std::max(1, _space_left / _num_not_done);
|
||||||
|
|
||||||
|
SG_LOG(SG_GUI, SG_DEBUG, "space/element=" << space_per_element);
|
||||||
|
|
||||||
|
for(int i = 0; i < num_children; ++i)
|
||||||
|
{
|
||||||
|
ItemData& d = items[i];
|
||||||
|
|
||||||
|
SG_LOG(
|
||||||
|
SG_GUI,
|
||||||
|
SG_DEBUG,
|
||||||
|
i << ") left=" << _space_left
|
||||||
|
<< ", not_done=" << _num_not_done
|
||||||
|
<< ", sum=" << _sum_stretch
|
||||||
|
<< ", stretch=" << _space_stretch
|
||||||
|
<< ", stretch/unit=" << _space_stretch / std::max(1, _sum_stretch)
|
||||||
|
);
|
||||||
|
|
||||||
|
if( d.done )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( _sum_stretch > 0 && d.stretch <= 0 )
|
||||||
|
d.done = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int target_size = 0;
|
||||||
|
int max_size = less_then_hint ? d.size_hint : d.max_size;
|
||||||
|
|
||||||
|
if( _sum_stretch > 0 )
|
||||||
|
{
|
||||||
|
target_size = (d.stretch * (_space_left + _space_stretch))
|
||||||
|
/ _sum_stretch;
|
||||||
|
|
||||||
|
// Item would be smaller than minimum size or larger than maximum
|
||||||
|
// size, so just keep bounded size and ignore stretch factor
|
||||||
|
if( target_size <= d.size || target_size >= max_size )
|
||||||
|
{
|
||||||
|
d.done = true;
|
||||||
|
_sum_stretch -= d.stretch;
|
||||||
|
_space_stretch -= d.size;
|
||||||
|
|
||||||
|
if( target_size >= max_size )
|
||||||
|
target_size = max_size;
|
||||||
|
else
|
||||||
|
target_size = d.size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_space_stretch += target_size - d.size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Give space evenly to all remaining elements in this round
|
||||||
|
target_size = d.size + std::min(_space_left, space_per_element);
|
||||||
|
|
||||||
|
if( target_size >= max_size )
|
||||||
|
{
|
||||||
|
d.done = true;
|
||||||
|
target_size = max_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int old_size = d.size;
|
||||||
|
d.size = target_size;
|
||||||
|
_space_left -= d.size - old_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( d.done )
|
||||||
|
{
|
||||||
|
_num_not_done -= 1;
|
||||||
|
|
||||||
|
if( _sum_stretch <= 0 && d.stretch > 0 )
|
||||||
|
// Distribute remaining space evenly to all non-stretchable items
|
||||||
|
// in a new round
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_space_left = space.size - space.max_size;
|
||||||
|
for(int i = 0; i < num_children; ++i)
|
||||||
|
{
|
||||||
|
ItemData& d = items[i];
|
||||||
|
d.size = d.max_size;
|
||||||
|
|
||||||
|
// Add superfluous space as padding
|
||||||
|
d.padding = d.padding_orig + _space_left
|
||||||
|
// Padding after last child...
|
||||||
|
/ (_num_not_done + 1);
|
||||||
|
|
||||||
|
_space_left -= d.padding - d.padding_orig;
|
||||||
|
_num_not_done -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_GUI, SG_DEBUG, "distribute:");
|
||||||
|
for(int i = 0; i < num_children; ++i)
|
||||||
|
{
|
||||||
|
ItemData const& d = items[i];
|
||||||
|
SG_LOG( SG_GUI,
|
||||||
|
SG_DEBUG,
|
||||||
|
i << ") pad=" << d.padding
|
||||||
|
<< ", size = " << d.size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace canvas
|
||||||
|
} // namespace simgear
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// Basic class for canvas layouts
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#ifndef SG_CANVAS_LAYOUT_HXX_
|
||||||
|
#define SG_CANVAS_LAYOUT_HXX_
|
||||||
|
|
||||||
|
#include "LayoutItem.hxx"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
namespace canvas
|
||||||
|
{
|
||||||
|
|
||||||
|
class Layout:
|
||||||
|
public LayoutItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void update();
|
||||||
|
|
||||||
|
virtual void invalidate();
|
||||||
|
virtual void setGeometry(const SGRecti& geom);
|
||||||
|
|
||||||
|
virtual void addItem(const LayoutItemRef& item) = 0;
|
||||||
|
virtual void setSpacing(int spacing) = 0;
|
||||||
|
virtual int spacing() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum LayoutFlags
|
||||||
|
{
|
||||||
|
LAYOUT_DIRTY = LayoutItem::LAST_FLAG << 1,
|
||||||
|
LAST_FLAG = LAYOUT_DIRTY
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ItemData
|
||||||
|
{
|
||||||
|
LayoutItemRef layout_item;
|
||||||
|
int size_hint,
|
||||||
|
min_size,
|
||||||
|
max_size,
|
||||||
|
padding_orig, //<! original padding as specified by the user
|
||||||
|
padding, //<! padding before element (layouted)
|
||||||
|
size, //<! layouted size
|
||||||
|
stretch; //<! stretch factor
|
||||||
|
bool done; //<! layouting done
|
||||||
|
|
||||||
|
/** Clear values (reset to default/empty state) */
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override to implement the actual layouting
|
||||||
|
*/
|
||||||
|
virtual void doLayout(const SGRecti& geom) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two integers taking care of overflow (limit to INT_MAX)
|
||||||
|
*/
|
||||||
|
static void safeAdd(int& a, int b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distribute the available @a space to all @a items
|
||||||
|
*/
|
||||||
|
void distribute(std::vector<ItemData>& items, const ItemData& space);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int _num_not_done, //<! number of children not layouted yet
|
||||||
|
_sum_stretch, //<! sum of stretch factors of all not yet layouted
|
||||||
|
// children
|
||||||
|
_space_stretch,//<! space currently assigned to all not yet layouted
|
||||||
|
// stretchable children
|
||||||
|
_space_left; //<! remaining space not used by any child yet
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SGSharedPtr<Layout> LayoutRef;
|
||||||
|
|
||||||
|
} // namespace canvas
|
||||||
|
} // namespace simgear
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SG_CANVAS_LAYOUT_HXX_ */
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
// Basic element for layouting canvas elements
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#include "LayoutItem.hxx"
|
||||||
|
#include <simgear/canvas/Canvas.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
namespace canvas
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
LayoutItem::LayoutItem():
|
||||||
|
_flags(0)
|
||||||
|
{
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
LayoutItem::~LayoutItem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i LayoutItem::sizeHint() const
|
||||||
|
{
|
||||||
|
if( _flags & SIZE_HINT_DIRTY )
|
||||||
|
{
|
||||||
|
_size_hint = sizeHintImpl();
|
||||||
|
_flags &= ~SIZE_HINT_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _size_hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i LayoutItem::minimumSize() const
|
||||||
|
{
|
||||||
|
if( _flags & MINIMUM_SIZE_DIRTY )
|
||||||
|
{
|
||||||
|
_min_size = minimumSizeImpl();
|
||||||
|
_flags &= ~MINIMUM_SIZE_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _min_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i LayoutItem::maximumSize() const
|
||||||
|
{
|
||||||
|
if( _flags & MAXIMUM_SIZE_DIRTY )
|
||||||
|
{
|
||||||
|
_max_size = maximumSizeImpl();
|
||||||
|
_flags &= ~MAXIMUM_SIZE_DIRTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void LayoutItem::invalidate()
|
||||||
|
{
|
||||||
|
_flags |= SIZE_HINT_DIRTY
|
||||||
|
| MINIMUM_SIZE_DIRTY
|
||||||
|
| MAXIMUM_SIZE_DIRTY;
|
||||||
|
|
||||||
|
invalidateParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void LayoutItem::invalidateParent()
|
||||||
|
{
|
||||||
|
LayoutItemRef parent = _parent.lock();
|
||||||
|
if( parent )
|
||||||
|
parent->invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void LayoutItem::setGeometry(const SGRecti& geom)
|
||||||
|
{
|
||||||
|
_geometry = geom;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGRecti LayoutItem::geometry() const
|
||||||
|
{
|
||||||
|
return _geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
|
||||||
|
{
|
||||||
|
_canvas = canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
CanvasPtr LayoutItem::getCanvas() const
|
||||||
|
{
|
||||||
|
return _canvas.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void LayoutItem::setParent(const LayoutItemWeakRef& parent)
|
||||||
|
{
|
||||||
|
_parent = parent;
|
||||||
|
LayoutItemRef parent_ref = parent.lock();
|
||||||
|
setCanvas(parent_ref ? parent_ref->_canvas : CanvasWeakPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
LayoutItemRef LayoutItem::getParent() const
|
||||||
|
{
|
||||||
|
return _parent.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i LayoutItem::sizeHintImpl() const
|
||||||
|
{
|
||||||
|
return SGVec2i(16, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i LayoutItem::minimumSizeImpl() const
|
||||||
|
{
|
||||||
|
return SGVec2i(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i LayoutItem::maximumSizeImpl() const
|
||||||
|
{
|
||||||
|
return SGVec2i(SGLimits<int>::max(), SGLimits<int>::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace canvas
|
||||||
|
} // namespace simgear
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
///@file Basic element for layouting canvas elements
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#ifndef SG_CANVAS_LAYOUT_ITEM_HXX_
|
||||||
|
#define SG_CANVAS_LAYOUT_ITEM_HXX_
|
||||||
|
|
||||||
|
#include <simgear/canvas/canvas_fwd.hxx>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include <simgear/math/SGRect.hxx>
|
||||||
|
#include <simgear/misc/stdint.hxx>
|
||||||
|
#include <simgear/structure/SGWeakReferenced.hxx>
|
||||||
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
namespace canvas
|
||||||
|
{
|
||||||
|
class LayoutItem;
|
||||||
|
typedef SGSharedPtr<LayoutItem> LayoutItemRef;
|
||||||
|
typedef SGWeakPtr<LayoutItem> LayoutItemWeakRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all layouting elements. Specializations either implement a
|
||||||
|
* layouting algorithm or a widget.
|
||||||
|
*/
|
||||||
|
class LayoutItem:
|
||||||
|
public virtual SGVirtualWeakReferenced
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
LayoutItem();
|
||||||
|
virtual ~LayoutItem();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the preferred size of this item.
|
||||||
|
*/
|
||||||
|
SGVec2i sizeHint() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the minimum amount of the space this item requires.
|
||||||
|
*/
|
||||||
|
SGVec2i minimumSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the maximum amount of space this item can use.
|
||||||
|
*/
|
||||||
|
SGVec2i maximumSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark all cached data as invalid and require it to be recalculated.
|
||||||
|
*/
|
||||||
|
virtual void invalidate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark all cached data of parent item as invalid (if it is known)
|
||||||
|
*/
|
||||||
|
void invalidateParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set position and size of this element. For layouts this triggers a
|
||||||
|
* recalculation of the layout.
|
||||||
|
*/
|
||||||
|
virtual void setGeometry(const SGRecti& geom);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get position and size of this element.
|
||||||
|
*/
|
||||||
|
virtual SGRecti geometry() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the canvas this item is attached to.
|
||||||
|
*/
|
||||||
|
virtual void setCanvas(const CanvasWeakPtr& canvas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the canvas this item is attached to.
|
||||||
|
*/
|
||||||
|
CanvasPtr getCanvas() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the parent layout item (usally this is a layout).
|
||||||
|
*/
|
||||||
|
void setParent(const LayoutItemWeakRef& parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parent layout.
|
||||||
|
*/
|
||||||
|
LayoutItemRef getParent() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
friend class Canvas;
|
||||||
|
|
||||||
|
enum Flags
|
||||||
|
{
|
||||||
|
SIZE_HINT_DIRTY = 1,
|
||||||
|
MINIMUM_SIZE_DIRTY = SIZE_HINT_DIRTY << 1,
|
||||||
|
MAXIMUM_SIZE_DIRTY = MINIMUM_SIZE_DIRTY << 1,
|
||||||
|
SIZE_INFO_DIRTY = SIZE_HINT_DIRTY
|
||||||
|
| MINIMUM_SIZE_DIRTY
|
||||||
|
| MAXIMUM_SIZE_DIRTY,
|
||||||
|
LAST_FLAG = MAXIMUM_SIZE_DIRTY
|
||||||
|
};
|
||||||
|
|
||||||
|
CanvasWeakPtr _canvas;
|
||||||
|
LayoutItemWeakRef _parent;
|
||||||
|
|
||||||
|
SGRecti _geometry;
|
||||||
|
|
||||||
|
mutable uint32_t _flags;
|
||||||
|
mutable SGVec2i _size_hint,
|
||||||
|
_min_size,
|
||||||
|
_max_size;
|
||||||
|
|
||||||
|
virtual SGVec2i sizeHintImpl() const;
|
||||||
|
virtual SGVec2i minimumSizeImpl() const;
|
||||||
|
virtual SGVec2i maximumSizeImpl() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace canvas
|
||||||
|
} // namespace simgear
|
||||||
|
|
||||||
|
#endif /* SG_CANVAS_LAYOUT_ITEM_HXX_ */
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
// Glue for GUI layout items implemented in Nasal space
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#include "NasalWidget.hxx"
|
||||||
|
|
||||||
|
#include <simgear/canvas/Canvas.hxx>
|
||||||
|
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
namespace canvas
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
NasalWidget::NasalWidget(naRef impl):
|
||||||
|
_nasal_impl(impl)
|
||||||
|
{
|
||||||
|
assert( naIsHash(_nasal_impl.get_naRef()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NasalWidget::setGeometry(const SGRect<int>& geom)
|
||||||
|
{
|
||||||
|
if( _geometry == geom )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_geometry = geom;
|
||||||
|
|
||||||
|
if( _set_geometry )
|
||||||
|
_set_geometry(_nasal_impl.get_naRef(), geom);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NasalWidget::setSetGeometryFunc(const SetGeometryFunc& func)
|
||||||
|
{
|
||||||
|
_set_geometry = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NasalWidget::setImpl(naRef obj)
|
||||||
|
{
|
||||||
|
_nasal_impl.reset(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
naRef NasalWidget::getImpl() const
|
||||||
|
{
|
||||||
|
return _nasal_impl.get_naRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NasalWidget::setSizeHint(const SGVec2i& s)
|
||||||
|
{
|
||||||
|
if( _size_hint == s )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_size_hint = s;
|
||||||
|
|
||||||
|
// TODO just invalidate size_hint? Probably not a performance issue...
|
||||||
|
invalidateParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NasalWidget::setMinimumSize(const SGVec2i& s)
|
||||||
|
{
|
||||||
|
if( _min_size == s )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_min_size = s;
|
||||||
|
invalidateParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NasalWidget::setMaximumSize(const SGVec2i& s)
|
||||||
|
{
|
||||||
|
if( _max_size == s )
|
||||||
|
return;
|
||||||
|
|
||||||
|
_max_size = s;
|
||||||
|
invalidateParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool NasalWidget::_set(naContext c, const std::string& key, naRef val)
|
||||||
|
{
|
||||||
|
if( !_nasal_impl.valid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
nasal::Hash(_nasal_impl.get_naRef(), c).set(key, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static naRef f_makeNasalWidget(const nasal::CallContext& ctx)
|
||||||
|
{
|
||||||
|
return ctx.to_nasal(NasalWidgetRef(
|
||||||
|
new NasalWidget( ctx.requireArg<naRef>(0) )
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void NasalWidget::setupGhost(nasal::Hash& ns)
|
||||||
|
{
|
||||||
|
nasal::Ghost<NasalWidgetRef>::init("canvas.Widget")
|
||||||
|
.bases<LayoutItemRef>()
|
||||||
|
._set(&NasalWidget::_set)
|
||||||
|
.member("parents", &NasalWidget::getParents)
|
||||||
|
.method("setSetGeometryFunc", &NasalWidget::setSetGeometryFunc)
|
||||||
|
.method("setSizeHint", &NasalWidget::setSizeHint)
|
||||||
|
.method("setMinimumSize", &NasalWidget::setMinimumSize)
|
||||||
|
.method("setMaximumSize", &NasalWidget::setMaximumSize);
|
||||||
|
|
||||||
|
nasal::Hash widget_hash = ns.createHash("Widget");
|
||||||
|
widget_hash.set("new", &f_makeNasalWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
naRef NasalWidget::getParents(NasalWidget& w, naContext c)
|
||||||
|
{
|
||||||
|
naRef parents[] = { w._nasal_impl.get_naRef() };
|
||||||
|
return nasal::to_nasal(c, parents);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i NasalWidget::sizeHintImpl() const
|
||||||
|
{
|
||||||
|
return _size_hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i NasalWidget::minimumSizeImpl() const
|
||||||
|
{
|
||||||
|
return _min_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
SGVec2i NasalWidget::maximumSizeImpl() const
|
||||||
|
{
|
||||||
|
return _max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace canvas
|
||||||
|
} // namespace simgear
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
///@file Glue for GUI widgets implemented in Nasal space
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#ifndef SG_CANVAS_NASAL_WIDGET_HXX_
|
||||||
|
#define SG_CANVAS_NASAL_WIDGET_HXX_
|
||||||
|
|
||||||
|
#include "LayoutItem.hxx"
|
||||||
|
|
||||||
|
#include <simgear/nasal/cppbind/from_nasal.hxx>
|
||||||
|
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
namespace canvas
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Baseclass/ghost to create widgets with Nasal.
|
||||||
|
*/
|
||||||
|
class NasalWidget:
|
||||||
|
public LayoutItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef boost::function<void (nasal::Me, const SGRecti&)> SetGeometryFunc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param impl Initial implementation hash (nasal part of
|
||||||
|
* implementation)
|
||||||
|
*/
|
||||||
|
NasalWidget(naRef impl);
|
||||||
|
|
||||||
|
virtual void setGeometry(const SGRecti& geom);
|
||||||
|
|
||||||
|
void setSetGeometryFunc(const SetGeometryFunc& func);
|
||||||
|
|
||||||
|
void setImpl(naRef obj);
|
||||||
|
naRef getImpl() const;
|
||||||
|
|
||||||
|
void setSizeHint(const SGVec2i& s);
|
||||||
|
void setMinimumSize(const SGVec2i& s);
|
||||||
|
void setMaximumSize(const SGVec2i& s);
|
||||||
|
|
||||||
|
bool _set(naContext c, const std::string& key, naRef val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ns Namespace to register the class interface
|
||||||
|
*/
|
||||||
|
static void setupGhost(nasal::Hash& ns);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SetGeometryFunc _set_geometry;
|
||||||
|
nasal::ObjectHolder<> _nasal_impl;
|
||||||
|
|
||||||
|
static naRef getParents(NasalWidget&, naContext);
|
||||||
|
|
||||||
|
virtual SGVec2i sizeHintImpl() const;
|
||||||
|
virtual SGVec2i minimumSizeImpl() const;
|
||||||
|
virtual SGVec2i maximumSizeImpl() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SGSharedPtr<NasalWidget> NasalWidgetRef;
|
||||||
|
|
||||||
|
} // namespace canvas
|
||||||
|
} // namespace simgear
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SG_CANVAS_NASAL_WIDGET_HXX_ */
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
// Testing canvas layouting system
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#define BOOST_TEST_MODULE canvas_layout
|
||||||
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
|
#include "BoxLayout.hxx"
|
||||||
|
#include "NasalWidget.hxx"
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
struct SetLogLevelFixture
|
||||||
|
{
|
||||||
|
SetLogLevelFixture()
|
||||||
|
{
|
||||||
|
sglog().set_log_priority(SG_DEBUG);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BOOST_GLOBAL_FIXTURE(SetLogLevelFixture);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
namespace sc = simgear::canvas;
|
||||||
|
|
||||||
|
class TestWidget:
|
||||||
|
public sc::LayoutItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestWidget( const SGVec2i& min_size,
|
||||||
|
const SGVec2i& size_hint,
|
||||||
|
const SGVec2i& max_size )
|
||||||
|
{
|
||||||
|
_size_hint = size_hint;
|
||||||
|
_min_size = min_size;
|
||||||
|
_max_size = max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestWidget(const TestWidget& rhs)
|
||||||
|
{
|
||||||
|
_size_hint = rhs._size_hint;
|
||||||
|
_min_size = rhs._min_size;
|
||||||
|
_max_size = rhs._max_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMinSize(const SGVec2i& size) { _min_size = size; }
|
||||||
|
void setMaxSize(const SGVec2i& size) { _max_size = size; }
|
||||||
|
void setSizeHint(const SGVec2i& size) { _size_hint = size; }
|
||||||
|
|
||||||
|
virtual void setGeometry(const SGRecti& geom) { _geom = geom; }
|
||||||
|
virtual SGRecti geometry() const { return _geom; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
SGRecti _geom;
|
||||||
|
|
||||||
|
virtual SGVec2i sizeHintImpl() const { return _size_hint; }
|
||||||
|
virtual SGVec2i minimumSizeImpl() const { return _min_size; }
|
||||||
|
virtual SGVec2i maximumSizeImpl() const { return _max_size; }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SGSharedPtr<TestWidget> TestWidgetRef;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||||
|
{
|
||||||
|
sc::BoxLayout box_layout(sc::BoxLayout::BottomToTop);
|
||||||
|
box_layout.setSpacing(5);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::BottomToTop);
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.spacing(), 5);
|
||||||
|
|
||||||
|
box_layout.setDirection(sc::BoxLayout::LeftToRight);
|
||||||
|
box_layout.setSpacing(9);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::LeftToRight);
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.spacing(), 9);
|
||||||
|
|
||||||
|
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
|
SGVec2i(16, 16),
|
||||||
|
SGVec2i(16, 16) ) );
|
||||||
|
box_layout.addItem(fixed_size_widget);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(16, 16));
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(16, 16));
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(16, 16));
|
||||||
|
|
||||||
|
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
|
SGVec2i(32, 32),
|
||||||
|
SGVec2i(256, 64) ) );
|
||||||
|
box_layout.addItem(limited_resize_widget);
|
||||||
|
|
||||||
|
// Combined sizes of both widget plus the padding between them
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(41, 16));
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(57, 32));
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(281, 64));
|
||||||
|
|
||||||
|
// Test with different spacing/padding
|
||||||
|
box_layout.setSpacing(5);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(37, 16));
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(53, 32));
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(277, 64));
|
||||||
|
|
||||||
|
box_layout.setGeometry(SGRecti(0, 0, 128, 32));
|
||||||
|
|
||||||
|
// Fixed size for first widget and remaining space goes to second widget
|
||||||
|
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
|
||||||
|
BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(21, 0, 107, 32));
|
||||||
|
|
||||||
|
TestWidgetRef stretch_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
|
SGVec2i(32, 32),
|
||||||
|
SGVec2i(128, 32) ) );
|
||||||
|
box_layout.addItem(stretch_widget, 1);
|
||||||
|
box_layout.update();
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(58, 16));
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(90, 32));
|
||||||
|
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(410, 64));
|
||||||
|
|
||||||
|
// Due to the stretch factor only the last widget gets additional space. All
|
||||||
|
// other widgets get the preferred size.
|
||||||
|
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
|
||||||
|
BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(21, 0, 32, 32));
|
||||||
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(58, 0, 70, 32));
|
||||||
|
|
||||||
|
// Test stretch factor
|
||||||
|
TestWidgetRef fast_stretch( new TestWidget(*stretch_widget) );
|
||||||
|
sc::BoxLayout box_layout_stretch(sc::BoxLayout::LeftToRight);
|
||||||
|
|
||||||
|
box_layout_stretch.addItem(stretch_widget, 1);
|
||||||
|
box_layout_stretch.addItem(fast_stretch, 2);
|
||||||
|
|
||||||
|
box_layout_stretch.setGeometry(SGRecti(0,0,128,32));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 41, 32));
|
||||||
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(46, 0, 82, 32));
|
||||||
|
|
||||||
|
box_layout_stretch.setGeometry(SGRecti(0,0,256,32));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 123, 32));
|
||||||
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
|
||||||
|
|
||||||
|
// Test superflous space to padding
|
||||||
|
box_layout_stretch.setGeometry(SGRecti(0,0,512,32));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(83, 0, 128, 32));
|
||||||
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
|
||||||
|
|
||||||
|
// Test more space then preferred, but less than maximum
|
||||||
|
{
|
||||||
|
sc::HBoxLayout hbox;
|
||||||
|
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||||
|
SGVec2i(32, 32),
|
||||||
|
SGVec2i(9999, 32) ) ),
|
||||||
|
w2( new TestWidget(*w1) );
|
||||||
|
|
||||||
|
hbox.addItem(w1);
|
||||||
|
hbox.addItem(w2);
|
||||||
|
|
||||||
|
hbox.setGeometry( SGRecti(0, 0, 256, 32) );
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
|
||||||
|
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
|
||||||
|
|
||||||
|
hbox.setStretch(0, 1);
|
||||||
|
hbox.setStretch(1, 1);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(hbox.stretch(0), 1);
|
||||||
|
BOOST_CHECK_EQUAL(hbox.stretch(1), 1);
|
||||||
|
|
||||||
|
hbox.update();
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
|
||||||
|
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BOOST_AUTO_TEST_CASE( vertical_layout)
|
||||||
|
{
|
||||||
|
sc::BoxLayout vbox(sc::BoxLayout::TopToBottom);
|
||||||
|
vbox.setSpacing(7);
|
||||||
|
|
||||||
|
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
|
SGVec2i(16, 16),
|
||||||
|
SGVec2i(16, 16) ) );
|
||||||
|
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
|
SGVec2i(32, 32),
|
||||||
|
SGVec2i(256, 64) ) );
|
||||||
|
|
||||||
|
vbox.addItem(fixed_size_widget);
|
||||||
|
vbox.addItem(limited_resize_widget);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(vbox.minimumSize(), SGVec2i(16, 39));
|
||||||
|
BOOST_CHECK_EQUAL(vbox.sizeHint(), SGVec2i(32, 55));
|
||||||
|
BOOST_CHECK_EQUAL(vbox.maximumSize(), SGVec2i(256, 87));
|
||||||
|
|
||||||
|
vbox.setGeometry(SGRecti(10, 20, 16, 55));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(10, 20, 16, 16));
|
||||||
|
BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(10, 43, 16, 32));
|
||||||
|
|
||||||
|
vbox.setDirection(sc::BoxLayout::BottomToTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BOOST_AUTO_TEST_CASE( nasal_layout )
|
||||||
|
{
|
||||||
|
naContext c = naNewContext();
|
||||||
|
naRef me = naNewHash(c);
|
||||||
|
|
||||||
|
sc::LayoutItemRef nasal_item( new sc::NasalWidget(me) );
|
||||||
|
|
||||||
|
naFreeContext(c);
|
||||||
|
}
|
||||||
@@ -31,7 +31,8 @@ typedef enum {
|
|||||||
SG_ENVIRONMENT = 0x00100000,
|
SG_ENVIRONMENT = 0x00100000,
|
||||||
SG_SOUND = 0x00200000,
|
SG_SOUND = 0x00200000,
|
||||||
SG_NAVAID = 0x00400000,
|
SG_NAVAID = 0x00400000,
|
||||||
SG_UNDEFD = 0x00800000, // For range checking
|
SG_GUI = 0x00800000,
|
||||||
|
SG_UNDEFD = 0x01000000, // For range checking
|
||||||
|
|
||||||
SG_ALL = 0xFFFFFFFF
|
SG_ALL = 0xFFFFFFFF
|
||||||
} sgDebugClass;
|
} sgDebugClass;
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ const char* debugClassToString(sgDebugClass c)
|
|||||||
case SG_ENVIRONMENT:return "environment";
|
case SG_ENVIRONMENT:return "environment";
|
||||||
case SG_SOUND: return "sound";
|
case SG_SOUND: return "sound";
|
||||||
case SG_NAVAID: return "navaid";
|
case SG_NAVAID: return "navaid";
|
||||||
|
case SG_GUI: return "gui";
|
||||||
default: return "unknown";
|
default: return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -438,4 +439,4 @@ void requestConsole()
|
|||||||
global_privateLogstream->requestConsole();
|
global_privateLogstream->requestConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // of namespace simgear
|
} // of namespace simgear
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace simgear
|
|||||||
*/
|
*/
|
||||||
class PropertyBasedElement:
|
class PropertyBasedElement:
|
||||||
public SGPropertyChangeListener,
|
public SGPropertyChangeListener,
|
||||||
public SGWeakReferenced
|
public virtual SGVirtualWeakReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PropertyBasedElement(SGPropertyNode* node);
|
PropertyBasedElement(SGPropertyNode* node);
|
||||||
|
|||||||
Reference in New Issue
Block a user