mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-16 11:46:25 +01:00
add a very (very) basic resize/layout design to the canvas
Items call ::queue_resize(), which sets a flag in the canvas; at next idle, we call Canvas::layout() which walks the item tree and recursively calls layout (depth first) on all items needing a resize. Only Container types implement layout, and so far only Box
This commit is contained in:
parent
03e32a22d0
commit
12b4807bc9
6 changed files with 197 additions and 99 deletions
|
|
@ -19,54 +19,55 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include "pbd/unwind.h"
|
||||
|
||||
#include "canvas/box.h"
|
||||
#include "canvas/rectangle.h"
|
||||
|
||||
using namespace ArdourCanvas;
|
||||
|
||||
Box::Box (Canvas* canvas, Orientation o)
|
||||
: Item (canvas)
|
||||
: Rectangle (canvas)
|
||||
, orientation (o)
|
||||
, spacing (0)
|
||||
, top_padding (0), right_padding (0), bottom_padding (0), left_padding (0)
|
||||
, top_margin (0), right_margin (0), bottom_margin (0), left_margin (0)
|
||||
, homogenous (false)
|
||||
, ignore_child_changes (false)
|
||||
{
|
||||
self = new Rectangle (this);
|
||||
self->set_outline (false);
|
||||
self->set_fill (false);
|
||||
}
|
||||
|
||||
Box::Box (Item* parent, Orientation o)
|
||||
: Item (parent)
|
||||
: Rectangle (parent)
|
||||
, orientation (o)
|
||||
, spacing (0)
|
||||
, top_padding (0), right_padding (0), bottom_padding (0), left_padding (0)
|
||||
, top_margin (0), right_margin (0), bottom_margin (0), left_margin (0)
|
||||
, homogenous (false)
|
||||
, ignore_child_changes (false)
|
||||
{
|
||||
self = new Rectangle (this);
|
||||
self->set_outline (false);
|
||||
self->set_fill (false);
|
||||
}
|
||||
|
||||
|
||||
Box::Box (Item* parent, Duple const & p, Orientation o)
|
||||
: Item (parent, p)
|
||||
: Rectangle (parent)
|
||||
, orientation (o)
|
||||
, spacing (0)
|
||||
, top_padding (0), right_padding (0), bottom_padding (0), left_padding (0)
|
||||
, top_margin (0), right_margin (0), bottom_margin (0), left_margin (0)
|
||||
, homogenous (false)
|
||||
, ignore_child_changes (false)
|
||||
{
|
||||
self = new Rectangle (this);
|
||||
self->set_outline (false);
|
||||
self->set_fill (false);
|
||||
set_position (p);
|
||||
}
|
||||
|
||||
void
|
||||
Box::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
|
||||
{
|
||||
if (_fill || _outline) {
|
||||
Rectangle::render (area, context);
|
||||
}
|
||||
|
||||
Item::render_children (area, context);
|
||||
}
|
||||
|
||||
|
|
@ -85,10 +86,14 @@ Box::compute_bounding_box () const
|
|||
if (_bounding_box) {
|
||||
Rect r = _bounding_box;
|
||||
|
||||
_bounding_box = r.expand (top_padding + outline_width() + top_margin,
|
||||
/* left and top margin and padding is already built into the
|
||||
* position of children
|
||||
*/
|
||||
|
||||
_bounding_box = r.expand (0.0,
|
||||
right_padding + outline_width() + right_margin,
|
||||
bottom_padding + outline_width() + bottom_margin,
|
||||
left_padding + outline_width() + left_margin);
|
||||
0.0);
|
||||
}
|
||||
|
||||
_bounding_box_dirty = false;
|
||||
|
|
@ -140,36 +145,17 @@ Box::set_margin (double t, double r, double b, double l)
|
|||
left_margin = last;
|
||||
}
|
||||
|
||||
void
|
||||
Box::reset_self ()
|
||||
{
|
||||
if (_bounding_box_dirty) {
|
||||
compute_bounding_box ();
|
||||
}
|
||||
|
||||
if (!_bounding_box) {
|
||||
self->hide ();
|
||||
return;
|
||||
}
|
||||
|
||||
Rect r (_bounding_box);
|
||||
|
||||
/* XXX need to shrink by margin */
|
||||
|
||||
self->set (r);
|
||||
}
|
||||
|
||||
void
|
||||
Box::reposition_children ()
|
||||
{
|
||||
Duple previous_edge (0, 0);
|
||||
Duple previous_edge = Duple (left_margin+left_padding, top_margin+top_padding);
|
||||
Distance largest_width = 0;
|
||||
Distance largest_height = 0;
|
||||
Rect uniform_size;
|
||||
|
||||
if (homogenous) {
|
||||
|
||||
for (std::list<Item*>::iterator i = _items.begin(); ++i != _items.end(); ++i) {
|
||||
for (std::list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
|
||||
Rect bb = (*i)->bounding_box();
|
||||
if (bb) {
|
||||
largest_height = std::max (largest_height, bb.height());
|
||||
|
|
@ -180,88 +166,99 @@ Box::reposition_children ()
|
|||
uniform_size = Rect (0, 0, largest_width, largest_height);
|
||||
}
|
||||
|
||||
for (std::list<Item*>::iterator i = _items.begin(); ++i != _items.end(); ++i) {
|
||||
{
|
||||
|
||||
(*i)->set_position (previous_edge);
|
||||
PBD::Unwinder<bool> uw (ignore_child_changes, true);
|
||||
|
||||
if (homogenous) {
|
||||
(*i)->size_allocate (uniform_size);
|
||||
}
|
||||
for (std::list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
|
||||
|
||||
if (orientation == Vertical) {
|
||||
(*i)->set_position (previous_edge);
|
||||
|
||||
Distance shift = 0;
|
||||
|
||||
Rect bb = (*i)->bounding_box();
|
||||
|
||||
if (!(*i)->visible()) {
|
||||
/* invisible child */
|
||||
if (!collapse_on_hide) {
|
||||
/* still add in its size */
|
||||
if (bb) {
|
||||
shift += bb.height();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (bb) {
|
||||
shift += bb.height();
|
||||
}
|
||||
if (homogenous) {
|
||||
(*i)->size_allocate (uniform_size);
|
||||
}
|
||||
|
||||
previous_edge = previous_edge.translate (Duple (0, spacing + shift));
|
||||
double width;
|
||||
double height;
|
||||
|
||||
} else {
|
||||
(*i)->size_request (width, height);
|
||||
|
||||
Distance shift = 0;
|
||||
Rect bb = (*i)->bounding_box();
|
||||
if (orientation == Vertical) {
|
||||
|
||||
if (!(*i)->visible()) {
|
||||
if (!collapse_on_hide) {
|
||||
if (bb) {
|
||||
shift += bb.width();
|
||||
Distance shift = 0;
|
||||
|
||||
if (!(*i)->visible()) {
|
||||
/* invisible child */
|
||||
if (!collapse_on_hide) {
|
||||
/* still add in its size */
|
||||
shift += height;
|
||||
}
|
||||
} else {
|
||||
shift += height;
|
||||
}
|
||||
} else {
|
||||
if (bb) {
|
||||
shift += bb.width();
|
||||
}
|
||||
}
|
||||
|
||||
previous_edge = previous_edge.translate (Duple (spacing + shift, 0));
|
||||
previous_edge = previous_edge.translate (Duple (0, spacing + shift));
|
||||
|
||||
} else {
|
||||
|
||||
Distance shift = 0;
|
||||
|
||||
if (!(*i)->visible()) {
|
||||
if (!collapse_on_hide) {
|
||||
shift += width;
|
||||
}
|
||||
} else {
|
||||
shift += width;
|
||||
}
|
||||
|
||||
previous_edge = previous_edge.translate (Duple (spacing + shift, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_bounding_box_dirty = true;
|
||||
reset_self ();
|
||||
}
|
||||
|
||||
void
|
||||
Box::pack_end (Item* i, double extra_padding)
|
||||
{
|
||||
if (!i) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* prepend new child */
|
||||
Item::add_front (i);
|
||||
reposition_children ();
|
||||
}
|
||||
void
|
||||
Box::pack_start (Item* i, double extra_padding)
|
||||
{
|
||||
if (!i) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* append new child */
|
||||
Item::add (i);
|
||||
reposition_children ();
|
||||
}
|
||||
|
||||
void
|
||||
Box::add (Item* i)
|
||||
{
|
||||
pack_start (i);
|
||||
if (!i) {
|
||||
return;
|
||||
}
|
||||
|
||||
Item::add (i);
|
||||
queue_resize ();
|
||||
}
|
||||
|
||||
void
|
||||
Box::add_front (Item* i)
|
||||
{
|
||||
if (!i) {
|
||||
return;
|
||||
}
|
||||
|
||||
Item::add_front (i);
|
||||
queue_resize ();
|
||||
}
|
||||
|
||||
void
|
||||
Box::layout ()
|
||||
{
|
||||
bool yes_do_it = _resize_queued;
|
||||
|
||||
Item::layout ();
|
||||
|
||||
if (yes_do_it) {
|
||||
reposition_children ();
|
||||
compute_bounding_box ();
|
||||
|
||||
const double w = std::max (requested_width, _bounding_box.width());
|
||||
const double h = std::max (requested_height, _bounding_box.height());
|
||||
|
||||
set (Rect (get().x0, get().y0, get().x0 + w, get().y0 + h));
|
||||
|
||||
std::cerr << name << " box layed out, reset to " << get() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -269,7 +266,12 @@ Box::child_changed (bool bbox_changed)
|
|||
{
|
||||
/* catch visibility and size changes */
|
||||
|
||||
if (ignore_child_changes) {
|
||||
return;
|
||||
}
|
||||
|
||||
Item::child_changed (bbox_changed);
|
||||
|
||||
reposition_children ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -454,6 +454,7 @@ GtkCanvas::GtkCanvas ()
|
|||
, current_tooltip_item (0)
|
||||
, tooltip_window (0)
|
||||
, _in_dtor (false)
|
||||
, resize_queued (false)
|
||||
, _nsglview (0)
|
||||
{
|
||||
#ifdef USE_CAIRO_IMAGE_SURFACE /* usually Windows builds */
|
||||
|
|
@ -1457,6 +1458,23 @@ GtkCanvas::get_pango_context ()
|
|||
return Glib::wrap (gdk_pango_context_get());
|
||||
}
|
||||
|
||||
void
|
||||
GtkCanvas::queue_resize ()
|
||||
{
|
||||
if (!resize_queued) {
|
||||
Glib::signal_idle().connect (sigc::mem_fun (*this, &GtkCanvas::resize_handler));
|
||||
resize_queued = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
GtkCanvas::resize_handler ()
|
||||
{
|
||||
resize_queued = false;
|
||||
_root.layout ();
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Create a GtkCanvaSViewport.
|
||||
* @param hadj Adjustment to use for horizontal scrolling.
|
||||
* @param vadj Adjustment to use for vertica scrolling.
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ public:
|
|||
void set_border_color (Gtkmm2ext::Color c) { set_outline_color (c); }
|
||||
|
||||
void add (Item*);
|
||||
void pack_start (Item*, double extra_padding = 0);
|
||||
void pack_end (Item*, double extra_padding = 0);
|
||||
void add_front (Item*);
|
||||
void layout ();
|
||||
|
||||
void set_collapse_on_hide (bool);
|
||||
void set_homogenous (bool);
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ public:
|
|||
virtual void grab (Item *) = 0;
|
||||
/** called to ask the canvas' host to `ungrab' any grabbed item */
|
||||
virtual void ungrab () = 0;
|
||||
/** called to ask for a resize/relayout of all or part of the canvas */
|
||||
virtual void queue_resize () = 0;
|
||||
|
||||
/** called to ask the canvas' host to keyboard focus on an item */
|
||||
virtual void focus (Item *) = 0;
|
||||
|
|
@ -187,6 +189,7 @@ protected:
|
|||
static uint32_t tooltip_timeout_msecs;
|
||||
|
||||
void queue_draw_item_area (Item *, Rect);
|
||||
|
||||
virtual void pick_current_item (int state) = 0;
|
||||
virtual void pick_current_item (Duple const &, int state) = 0;
|
||||
|
||||
|
|
@ -227,6 +230,7 @@ public:
|
|||
|
||||
void queue_draw ();
|
||||
void queue_draw_area (int x, int y, int width, int height);
|
||||
void queue_resize ();
|
||||
|
||||
Glib::RefPtr<Pango::Context> get_pango_context();
|
||||
|
||||
|
|
@ -288,8 +292,10 @@ private:
|
|||
bool show_tooltip ();
|
||||
void hide_tooltip ();
|
||||
bool really_start_tooltip_timeout ();
|
||||
bool resize_handler ();
|
||||
|
||||
bool _in_dtor;
|
||||
bool resize_queued;
|
||||
|
||||
void* _nsglview;
|
||||
Cairo::RefPtr<Cairo::Surface> _canvas_image;
|
||||
|
|
|
|||
|
|
@ -272,7 +272,20 @@ public:
|
|||
virtual void dump (std::ostream&) const;
|
||||
std::string whatami() const;
|
||||
|
||||
protected:
|
||||
bool resize_queued() const { return _resize_queued; }
|
||||
void queue_resize();
|
||||
|
||||
/* only derived containers need to implement this, but this
|
||||
is where they compute the sizes and position and their
|
||||
children. A fixed-layout container (i.e. one where every child
|
||||
has just had its position fixed via ::set_position()) does not
|
||||
need to do anything here. Only box/table/grid style containers,
|
||||
where the position of one child depends on the position and size of
|
||||
other children, need to provide an implementation.
|
||||
*/
|
||||
virtual void layout();
|
||||
|
||||
protected:
|
||||
friend class Fill;
|
||||
friend class Outline;
|
||||
|
||||
|
|
@ -335,6 +348,10 @@ protected:
|
|||
public:
|
||||
Duple position_offset() const;
|
||||
|
||||
bool _resize_queued;
|
||||
double requested_width;
|
||||
double requested_height;
|
||||
|
||||
private:
|
||||
void init ();
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ Item::Item (Canvas* canvas)
|
|||
, _intrinsic_width (-1.)
|
||||
, _intrinsic_height(-1.)
|
||||
, _lut (0)
|
||||
, _resize_queued (false)
|
||||
, requested_width (-1)
|
||||
, requested_height (-1)
|
||||
, _ignore_events (false)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::CanvasItems, string_compose ("new canvas item %1\n", this));
|
||||
|
|
@ -63,6 +66,9 @@ Item::Item (Item* parent)
|
|||
, _intrinsic_width (-1.)
|
||||
, _intrinsic_height(-1.)
|
||||
, _lut (0)
|
||||
, _resize_queued (false)
|
||||
, requested_width (-1)
|
||||
, requested_height (-1)
|
||||
, _ignore_events (false)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::CanvasItems, string_compose ("new canvas item %1\n", this));
|
||||
|
|
@ -86,6 +92,7 @@ Item::Item (Item* parent, Duple const& p)
|
|||
, _intrinsic_width (-1.)
|
||||
, _intrinsic_height(-1.)
|
||||
, _lut (0)
|
||||
, _resize_queued (false)
|
||||
, _ignore_events (false)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::CanvasItems, string_compose ("new canvas item %1\n", this));
|
||||
|
|
@ -292,6 +299,18 @@ Item::set_position (Duple p)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Item::layout()
|
||||
{
|
||||
for (list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
|
||||
if ((*i)->resize_queued()) {
|
||||
(*i)->layout ();
|
||||
}
|
||||
}
|
||||
|
||||
_resize_queued = false;
|
||||
}
|
||||
|
||||
void
|
||||
Item::set_x_position (Coord x)
|
||||
{
|
||||
|
|
@ -590,6 +609,28 @@ Item::size_allocate (Rect const & r)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Item::size_request (double& w, double& h) const
|
||||
{
|
||||
Rect r (bounding_box());
|
||||
|
||||
w = std::max (requested_width, r.width());
|
||||
h = std::max (requested_height, r.height());
|
||||
}
|
||||
|
||||
void
|
||||
Item::set_size_request (double w, double h)
|
||||
{
|
||||
/* allow reset to zero or require that both are positive */
|
||||
|
||||
begin_change ();
|
||||
requested_width = w;
|
||||
requested_height = h;
|
||||
_bounding_box_dirty = true;
|
||||
end_change ();
|
||||
}
|
||||
|
||||
|
||||
/** @return Bounding box in this item's coordinates */
|
||||
ArdourCanvas::Rect
|
||||
Item::bounding_box () const
|
||||
|
|
@ -916,6 +957,20 @@ Rect self;
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Item::queue_resize()
|
||||
{
|
||||
_resize_queued = true;
|
||||
|
||||
if (_parent) {
|
||||
_parent->queue_resize ();
|
||||
}
|
||||
|
||||
if (this == _canvas->root()) {
|
||||
_canvas->queue_resize ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Item::add (Item* i)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue