mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 07:14:56 +01:00
add/update constraint packing containers, test code
This commit is contained in:
parent
606866ea00
commit
a3039d3895
8 changed files with 1232 additions and 73 deletions
87
libs/canvas/canvas/cbox.h
Normal file
87
libs/canvas/canvas/cbox.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Carl Hetherington <carl@carlh.net>
|
||||
* Copyright (C) 2016 Paul Davis <paul@linuxaudiosystems.com>
|
||||
* Copyright (C) 2017 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __CANVAS_CBOX_H__
|
||||
#define __CANVAS_CBOX_H__
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "canvas/constraint_packer.h"
|
||||
|
||||
namespace ArdourCanvas
|
||||
{
|
||||
|
||||
class Rectangle;
|
||||
class BoxConstrainedItem;
|
||||
|
||||
class LIBCANVAS_API cBox : public ConstraintPacker
|
||||
{
|
||||
public:
|
||||
cBox (Canvas *, Orientation);
|
||||
cBox (Item *, Orientation);
|
||||
|
||||
void set_spacing (double s);
|
||||
void set_padding (double top, double right = -1.0, double bottom = -1.0, double left = -1.0);
|
||||
void set_margin (double top, double right = -1.0, double bottom = -1.0, double left = -1.0);
|
||||
|
||||
/* aliases so that CSS box model terms work */
|
||||
void set_border_width (double w) { set_outline_width (w); }
|
||||
void set_border_color (Gtkmm2ext::Color c) { set_outline_color (c); }
|
||||
|
||||
void remove (Item*);
|
||||
|
||||
BoxConstrainedItem* pack_start (Item*, PackOptions primary_axis_packing = PackOptions (0), PackOptions secondary_axis_packing = PackOptions (PackExpand|PackFill));
|
||||
BoxConstrainedItem* pack_end (Item*, PackOptions primary_axis_packing = PackOptions (0), PackOptions secondary_axis_packing = PackOptions (PackExpand|PackFill));
|
||||
|
||||
void set_collapse_on_hide (bool);
|
||||
void set_homogenous (bool);
|
||||
|
||||
void preferred_size(Duple& minimum, Duple& natural) const;
|
||||
void size_allocate (Rect const &);
|
||||
|
||||
ConstrainedItem* add_constrained (Item*);
|
||||
|
||||
protected:
|
||||
Orientation orientation;
|
||||
|
||||
double _spacing;
|
||||
double _top_padding;
|
||||
double _bottom_padding;
|
||||
double _left_padding;
|
||||
double _right_padding;
|
||||
double _top_margin;
|
||||
double _bottom_margin;
|
||||
double _left_margin;
|
||||
double _right_margin;
|
||||
|
||||
void child_changed (bool bbox_changed);
|
||||
|
||||
private:
|
||||
typedef std::list<BoxConstrainedItem*> Order;
|
||||
Order order;
|
||||
bool collapse_on_hide;
|
||||
bool homogenous;
|
||||
|
||||
BoxConstrainedItem* pack (Item*, PackOptions primary_axis_packing, PackOptions secondary_axis_packing);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* __CANVAS_CBOX_H__ */
|
||||
119
libs/canvas/canvas/constrained_item.h
Normal file
119
libs/canvas/canvas/constrained_item.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __CANVAS_CONSTRAINED_ITEM_H__
|
||||
#define __CANVAS_CONSTRAINED_ITEM_H__
|
||||
|
||||
#include "kiwi/kiwi.h"
|
||||
|
||||
#include "canvas/types.h"
|
||||
#include "canvas/visibility.h"
|
||||
|
||||
namespace ArdourCanvas
|
||||
{
|
||||
|
||||
class Item;
|
||||
class ConstraintPacker;
|
||||
|
||||
|
||||
class /* LIBCANVAS_API */ ConstrainedItem
|
||||
{
|
||||
public:
|
||||
ConstrainedItem (Item& i);
|
||||
virtual ~ConstrainedItem ();
|
||||
|
||||
Item& item() { return _item; }
|
||||
|
||||
kiwi::Variable& left () { return _left; }
|
||||
kiwi::Variable& right () { return _right; }
|
||||
kiwi::Variable& top () { return _top; }
|
||||
kiwi::Variable& bottom () { return _bottom; }
|
||||
kiwi::Variable& width () { return _width; }
|
||||
kiwi::Variable& height () { return _height; }
|
||||
|
||||
void constrained (ConstraintPacker const & parent);
|
||||
virtual bool involved (kiwi::Constraint const &) const;
|
||||
|
||||
std::vector<kiwi::Constraint> const & constraints() const { return _constraints; }
|
||||
void add_constraint (kiwi::Constraint const & c) { _constraints.push_back (c); }
|
||||
|
||||
protected:
|
||||
Item& _item;
|
||||
std::vector<kiwi::Constraint> _constraints;
|
||||
|
||||
kiwi::Variable _left;
|
||||
kiwi::Variable _right;
|
||||
kiwi::Variable _top;
|
||||
kiwi::Variable _bottom;
|
||||
kiwi::Variable _width;
|
||||
kiwi::Variable _height;
|
||||
|
||||
virtual void dump (std::ostream&);
|
||||
};
|
||||
|
||||
class /* LIBCANVAS_API */ BoxConstrainedItem : public ConstrainedItem
|
||||
{
|
||||
public:
|
||||
BoxConstrainedItem (Item& i, PackOptions primary_axis_opts, PackOptions secondary_axis_opts);
|
||||
~BoxConstrainedItem ();
|
||||
|
||||
virtual bool involved (kiwi::Constraint const &) const;
|
||||
|
||||
kiwi::Variable& center_x () { return _center_x; }
|
||||
kiwi::Variable& center_y () { return _center_y; }
|
||||
kiwi::Variable& left_margin () { return _left_margin; }
|
||||
kiwi::Variable& right_margin () { return _right_margin; }
|
||||
kiwi::Variable& top_margin () { return _top_margin; }
|
||||
kiwi::Variable& bottom_margin () { return _bottom_margin; }
|
||||
|
||||
/* Padding is not for use by items or anyone except the parent
|
||||
* (constraint) container. It is used to space out items that are set
|
||||
* to expand inside a container but not to "fill" (i.e. the extra space
|
||||
* is assigned to padding around the item, not the item itself).
|
||||
*/
|
||||
|
||||
kiwi::Variable& left_padding () { return _left_padding; }
|
||||
kiwi::Variable& right_padding () { return _right_padding; }
|
||||
kiwi::Variable& top_padding () { return _top_padding; }
|
||||
kiwi::Variable& bottom_padding () { return _bottom_padding; }
|
||||
|
||||
PackOptions primary_axis_pack_options() const { return _primary_axis_pack_options; }
|
||||
PackOptions secondary_axis_pack_options() const { return _secondary_axis_pack_options; }
|
||||
|
||||
void dump (std::ostream&);
|
||||
|
||||
private:
|
||||
kiwi::Variable _center_x;
|
||||
kiwi::Variable _center_y;
|
||||
kiwi::Variable _left_margin;
|
||||
kiwi::Variable _right_margin;
|
||||
kiwi::Variable _top_margin;
|
||||
kiwi::Variable _bottom_margin;
|
||||
kiwi::Variable _left_padding;
|
||||
kiwi::Variable _right_padding;
|
||||
kiwi::Variable _top_padding;
|
||||
kiwi::Variable _bottom_padding;
|
||||
|
||||
PackOptions _primary_axis_pack_options;
|
||||
PackOptions _secondary_axis_pack_options;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -19,7 +19,10 @@
|
|||
#ifndef __CANVAS_CONSTRAINT_PACKER_H__
|
||||
#define __CANVAS_CONSTRAINT_PACKER_H__
|
||||
|
||||
#include "canvas/item.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "canvas/container.h"
|
||||
#include "kiwi/kiwi.h"
|
||||
|
||||
namespace ArdourCanvas
|
||||
|
|
@ -28,40 +31,43 @@ namespace ArdourCanvas
|
|||
class Rectangle;
|
||||
class ConstrainedItem;
|
||||
|
||||
class LIBCANVAS_API ConstraintPacker : public Item
|
||||
class LIBCANVAS_API ConstraintPacker : public Container
|
||||
{
|
||||
public:
|
||||
ConstraintPacker (Canvas *);
|
||||
ConstraintPacker (Item *);
|
||||
|
||||
void add (Item *);
|
||||
void add_front (Item *);
|
||||
void remove (Item *);
|
||||
void constrain (kiwi::Constraint const &);
|
||||
|
||||
virtual ConstrainedItem* add_constrained (Item* item);
|
||||
|
||||
void solve ();
|
||||
void apply ();
|
||||
void apply (kiwi::Solver*);
|
||||
|
||||
void compute_bounding_box () const;
|
||||
void render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const;
|
||||
|
||||
void preferred_size (Duple& mininum, Duple& natural) const;
|
||||
void size_allocate (Rect const &);
|
||||
|
||||
protected:
|
||||
void child_changed ();
|
||||
|
||||
private:
|
||||
typedef std::map<Item*,ConstrainedItem*> ConstraintMap;
|
||||
ConstraintMap constraint_map;
|
||||
|
||||
kiwi::Solver _solver;
|
||||
kiwi::Variable width;
|
||||
kiwi::Variable height;
|
||||
|
||||
Rectangle *self;
|
||||
bool collapse_on_hide;
|
||||
protected:
|
||||
void child_changed (bool bbox_changed);
|
||||
|
||||
void reset_self ();
|
||||
void reposition_children ();
|
||||
typedef std::map<Item*,ConstrainedItem*> ConstrainedItemMap;
|
||||
ConstrainedItemMap constrained_map;
|
||||
typedef std::list<kiwi::Constraint> ConstraintList;
|
||||
ConstraintList constraint_list;
|
||||
|
||||
bool in_alloc;
|
||||
|
||||
void add_constrained_internal (Item*, ConstrainedItem*);
|
||||
|
||||
void add_constraints (kiwi::Solver&, ConstrainedItem*) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
486
libs/canvas/cbox.cc
Normal file
486
libs/canvas/cbox.cc
Normal file
|
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "pbd/unwind.h"
|
||||
|
||||
#include "canvas/canvas.h"
|
||||
#include "canvas/cbox.h"
|
||||
#include "canvas/constrained_item.h"
|
||||
|
||||
using namespace ArdourCanvas;
|
||||
using namespace kiwi;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
cBox::cBox (Canvas* c, Orientation o)
|
||||
: ConstraintPacker (c)
|
||||
, orientation (o)
|
||||
, _spacing (0)
|
||||
, _top_padding (0)
|
||||
, _bottom_padding (0)
|
||||
, _left_padding (0)
|
||||
, _right_padding (0)
|
||||
, _top_margin (0)
|
||||
, _bottom_margin (0)
|
||||
, _left_margin (0)
|
||||
, _right_margin (0)
|
||||
, collapse_on_hide (false)
|
||||
, homogenous (true)
|
||||
{
|
||||
}
|
||||
|
||||
cBox::cBox (Item* i, Orientation o)
|
||||
: ConstraintPacker (i)
|
||||
, orientation (o)
|
||||
, _spacing (0)
|
||||
, _top_padding (0)
|
||||
, _bottom_padding (0)
|
||||
, _left_padding (0)
|
||||
, _right_padding (0)
|
||||
, _top_margin (0)
|
||||
, _bottom_margin (0)
|
||||
, _left_margin (0)
|
||||
, _right_margin (0)
|
||||
, collapse_on_hide (false)
|
||||
, homogenous (true)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
cBox::set_spacing (double s)
|
||||
{
|
||||
_spacing = s;
|
||||
}
|
||||
|
||||
void
|
||||
cBox::set_padding (double top, double right, double bottom, double left)
|
||||
{
|
||||
double last = top;
|
||||
|
||||
_top_padding = last;
|
||||
|
||||
if (right >= 0) {
|
||||
last = right;
|
||||
}
|
||||
_right_padding = last;
|
||||
|
||||
if (bottom >= 0) {
|
||||
last = bottom;
|
||||
}
|
||||
_bottom_padding = last;
|
||||
|
||||
if (left >= 0) {
|
||||
last = left;
|
||||
}
|
||||
_left_padding = last;
|
||||
}
|
||||
|
||||
void
|
||||
cBox::set_margin (double top, double right, double bottom, double left)
|
||||
{
|
||||
double last = top;
|
||||
|
||||
_top_margin = last;
|
||||
|
||||
if (right >= 0) {
|
||||
last = right;
|
||||
}
|
||||
_right_margin = last;
|
||||
|
||||
if (bottom >= 0) {
|
||||
last = bottom;
|
||||
}
|
||||
_bottom_margin = last;
|
||||
|
||||
if (left >= 0) {
|
||||
last = left;
|
||||
}
|
||||
_left_margin = last;
|
||||
}
|
||||
|
||||
void
|
||||
cBox::remove (Item* item)
|
||||
{
|
||||
for (Order::iterator t = order.begin(); t != order.end(); ++t) {
|
||||
if (&(*t)->item() == item) {
|
||||
order.erase (t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ConstraintPacker::remove (item);
|
||||
}
|
||||
|
||||
ConstrainedItem*
|
||||
cBox::add_constrained (Item* item)
|
||||
{
|
||||
return pack (item, PackOptions (0), PackOptions (PackExpand|PackFill));
|
||||
}
|
||||
|
||||
BoxConstrainedItem*
|
||||
cBox::pack_start (Item* item, PackOptions primary_axis_opts, PackOptions secondary_axis_opts)
|
||||
{
|
||||
return pack (item, PackOptions (primary_axis_opts|PackFromStart), secondary_axis_opts);
|
||||
}
|
||||
|
||||
BoxConstrainedItem*
|
||||
cBox::pack_end (Item* item, PackOptions primary_axis_opts, PackOptions secondary_axis_opts)
|
||||
{
|
||||
return pack (item, PackOptions (primary_axis_opts|PackFromEnd), secondary_axis_opts);
|
||||
}
|
||||
|
||||
BoxConstrainedItem*
|
||||
cBox::pack (Item* item, PackOptions primary_axis_opts, PackOptions secondary_axis_opts)
|
||||
{
|
||||
BoxConstrainedItem* ci = new BoxConstrainedItem (*item, primary_axis_opts, secondary_axis_opts);
|
||||
|
||||
add_constrained_internal (item, ci);
|
||||
order.push_back (ci);
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
void
|
||||
cBox::preferred_size (Duple& min, Duple& natural) const
|
||||
{
|
||||
Order::size_type n_expanding = 0;
|
||||
Order::size_type n_nonexpanding = 0;
|
||||
Order::size_type total = 0;
|
||||
Distance non_expanding_used = 0;
|
||||
Distance largest = 0;
|
||||
Distance largest_opposite = 0;
|
||||
Duple i_min, i_natural;
|
||||
|
||||
cerr << "cbox::prefsize (" << (orientation == Vertical ? " vert) " : " horiz) ") << endl;
|
||||
|
||||
for (Order::const_iterator o = order.begin(); o != order.end(); ++o) {
|
||||
|
||||
(*o)->item().preferred_size (i_min, i_natural);
|
||||
|
||||
cerr << '\t' << (*o)->item().debug_name() << " min " << i_min << " nat " << i_natural << endl;
|
||||
|
||||
if ((*o)->primary_axis_pack_options() & PackExpand) {
|
||||
n_expanding++;
|
||||
|
||||
if (orientation == Vertical) {
|
||||
if (i_natural.height() > largest) {
|
||||
largest = i_natural.height();
|
||||
}
|
||||
if (i_natural.width() > largest) {
|
||||
largest_opposite = i_natural.width();
|
||||
}
|
||||
} else {
|
||||
if (i_natural.width() > largest) {
|
||||
largest = i_natural.width();
|
||||
}
|
||||
if (i_natural.height() > largest) {
|
||||
largest_opposite = i_natural.height();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
n_nonexpanding++;
|
||||
|
||||
if (orientation == Vertical) {
|
||||
if (i_natural.height() > 0) {
|
||||
non_expanding_used += i_natural.height();
|
||||
} else {
|
||||
non_expanding_used += i_min.height();
|
||||
}
|
||||
} else {
|
||||
if (i_natural.width() > 0) {
|
||||
non_expanding_used += i_natural.width();
|
||||
} else {
|
||||
non_expanding_used += i_min.width();
|
||||
}
|
||||
}
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
Duple r;
|
||||
|
||||
if (orientation == Vertical) {
|
||||
cerr << "+++ vertical box, neu = " << non_expanding_used << " largest = " << largest << " opp " << largest_opposite << " total " << total << endl;
|
||||
min.x = non_expanding_used + (n_expanding * largest_opposite) + _left_margin + _right_margin + ((total - 1) * _spacing);
|
||||
min.y = non_expanding_used + (n_expanding * largest) + _top_margin + _bottom_margin + ((total - 1) * _spacing);
|
||||
} else {
|
||||
cerr << "+++ horiz box, neu = " << non_expanding_used << " largest = " << largest << " opp " << largest_opposite << " total " << total << endl;
|
||||
min.x = non_expanding_used + (n_expanding * largest) + _left_margin + _right_margin + ((total - 1) * _spacing);
|
||||
min.y = non_expanding_used + (n_expanding * largest_opposite) + _top_margin + _bottom_margin + ((total - 1) * _spacing);
|
||||
|
||||
}
|
||||
|
||||
cerr << "++++ " << debug_name() << " rpref " << min << endl;
|
||||
|
||||
natural = min;
|
||||
}
|
||||
|
||||
void
|
||||
cBox::size_allocate (Rect const & r)
|
||||
{
|
||||
PBD::Unwinder<bool> uw (in_alloc, true);
|
||||
|
||||
Item::size_allocate (r);
|
||||
|
||||
kiwi::Solver solver;
|
||||
|
||||
double expanded_size;
|
||||
Order::size_type n_expanding = 0;
|
||||
Order::size_type n_nonexpanding = 0;
|
||||
Order::size_type total = 0;
|
||||
Distance non_expanding_used = 0;
|
||||
|
||||
for (Order::iterator o = order.begin(); o != order.end(); ++o) {
|
||||
if ((*o)->primary_axis_pack_options() & PackExpand) {
|
||||
n_expanding++;
|
||||
} else {
|
||||
n_nonexpanding++;
|
||||
|
||||
Duple min, natural;
|
||||
|
||||
(*o)->item().preferred_size (min, natural);
|
||||
|
||||
if (orientation == Vertical) {
|
||||
non_expanding_used += natural.height();
|
||||
} else {
|
||||
non_expanding_used += natural.width();
|
||||
}
|
||||
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
if (orientation == Vertical) {
|
||||
expanded_size = (r.height() - _top_margin - _bottom_margin - ((total - 1) * _spacing) - non_expanding_used) / n_expanding;
|
||||
} else {
|
||||
expanded_size = (r.width() - _left_margin - _right_margin - ((total - 1) * _spacing) - non_expanding_used) / n_expanding;
|
||||
}
|
||||
|
||||
cerr << "\n\n\n" << debug_name() << " SIZE-ALLOC " << r << " expanded items (" << n_expanding << ")will be " << expanded_size << " neu " << non_expanding_used << " t = " << total << " s " << _spacing << '\n';
|
||||
|
||||
Order::size_type n = 0;
|
||||
Order::iterator prev = order.end();
|
||||
try {
|
||||
for (Order::iterator o = order.begin(); o != order.end(); ++o, ++n) {
|
||||
|
||||
Duple min, natural;
|
||||
(*o)->item().preferred_size (min, natural);
|
||||
|
||||
cerr << "\t" << (*o)->item().debug_name() << " min " << min << " nat " << natural << endl;
|
||||
|
||||
/* setup center_{x,y} variables in case calling/using
|
||||
* code wants to use them for additional constraints
|
||||
*/
|
||||
|
||||
solver.addConstraint ((*o)->center_x() == (*o)->left() + ((*o)->width() / 2.));
|
||||
solver.addConstraint ((*o)->center_y() == (*o)->top() + ((*o)->height() / 2.));
|
||||
|
||||
/* Add constraints that will size the item within this box */
|
||||
|
||||
if (orientation == Vertical) {
|
||||
|
||||
/* set up constraints for expand/fill options, done by
|
||||
* adjusting height and margins of each item
|
||||
*/
|
||||
|
||||
if ((*o)->primary_axis_pack_options() & PackExpand) {
|
||||
|
||||
/* item will take up more than it's natural
|
||||
* size, if space is available
|
||||
*/
|
||||
|
||||
if ((*o)->primary_axis_pack_options() & PackFill) {
|
||||
|
||||
/* item is expanding to fill all
|
||||
* available space and wants that space
|
||||
* for itself.
|
||||
*/
|
||||
|
||||
solver.addConstraint ((*o)->height() == expanded_size | kiwi::strength::strong);
|
||||
solver.addConstraint ((*o)->top_padding() == 0. | kiwi::strength::strong);
|
||||
solver.addConstraint ((*o)->bottom_padding() == 0. | kiwi::strength::strong);
|
||||
|
||||
} else {
|
||||
|
||||
/* item is expanding to fill all
|
||||
* available space and wants that space
|
||||
* as padding
|
||||
*/
|
||||
|
||||
solver.addConstraint ((*o)->height() == natural.height());
|
||||
solver.addConstraint ((*o)->top_padding() + (*o)->bottom_padding() + (*o)->height() == expanded_size | kiwi::strength::strong);
|
||||
solver.addConstraint ((*o)->bottom_padding() == (*o)->top_padding() | kiwi::strength::strong);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* item is not going to expand to fill
|
||||
* available space. just give it's preferred
|
||||
* height.
|
||||
*/
|
||||
|
||||
cerr << (*o)->item().debug_name() << " will use natural height of " << natural.height() << endl;
|
||||
solver.addConstraint ((*o)->height() == natural.height());
|
||||
solver.addConstraint ((*o)->top_padding() == 0.);
|
||||
solver.addConstraint ((*o)->bottom_padding() == 0.);
|
||||
}
|
||||
|
||||
|
||||
/* now set upper left corner of the item */
|
||||
|
||||
if (n == 0) {
|
||||
|
||||
/* first item */
|
||||
|
||||
solver.addConstraint ((*o)->top() == _top_margin + (*o)->top_padding() | kiwi::strength::strong);
|
||||
|
||||
} else {
|
||||
/* subsequent items */
|
||||
|
||||
solver.addConstraint ((*o)->top() == (*prev)->bottom() + (*prev)->bottom_padding() + (*o)->top_padding() + _spacing | kiwi::strength::strong);
|
||||
}
|
||||
|
||||
/* set the side-effect variables and/or constants */
|
||||
|
||||
solver.addConstraint ((*o)->left() + (*o)->width() == (*o)->right()| kiwi::strength::strong);
|
||||
solver.addConstraint ((*o)->bottom() == (*o)->top() + (*o)->height());
|
||||
solver.addConstraint ((*o)->left() == _left_margin + (*o)->left_padding() | kiwi::strength::strong);
|
||||
|
||||
if (!((*o)->secondary_axis_pack_options() & PackExpand) && natural.width() > 0) {
|
||||
cerr << "\t\t also using natural width of " << natural.width() << endl;
|
||||
solver.addConstraint ((*o)->width() == natural.width());
|
||||
} else {
|
||||
cerr << "\t\t also using container width of " << r.width() << endl;
|
||||
solver.addConstraint ((*o)->width() == r.width() - (_left_margin + _right_margin + (*o)->right_padding()) | kiwi::strength::strong);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
/* set up constraints for expand/fill options, done by
|
||||
* adjusting width and margins of each item
|
||||
*/
|
||||
|
||||
if ((*o)->primary_axis_pack_options() & PackExpand) {
|
||||
|
||||
/* item will take up more than it's natural
|
||||
* size, if space is available
|
||||
*/
|
||||
|
||||
if ((*o)->primary_axis_pack_options() & PackFill) {
|
||||
|
||||
/* item is expanding to fill all
|
||||
* available space and wants that space
|
||||
* for itself.
|
||||
*/
|
||||
|
||||
solver.addConstraint ((*o)->width() == expanded_size | kiwi::strength::strong);
|
||||
solver.addConstraint ((*o)->left_padding() == 0. | kiwi::strength::strong);
|
||||
solver.addConstraint ((*o)->right_padding() == 0. | kiwi::strength::strong);
|
||||
|
||||
} else {
|
||||
|
||||
/* item is expanding to fill all
|
||||
* available space and wants that space
|
||||
* as padding
|
||||
*/
|
||||
|
||||
solver.addConstraint ((*o)->width() == natural.width());
|
||||
solver.addConstraint ((*o)->left_padding() + (*o)->right_padding() + (*o)->width() == expanded_size | kiwi::strength::strong);
|
||||
solver.addConstraint ((*o)->left_padding() == (*o)->right_padding() | kiwi::strength::strong);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* item is not going to expand to fill
|
||||
* available space. just give it's preferred
|
||||
* width.
|
||||
*/
|
||||
|
||||
solver.addConstraint ((*o)->width() == natural.width());
|
||||
solver.addConstraint ((*o)->left_padding() == 0.);
|
||||
solver.addConstraint ((*o)->right_padding() == 0.);
|
||||
}
|
||||
|
||||
|
||||
/* now set upper left corner of the item */
|
||||
|
||||
if (n == 0) {
|
||||
|
||||
/* first item */
|
||||
|
||||
solver.addConstraint ((*o)->left() == _left_margin + (*o)->left_padding() | kiwi::strength::strong);
|
||||
|
||||
} else {
|
||||
/* subsequent items */
|
||||
|
||||
solver.addConstraint ((*o)->left() == (*prev)->right() + (*prev)->right_padding() + (*o)->left_padding() + _spacing | kiwi::strength::strong);
|
||||
}
|
||||
|
||||
/* set the side-effect variables and/or constants */
|
||||
|
||||
solver.addConstraint ((*o)->bottom() == (*o)->top() + (*o)->height());
|
||||
solver.addConstraint ((*o)->right() == (*o)->left() + (*o)->width());
|
||||
solver.addConstraint ((*o)->top() == _top_margin + (*o)->top_padding() | kiwi::strength::strong);
|
||||
|
||||
if (!((*o)->secondary_axis_pack_options() & PackExpand) && natural.height() > 0) {
|
||||
cerr << "\t\tand natural height of " << natural.height() << endl;
|
||||
solver.addConstraint ((*o)->height() == natural.height());
|
||||
} else {
|
||||
cerr << "\t\tand container height of " << r.height() << endl;
|
||||
solver.addConstraint ((*o)->height() == r.height() - (_top_margin + _bottom_margin + (*o)->bottom_padding()) | kiwi::strength::strong);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add constraints that come with the item */
|
||||
|
||||
std::vector<Constraint> const & constraints ((*o)->constraints());
|
||||
|
||||
for (std::vector<Constraint>::const_iterator c = constraints.begin(); c != constraints.end(); ++c) {
|
||||
solver.addConstraint (*c);
|
||||
}
|
||||
|
||||
prev = o;
|
||||
}
|
||||
|
||||
} catch (std::exception& e) {
|
||||
cerr << "Setting up sovler failed: " << e.what() << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
solver.updateVariables ();
|
||||
//solver.dump (cerr);
|
||||
|
||||
for (Order::iterator o = order.begin(); o != order.end(); ++o, ++n) {
|
||||
(*o)->dump (cerr);
|
||||
}
|
||||
|
||||
apply (&solver);
|
||||
|
||||
_bounding_box_dirty = true;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
cBox::child_changed (bool bbox_changed)
|
||||
{
|
||||
}
|
||||
142
libs/canvas/constrained_item.cc
Normal file
142
libs/canvas/constrained_item.cc
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Paul Davis <paul@linuxaudiosystems.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "canvas/item.h"
|
||||
#include "canvas/types.h"
|
||||
#include "canvas/constrained_item.h"
|
||||
|
||||
using namespace ArdourCanvas;
|
||||
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using kiwi::Constraint;
|
||||
using kiwi::Variable;
|
||||
|
||||
ConstrainedItem::ConstrainedItem (Item& i)
|
||||
: _item (i)
|
||||
, _left (_item.name + " left")
|
||||
, _right (_item.name + " right")
|
||||
, _top (_item.name + " top")
|
||||
, _bottom (_item.name + " bottom")
|
||||
, _width (_item.name + " width")
|
||||
, _height (_item.name + " height")
|
||||
{
|
||||
}
|
||||
|
||||
ConstrainedItem::~ConstrainedItem ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ConstrainedItem::constrained (ConstraintPacker const & parent)
|
||||
{
|
||||
/* our variables should be set. Deliver computed size to item */
|
||||
|
||||
Rect r (_left.value(), _top.value(), _right.value(), _bottom.value());
|
||||
dump (cerr);
|
||||
cerr << _item.whatami() << '/' << _item.name << " constrained-alloc " << r << endl;
|
||||
|
||||
_item.size_allocate (r);
|
||||
}
|
||||
|
||||
void
|
||||
ConstrainedItem::dump (std::ostream& out)
|
||||
{
|
||||
out << _item.name << " value dump:\n\n";
|
||||
|
||||
out << '\t' << "left: " << _left.value() << '\n';
|
||||
out << '\t' << "right: " << _right.value() << '\n';
|
||||
out << '\t' << "top: " << _top.value() << '\n';
|
||||
out << '\t' << "bottom: " << _bottom.value() << '\n';
|
||||
out << '\t' << "width: " << _width.value() << '\n';
|
||||
out << '\t' << "height: " << _height.value() << '\n';
|
||||
}
|
||||
|
||||
bool
|
||||
ConstrainedItem::involved (Constraint const & c) const
|
||||
{
|
||||
if (c.involves (_left) ||
|
||||
c.involves (_right) ||
|
||||
c.involves (_top) ||
|
||||
c.involves (_bottom) ||
|
||||
c.involves (_width) ||
|
||||
c.involves (_height)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*** BoxConstrainedItem */
|
||||
|
||||
BoxConstrainedItem::BoxConstrainedItem (Item& parent, PackOptions primary_axis_opts, PackOptions secondary_axis_opts)
|
||||
: ConstrainedItem (parent)
|
||||
, _center_x (_item.name + " center_x")
|
||||
, _center_y (_item.name + " center_y")
|
||||
, _left_margin (_item.name + " left_margin")
|
||||
, _right_margin (_item.name + " right_margin")
|
||||
, _top_margin (_item.name + " top_margin")
|
||||
, _bottom_margin (_item.name + " bottom_margin")
|
||||
, _primary_axis_pack_options (primary_axis_opts)
|
||||
, _secondary_axis_pack_options (secondary_axis_opts)
|
||||
{
|
||||
}
|
||||
|
||||
BoxConstrainedItem::~BoxConstrainedItem ()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BoxConstrainedItem::involved (Constraint const & c) const
|
||||
{
|
||||
if (ConstrainedItem::involved (c)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (c.involves (_center_x) ||
|
||||
c.involves (_center_y) ||
|
||||
c.involves (_left_margin) ||
|
||||
c.involves (_right_margin) ||
|
||||
c.involves (_top_margin) ||
|
||||
c.involves (_bottom_margin)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
BoxConstrainedItem::dump (std::ostream& out)
|
||||
{
|
||||
ConstrainedItem::dump (out);
|
||||
|
||||
out << '\t' << "center_x: " << _center_x.value() << '\n';
|
||||
out << '\t' << "center_y: " << _center_y.value() << '\n';
|
||||
out << '\t' << "left_margin: " << _left_margin.value() << '\n';
|
||||
out << '\t' << "right_margin: " << _right_margin.value() << '\n';
|
||||
out << '\t' << "top_margin: " << _top_margin.value() << '\n';
|
||||
out << '\t' << "bottom_margin: " << _bottom_margin.value() << '\n';
|
||||
|
||||
out << '\t' << "right_padding: " << _right_padding.value() << '\n';
|
||||
out << '\t' << "left_padding: " << _left_padding.value() << '\n';
|
||||
out << '\t' << "top_padding: " << _top_padding.value() << '\n';
|
||||
out << '\t' << "bottom_padding: " << _bottom_padding.value() << '\n';
|
||||
}
|
||||
|
||||
|
|
@ -16,8 +16,11 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
#include "pbd/unwind.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
#include "kiwi/kiwi.h"
|
||||
|
||||
|
|
@ -28,114 +31,279 @@
|
|||
|
||||
using namespace ArdourCanvas;
|
||||
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
using kiwi::Constraint;
|
||||
using namespace kiwi;
|
||||
|
||||
ConstraintPacker::ConstraintPacker (Canvas* canvas)
|
||||
: Item (canvas)
|
||||
, width (X_("width"))
|
||||
, height (X_("height"))
|
||||
: Container (canvas)
|
||||
, width (X_("packer width"))
|
||||
, height (X_("packer height"))
|
||||
, in_alloc (false)
|
||||
{
|
||||
_solver.addEditVariable (width, kiwi::strength::strong);
|
||||
_solver.addEditVariable (height, kiwi::strength::strong);
|
||||
set_fill (false);
|
||||
set_outline (false);
|
||||
}
|
||||
|
||||
ConstraintPacker::ConstraintPacker (Item* parent)
|
||||
: Item (parent)
|
||||
: Container (parent)
|
||||
, width (X_("packer width"))
|
||||
, height (X_("packer height"))
|
||||
, in_alloc (false)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
|
||||
{
|
||||
Item::render_children (area, context);
|
||||
set_fill (false);
|
||||
set_outline (false);
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::compute_bounding_box () const
|
||||
{
|
||||
_bounding_box = Rect();
|
||||
|
||||
if (_items.empty()) {
|
||||
_bounding_box_dirty = false;
|
||||
return;
|
||||
}
|
||||
|
||||
add_child_bounding_boxes (!collapse_on_hide);
|
||||
|
||||
_bounding_box = _allocation;
|
||||
_bounding_box_dirty = false;
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::reset_self ()
|
||||
ConstraintPacker::child_changed (bool bbox_changed)
|
||||
{
|
||||
if (_bounding_box_dirty) {
|
||||
compute_bounding_box ();
|
||||
}
|
||||
Item::child_changed (bbox_changed);
|
||||
|
||||
if (!_bounding_box) {
|
||||
self->hide ();
|
||||
if (in_alloc || !bbox_changed) {
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
cerr << "CP, child bbox changed\n";
|
||||
|
||||
Rect r (_bounding_box);
|
||||
for (ConstrainedItemMap::iterator x = constrained_map.begin(); x != constrained_map.end(); ++x) {
|
||||
|
||||
/* XXX need to shrink by margin */
|
||||
Duple i = x->first->intrinsic_size();
|
||||
|
||||
self->set (r);
|
||||
}
|
||||
if (r) {
|
||||
|
||||
void
|
||||
ConstraintPacker::reposition_children ()
|
||||
{
|
||||
_bounding_box_dirty = true;
|
||||
reset_self ();
|
||||
}
|
||||
void
|
||||
ConstraintPacker::child_changed ()
|
||||
{
|
||||
/* catch visibility and size changes */
|
||||
// cerr << x->first->whatami() << '/' << x->first->name << " has instrinsic size " << r << endl;
|
||||
|
||||
Item::child_changed ();
|
||||
reposition_children ();
|
||||
kiwi::Variable& w (x->second->intrinsic_width());
|
||||
if (!r.width()) {
|
||||
if (_solver.hasEditVariable (w)) {
|
||||
_solver.removeEditVariable (w);
|
||||
cerr << "\tremoved inttrinsic-width edit var\n";
|
||||
}
|
||||
} else {
|
||||
if (!_solver.hasEditVariable (w)) {
|
||||
cerr << "\tadding intrinsic width constraints\n";
|
||||
_solver.addEditVariable (w, kiwi::strength::strong);
|
||||
_solver.addConstraint (Constraint {x->second->width() >= w } | kiwi::strength::strong);
|
||||
_solver.addConstraint (Constraint (x->second->width() <= w) | kiwi::strength::weak);
|
||||
}
|
||||
}
|
||||
|
||||
kiwi::Variable& h (x->second->intrinsic_height());
|
||||
if (!r.height()) {
|
||||
if (_solver.hasEditVariable (h)) {
|
||||
_solver.removeEditVariable (h);
|
||||
cerr << "\tremoved inttrinsic-height edit var\n";
|
||||
}
|
||||
} else {
|
||||
if (!_solver.hasEditVariable (h)) {
|
||||
cerr << "\tadding intrinsic height constraints\n";
|
||||
_solver.addEditVariable (h, kiwi::strength::strong);
|
||||
_solver.addConstraint (Constraint {x->second->height() >= h } | kiwi::strength::strong);
|
||||
_solver.addConstraint (Constraint (x->second->height() <= h) | kiwi::strength::weak);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::constrain (kiwi::Constraint const &c)
|
||||
{
|
||||
_solver.addConstraint (c);
|
||||
constraint_list.push_back (c);
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::preferred_size (Duple& minimum, Duple& natural) const
|
||||
{
|
||||
/* our parent wants to know how big we are.
|
||||
|
||||
We may have some intrinsic size (i.e. "everything in this constraint
|
||||
layout should fit into WxH". Just up two constraints on our width
|
||||
and height, and solve.
|
||||
|
||||
We may have one intrinsic dimension (i.e. "everything in this
|
||||
constraint layout should fit into this (width|height). Ask all of
|
||||
our children for the size-given-(W|H). Add constraints to represent
|
||||
those values, and solve.
|
||||
|
||||
We may have no intrinsic dimensions at all. This is the tricky one.
|
||||
*/
|
||||
|
||||
kiwi::Solver s;
|
||||
|
||||
if (_intrinsic_width > 0) {
|
||||
|
||||
s.addEditVariable (width, kiwi::strength::strong);
|
||||
s.suggestValue (width, _intrinsic_width);
|
||||
|
||||
} else if (_intrinsic_height > 0) {
|
||||
|
||||
s.addEditVariable (height, kiwi::strength::strong);
|
||||
s.suggestValue (height, _intrinsic_height);
|
||||
|
||||
}
|
||||
|
||||
for (ConstrainedItemMap::const_iterator x = constrained_map.begin(); x != constrained_map.end(); ++x) {
|
||||
|
||||
Duple min, natural;
|
||||
ConstrainedItem* ci = x->second;
|
||||
|
||||
x->first->preferred_size (min, natural);
|
||||
|
||||
s.addConstraint (ci->width() >= min.width() | kiwi::strength::required);
|
||||
s.addConstraint (ci->height() >= min.height() | kiwi::strength::required);
|
||||
s.addConstraint (ci->width() == natural.width() | kiwi::strength::medium);
|
||||
s.addConstraint (ci->height() == natural.width() | kiwi::strength::medium);
|
||||
|
||||
add_constraints (s, ci);
|
||||
}
|
||||
|
||||
for (ConstraintList::const_iterator c = constraint_list.begin(); c != constraint_list.end(); ++c) {
|
||||
s.addConstraint (*c);
|
||||
}
|
||||
|
||||
s.updateVariables ();
|
||||
|
||||
Duple ret;
|
||||
|
||||
natural.x = width.value ();
|
||||
natural.y = height.value ();
|
||||
|
||||
minimum = natural;
|
||||
|
||||
cerr << "CP::sr returns " << natural<< endl;
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::size_allocate (Rect const & r)
|
||||
{
|
||||
PBD::Unwinder<bool> uw (in_alloc, true);
|
||||
|
||||
Item::size_allocate (r);
|
||||
|
||||
_solver.suggestValue (width, r.width());
|
||||
_solver.suggestValue (height, r.height());
|
||||
cerr << "CP alloc " << r << " with " << constrained_map.size() << " children\n";
|
||||
|
||||
solve ();
|
||||
kiwi::Solver s;
|
||||
|
||||
s.addConstraint (width == r.width());
|
||||
s.addConstraint (height == r.height());
|
||||
|
||||
// s.addEditVariable (width, kiwi::strength::strong);
|
||||
// s.addEditVariable (height, kiwi::strength::strong);
|
||||
// s.suggestValue (width, r.width());
|
||||
// s.suggestValue (height, r.height());
|
||||
|
||||
for (ConstrainedItemMap::iterator x = constrained_map.begin(); x != constrained_map.end(); ++x) {
|
||||
|
||||
Duple min, natural;
|
||||
ConstrainedItem* ci = x->second;
|
||||
|
||||
x->first->preferred_size (min, natural);
|
||||
|
||||
s.addConstraint (ci->width() >= min.width() | kiwi::strength::required);
|
||||
s.addConstraint (ci->height() >= min.height() | kiwi::strength::required);
|
||||
s.addConstraint (ci->width() == natural.width() | kiwi::strength::medium);
|
||||
s.addConstraint (ci->height() == natural.width() | kiwi::strength::medium);
|
||||
|
||||
add_constraints (s, ci);
|
||||
}
|
||||
|
||||
for (ConstraintList::const_iterator c = constraint_list.begin(); c != constraint_list.end(); ++c) {
|
||||
s.addConstraint (*c);
|
||||
}
|
||||
|
||||
s.updateVariables ();
|
||||
apply (0);
|
||||
|
||||
_bounding_box_dirty = true;
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::add (Item* item)
|
||||
{
|
||||
(void) add_constrained (item);
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::add_front (Item* item)
|
||||
{
|
||||
(void) add_constrained (item);
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::add_constraints (Solver& s, ConstrainedItem* ci) const
|
||||
{
|
||||
/* add any constraints inherent to this item */
|
||||
|
||||
vector<Constraint> const & vc (ci->constraints());
|
||||
|
||||
for (vector<Constraint>::const_iterator x = vc.begin(); x != vc.end(); ++x) {
|
||||
s.addConstraint (*x);
|
||||
}
|
||||
}
|
||||
|
||||
ConstrainedItem*
|
||||
ConstraintPacker::add_constrained (Item* item)
|
||||
{
|
||||
ConstrainedItem* ci = new ConstrainedItem (*item);
|
||||
add_constrained_internal (item, ci);
|
||||
return ci;
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::add_constrained_internal (Item* item, ConstrainedItem* ci)
|
||||
{
|
||||
Item::add (item);
|
||||
ConstrainedItem* ci = new ConstrainedItem (*item);
|
||||
constraint_map.insert (std::make_pair (item, ci));
|
||||
item->set_layout_sensitive (true);
|
||||
constrained_map.insert (std::make_pair (item, ci));
|
||||
child_changed (true);
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::remove (Item* item)
|
||||
{
|
||||
Item::remove (item);
|
||||
constraint_map.erase (item);
|
||||
|
||||
for (ConstrainedItemMap::iterator x = constrained_map.begin(); x != constrained_map.end(); ++x) {
|
||||
|
||||
if (x->first == item) {
|
||||
|
||||
/* remove any non-builtin constraints for this item */
|
||||
|
||||
for (ConstraintList::iterator c = constraint_list.begin(); c != constraint_list.end(); ++c) {
|
||||
if (x->second->involved (*c)) {
|
||||
constraint_list.erase (c);
|
||||
}
|
||||
}
|
||||
|
||||
item->set_layout_sensitive (false);
|
||||
|
||||
/* clean up */
|
||||
|
||||
delete x->second;
|
||||
constrained_map.erase (x);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
ConstraintPacker::solve ()
|
||||
ConstraintPacker::apply (Solver* s)
|
||||
{
|
||||
_solver.updateVariables ();
|
||||
|
||||
for (ConstraintMap::iterator x = constraint_map.begin(); x != constraint_map.end(); ++x) {
|
||||
x->first->constrained (*(x->second));
|
||||
for (ConstrainedItemMap::iterator x = constrained_map.begin(); x != constrained_map.end(); ++x) {
|
||||
x->second->constrained (*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,24 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <gtkmm/adjustment.h>
|
||||
#include <gtkmm/main.h>
|
||||
#include <gtkmm/window.h>
|
||||
|
||||
#include "gtkmm2ext/colors.h"
|
||||
|
||||
#include "canvas/box.h"
|
||||
#include "canvas/canvas.h"
|
||||
#include "canvas/cbox.h"
|
||||
#include "canvas/circle.h"
|
||||
#include "canvas/constrained_item.h"
|
||||
#include "canvas/constraint_packer.h"
|
||||
#include "canvas/rectangle.h"
|
||||
#include "canvas/text.h"
|
||||
|
||||
using namespace ArdourCanvas;
|
||||
using namespace Gtk;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
int
|
||||
main (int argc, char* argv[])
|
||||
|
|
@ -17,10 +29,147 @@ main (int argc, char* argv[])
|
|||
Gtk::Adjustment hadj (0, 0, 1000, 1, 10);
|
||||
Gtk::Adjustment vadj (0, 0, 1000, 1, 10);
|
||||
GtkCanvasViewport cview (hadj, vadj);
|
||||
Canvas* c = cview.canvas ();
|
||||
|
||||
c->set_background_color (0xffffffff);
|
||||
|
||||
srandom (time ((time_t) 0));
|
||||
|
||||
// cview.set_size_request (100, 100);
|
||||
|
||||
win.add (cview);
|
||||
|
||||
Rectangle* r1 = new Rectangle (c);
|
||||
Rectangle* r2 = new Rectangle (c);
|
||||
Rectangle* r3 = new Rectangle (c);
|
||||
|
||||
r1->set_fill_color (Gtkmm2ext::random_color());
|
||||
r2->set_fill_color (Gtkmm2ext::random_color());
|
||||
r3->set_fill_color (Gtkmm2ext::random_color());
|
||||
|
||||
r1->name = "r1";
|
||||
r2->name = "r2";
|
||||
r3->name = "r3";
|
||||
|
||||
//r1->set_intrinsic_size (20, 20);
|
||||
//r2->set_intrinsic_size (30, 30);
|
||||
//r3->set_intrinsic_size (40, 40);
|
||||
|
||||
//#define FULL_PACKER
|
||||
#define CBOX_PACKER
|
||||
//#define BOX_PACKER
|
||||
|
||||
#ifdef FULL_PACKER
|
||||
ConstraintPacker* packer = new ConstraintPacker (c->root());
|
||||
|
||||
ConstrainedItem* left = packer->add_constrained (r1);
|
||||
ConstrainedItem* right = packer->add_constrained (r2);
|
||||
ConstrainedItem* center = packer->add_constrained (r3);
|
||||
|
||||
/* x-axis */
|
||||
|
||||
packer->constrain (left->left() == 0);
|
||||
packer->constrain (center->left() == left->right());
|
||||
packer->constrain (right->left() == center->right());
|
||||
|
||||
packer->constrain (left->width() == packer->width * 0.4);
|
||||
packer->constrain (center->width() == packer->width * 0.1);
|
||||
packer->constrain (left->width() + right->width() + center->width() == packer->width);
|
||||
|
||||
packer->constrain (left->right() == left->left() + left->width());
|
||||
packer->constrain (right->right() == right->left() + right->width());
|
||||
packer->constrain (center->right() == center->left() + center->width());
|
||||
|
||||
/* y-axis */
|
||||
|
||||
packer->constrain (left->top() == 0);
|
||||
packer->constrain (right->top() == left->top());
|
||||
packer->constrain (center->top() == left->top());
|
||||
|
||||
packer->constrain (left->height() == packer->height);
|
||||
packer->constrain (right->height() == left->height());
|
||||
packer->constrain (center->height() == left->height());
|
||||
|
||||
packer->constrain (left->bottom() == left->top() + left->height());
|
||||
packer->constrain (center->bottom() == center->top() + center->height());
|
||||
packer->constrain (right->bottom() == right->top() + right->height());
|
||||
|
||||
#elif defined(CBOX_PACKER)
|
||||
|
||||
cBox* vbox = new cBox (c->root(), Vertical);
|
||||
vbox->name = "vbox";
|
||||
|
||||
vbox->set_margin (10, 20, 30, 40);
|
||||
|
||||
vbox->pack_start (r1, PackOptions(PackExpand|PackFill));
|
||||
vbox->pack_start (r2, PackOptions(PackExpand|PackFill));
|
||||
vbox->pack_start (r3, PackOptions(PackExpand|PackFill));
|
||||
|
||||
cBox* hbox1 = new cBox (c, Horizontal);
|
||||
hbox1->name = "hbox1";
|
||||
|
||||
hbox1->set_margin (10, 10, 10, 10);
|
||||
|
||||
Rectangle* r4 = new Rectangle (c);
|
||||
Rectangle* r5 = new Rectangle (c);
|
||||
Rectangle* r6 = new Rectangle (c);
|
||||
|
||||
r4->set_fill_color (Gtkmm2ext::random_color());
|
||||
r5->set_fill_color (Gtkmm2ext::random_color());
|
||||
r6->set_fill_color (Gtkmm2ext::random_color());
|
||||
|
||||
r4->name = "r4";
|
||||
r5->name = "r5";
|
||||
r6->name = "r6";
|
||||
hbox1->pack_start (r4, PackOptions(PackExpand|PackFill));
|
||||
hbox1->pack_start (r5, PackOptions(PackExpand|PackFill));
|
||||
hbox1->pack_start (r6, PackOptions(PackExpand|PackFill));
|
||||
|
||||
BoxConstrainedItem* hb1;
|
||||
ConstrainedItem* ci;
|
||||
|
||||
hb1 = vbox->pack_start (hbox1, PackOptions (PackExpand|PackFill));
|
||||
|
||||
Circle* circle = new Circle (c);
|
||||
circle->name = "circle";
|
||||
//circle->set_radius (30);
|
||||
circle->set_fill_color (Gtkmm2ext::random_color());
|
||||
circle->set_outline_color (Gtkmm2ext::random_color());
|
||||
|
||||
ci = vbox->pack_start (circle, PackOptions (PackExpand|PackFill));
|
||||
ci->add_constraint (ci->height() == 0.5 * hb1->height());
|
||||
|
||||
//#endif
|
||||
|
||||
cBox* hbox2 = new cBox (c, Horizontal);
|
||||
hbox2->name = "hbox2";
|
||||
hbox2->set_fill (true);
|
||||
hbox2->set_fill_color (Gtkmm2ext::random_color());
|
||||
|
||||
Text* txt = new Text (c);
|
||||
txt->name = "text";
|
||||
Pango::FontDescription font ("Sans");
|
||||
txt->set_font_description (font);
|
||||
txt->set ("hello, world");
|
||||
|
||||
BoxConstrainedItem* ti = hbox2->pack_start (txt, PackExpand);
|
||||
BoxConstrainedItem* hb2 = vbox->pack_start (hbox2, PackOptions (PackExpand|PackFill));
|
||||
|
||||
// c1 == first hbox
|
||||
// ci = circle
|
||||
// hb2 == second hbox
|
||||
// ti == text inside second hbox
|
||||
|
||||
//ti->add_constraint (ti->center_x() == hb2->center_x());
|
||||
|
||||
cerr << "hbox1 f = " << hbox1->fill() << " o " << hbox1->outline() << endl;
|
||||
|
||||
#endif
|
||||
|
||||
win.show_all ();
|
||||
|
||||
// cerr << "\n\n\n text center @ " << c3->center_x().value() << " hbox center @ " << c1->center_x().value() << endl;
|
||||
|
||||
app.run ();
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -32,8 +32,10 @@ canvas_sources = [
|
|||
'arrow.cc',
|
||||
'box.cc',
|
||||
'canvas.cc',
|
||||
'cbox.cc',
|
||||
'circle.cc',
|
||||
'container.cc',
|
||||
'constrained_item.cc',
|
||||
'constraint_packer.cc',
|
||||
'curve.cc',
|
||||
'debug.cc',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue