From 502a9e80dc6118b04062a511ef2fa0a0f0d0a51b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 28 Jun 2020 21:36:22 -0600 Subject: [PATCH] Canvas: add a nice new syntax for constraint packing --- libs/canvas/canvas/constrained_item.h | 54 +++++++--- libs/canvas/cbox.cc | 15 ++- libs/canvas/constrained_item.cc | 142 ++++++++++++++++++++++++-- libs/canvas/constraint_packer.cc | 100 ++++++++---------- libs/canvas/constraint_test.cc | 11 +- libs/canvas/constraint_test4.cc | 128 +++++++++++++++++++++++ libs/canvas/wscript | 9 ++ 7 files changed, 367 insertions(+), 92 deletions(-) create mode 100644 libs/canvas/constraint_test4.cc diff --git a/libs/canvas/canvas/constrained_item.h b/libs/canvas/canvas/constrained_item.h index 06aa65d510..41066354cc 100644 --- a/libs/canvas/canvas/constrained_item.h +++ b/libs/canvas/canvas/constrained_item.h @@ -45,16 +45,48 @@ class /* LIBCANVAS_API */ ConstrainedItem kiwi::Variable& bottom () { return _bottom; } kiwi::Variable& width () { return _width; } kiwi::Variable& height () { return _height; } - kiwi::Variable& center_x () { return _center_x; } kiwi::Variable& center_y () { return _center_y; } + kiwi::Variable const & left () const { return _left; } + kiwi::Variable const & right () const { return _right; } + kiwi::Variable const & top () const { return _top; } + kiwi::Variable const & bottom () const { return _bottom; } + kiwi::Variable const & width () const { return _width; } + kiwi::Variable const & height () const { return _height; } + kiwi::Variable const & center_x () const { return _center_x; } + kiwi::Variable const & center_y () const { return _center_y; } + + 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; } + void constrained (ConstraintPacker const & parent); virtual bool involved (kiwi::Constraint const &) const; std::vector const & constraints() const { return _constraints; } void add_constraint (kiwi::Constraint const & c) { _constraints.push_back (c); } + ConstrainedItem& at (Duple const &); + ConstrainedItem& size (Duple const &); + ConstrainedItem& box (Rect const &); + + ConstrainedItem& left_of (ConstrainedItem const &, Distance pad = 0); + ConstrainedItem& right_of (ConstrainedItem const &, Distance pad = 0); + ConstrainedItem& above (ConstrainedItem const &, Distance pad = 0); + ConstrainedItem& below (ConstrainedItem const &, Distance pad = 0); + ConstrainedItem& x_centered (ConstrainedItem const &, Distance offset = 0); + ConstrainedItem& y_centered (ConstrainedItem const &, Distance offset = 0); + ConstrainedItem& centered_on (ConstrainedItem const &, Distance xoffset = 0, Distance yoffset = 0); + ConstrainedItem& top_aligned_with (ConstrainedItem const &, Distance offset = 0); + ConstrainedItem& bottom_aligned_with (ConstrainedItem const &, Distance offset = 0); + ConstrainedItem& left_aligned_with (ConstrainedItem const &, Distance offset = 0); + ConstrainedItem& right_aligned_with (ConstrainedItem const &, Distance offset = 0); + ConstrainedItem& same_size_as (ConstrainedItem const &, Distance wdelta = 0, Distance hdelta = 0); + ConstrainedItem& same_width_as (ConstrainedItem const &, Distance delta = 0); + ConstrainedItem& same_height_as (ConstrainedItem const &, Distance delta = 0); + virtual void dump (std::ostream&); protected: @@ -67,6 +99,10 @@ class /* LIBCANVAS_API */ ConstrainedItem kiwi::Variable _bottom; kiwi::Variable _width; kiwi::Variable _height; + kiwi::Variable _left_padding; + kiwi::Variable _right_padding; + kiwi::Variable _top_padding; + kiwi::Variable _bottom_padding; /* derived */ @@ -87,17 +123,6 @@ class /* LIBCANVAS_API */ BoxConstrainedItem : public ConstrainedItem 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; } @@ -108,10 +133,6 @@ class /* LIBCANVAS_API */ BoxConstrainedItem : public ConstrainedItem 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; @@ -120,4 +141,3 @@ class /* LIBCANVAS_API */ BoxConstrainedItem : public ConstrainedItem } #endif - diff --git a/libs/canvas/cbox.cc b/libs/canvas/cbox.cc index d85a770b99..8fd6a14928 100644 --- a/libs/canvas/cbox.cc +++ b/libs/canvas/cbox.cc @@ -284,11 +284,11 @@ cBox::size_allocate (Rect const & r) _solver.suggestValue (expanded_item_size, expanded_size); _solver.updateVariables (); - //solver.dump (cerr); + _solver.dump (cerr); - //for (ConstrainedItemMap::const_iterator o = constrained_map.begin(); o != constrained_map.end(); ++o) { - //o->second->dump (cerr); - //} + for (ConstrainedItemMap::const_iterator o = constrained_map.begin(); o != constrained_map.end(); ++o) { + o->second->dump (cerr); + } apply (&_solver); @@ -299,8 +299,11 @@ cBox::size_allocate (Rect const & r) void cBox::update_constraints () { - ConstraintPacker::update_constraints (); + /* must totally override ConstraintPacker::update_constraints() */ + _solver.reset (); + _solver.addEditVariable (width, kiwi::strength::strong); + _solver.addEditVariable (height, kiwi::strength::strong); _solver.addEditVariable (expanded_item_size, kiwi::strength::strong); try { @@ -506,6 +509,8 @@ cBox::render (Rect const & area, Cairo::RefPtr context) const if (fill()) { + cerr << whoami() << " setting fill context with 0x" << std::hex << _fill_color << std::dec << " draw " << draw << endl; + setup_fill_context (context); context->rectangle (draw.x0, draw.y0, draw.width(), draw.height()); context->fill_preserve (); diff --git a/libs/canvas/constrained_item.cc b/libs/canvas/constrained_item.cc index 6e3388513f..4ba10d721a 100644 --- a/libs/canvas/constrained_item.cc +++ b/libs/canvas/constrained_item.cc @@ -37,6 +37,10 @@ ConstrainedItem::ConstrainedItem (Item& i) , _bottom (_item.name + " bottom") , _width (_item.name + " width") , _height (_item.name + " height") + , _left_padding (_item.name + " left_padding") + , _right_padding (_item.name + " right_padding") + , _top_padding (_item.name + " top_padding") + , _bottom_padding (_item.name + " bottom_padding") , _center_x (_item.name + " center_x") , _center_y (_item.name + " center_y") { @@ -46,6 +50,9 @@ ConstrainedItem::ConstrainedItem (Item& i) _constraints.push_back (center_x() == left() + (width() / 2.)); _constraints.push_back (center_y() == top() + (height() / 2.)); + + _constraints.push_back (_right == _left + _width); + _constraints.push_back (_bottom == _top + _height); } ConstrainedItem::~ConstrainedItem () @@ -74,6 +81,10 @@ ConstrainedItem::dump (std::ostream& out) << '\t' << "bottom: " << _bottom.value() << '\n' << '\t' << "width: " << _width.value() << '\n' << '\t' << "height: " << _height.value() << '\n' + << '\t' << "right_padding: " << _right_padding.value() << '\n' + << '\t' << "left_padding: " << _left_padding.value() << '\n' + << '\t' << "top_padding: " << _top_padding.value() << '\n' + << '\t' << "bottom_padding: " << _bottom_padding.value() << '\n' << '\t' << "center_x: " << _center_x.value() << '\n' << '\t' << "center_y: " << _center_y.value() << '\n'; } @@ -103,10 +114,6 @@ BoxConstrainedItem::BoxConstrainedItem (Item& parent, PackOptions primary_axis_o , _right_margin (_item.name + " right_margin") , _top_margin (_item.name + " top_margin") , _bottom_margin (_item.name + " bottom_margin") - , _left_padding (_item.name + " left_padding") - , _right_padding (_item.name + " right_padding") - , _top_padding (_item.name + " top_padding") - , _bottom_padding (_item.name + " bottom_padding") , _primary_axis_pack_options (primary_axis_opts) , _secondary_axis_pack_options (secondary_axis_opts) { @@ -141,9 +148,126 @@ BoxConstrainedItem::dump (std::ostream& out) out << '\t' << "left_margin: " << _left_margin.value() << '\n' << '\t' << "right_margin: " << _right_margin.value() << '\n' << '\t' << "top_margin: " << _top_margin.value() << '\n' - << '\t' << "bottom_margin: " << _bottom_margin.value() << '\n' - << '\t' << "right_padding: " << _right_padding.value() << '\n' - << '\t' << "left_padding: " << _left_padding.value() << '\n' - << '\t' << "top_padding: " << _top_padding.value() << '\n' - << '\t' << "bottom_padding: " << _bottom_padding.value() << '\n'; + << '\t' << "bottom_margin: " << _bottom_margin.value() << '\n'; } + +ConstrainedItem& +ConstrainedItem::at (Duple const & d) +{ + _constraints.push_back (_left == d.x); + _constraints.push_back (_top == d.y); + + return *this; +} + +ConstrainedItem& +ConstrainedItem::size (Duple const & d) +{ + _constraints.push_back (_width == d.x); + _constraints.push_back (_height == d.y); + + return *this; +} + +ConstrainedItem& +ConstrainedItem::box (Rect const & r) +{ + _constraints.push_back (_left == r.x0); + _constraints.push_back (_top == r.y0); + _constraints.push_back (_width == r.width()); + _constraints.push_back (_height == r.height()); + + return *this; +} + + +ConstrainedItem& +ConstrainedItem::left_of (ConstrainedItem const & other, Distance by) +{ + _constraints.push_back (_right_padding == by); + _constraints.push_back (_right == other.left() + _right_padding); + return *this; +} + +ConstrainedItem& +ConstrainedItem::right_of (ConstrainedItem const & other, Distance by) +{ + _constraints.push_back (_left_padding == by); + _constraints.push_back (_left == other.right() + _left_padding); + return *this; +} + +ConstrainedItem& +ConstrainedItem::above (ConstrainedItem const & other, Distance by) +{ + _constraints.push_back (_bottom_padding == by); + _constraints.push_back (_bottom == other.top() + _bottom_padding); + return *this; +} + +ConstrainedItem& +ConstrainedItem::below (ConstrainedItem const & other, Distance by) +{ + _constraints.push_back (_top_padding == by); + _constraints.push_back (_top == other.bottom() + _top_padding); + return *this; +} + +ConstrainedItem& +ConstrainedItem::centered_on (ConstrainedItem const & other, Distance xoffset, Distance yoffset) +{ + _constraints.push_back (_center_x == other.center_x() + xoffset); + _constraints.push_back (_center_y == other.center_y() + yoffset); + return *this; +} + +ConstrainedItem& +ConstrainedItem::top_aligned_with (ConstrainedItem const & other, Distance offset) +{ + _constraints.push_back (_top == other.top() + offset); + return *this; +} + +ConstrainedItem& +ConstrainedItem::bottom_aligned_with (ConstrainedItem const & other, Distance offset) +{ + _constraints.push_back (_bottom == other.bottom() + offset); + return *this; +} + +ConstrainedItem& +ConstrainedItem::left_aligned_with (ConstrainedItem const & other, Distance offset) +{ + _constraints.push_back (_left == other.left() + offset); + return *this; +} + +ConstrainedItem& +ConstrainedItem::right_aligned_with (ConstrainedItem const & other, Distance offset) +{ + _constraints.push_back (_right == other.right() + offset); + return *this; +} + +ConstrainedItem& +ConstrainedItem::same_size_as (ConstrainedItem const & other, Distance wdelta, Distance hdelta) +{ + _constraints.push_back (_width == other.width() + wdelta); + _constraints.push_back (_height == other.height() + hdelta); + return *this; +} + +ConstrainedItem& +ConstrainedItem::same_width_as (ConstrainedItem const & other, Distance delta) +{ + _constraints.push_back (_width == other.width() + delta); + return *this; +} + +ConstrainedItem& +ConstrainedItem::same_height_as (ConstrainedItem const & other, Distance delta) +{ + _constraints.push_back (_height == other.height() + delta); + return *this; +} + diff --git a/libs/canvas/constraint_packer.cc b/libs/canvas/constraint_packer.cc index 3a0dad81fc..6adbf70e82 100644 --- a/libs/canvas/constraint_packer.cc +++ b/libs/canvas/constraint_packer.cc @@ -131,11 +131,13 @@ void ConstraintPacker::constrain (kiwi::Constraint const &c) { constraint_list.push_back (c); + _need_constraint_update = true; } void ConstraintPacker::preferred_size (Duple& minimum, Duple& natural) const { +#if 0 /* our parent wants to know how big we are. We may have some intrinsic size (i.e. "everything in this constraint @@ -150,40 +152,17 @@ ConstraintPacker::preferred_size (Duple& minimum, Duple& natural) const We may have no intrinsic dimensions at all. This is the tricky one. */ - kiwi::Solver s; + if (_need_constraint_update) { + const_cast(this)->update_constraints (); + } if (_intrinsic_width > 0) { - - s.addEditVariable (width, kiwi::strength::strong); - s.suggestValue (width, _intrinsic_width); - + _solver.suggestValue (width, _intrinsic_width); } else if (_intrinsic_height > 0) { - - s.addEditVariable (height, kiwi::strength::strong); - s.suggestValue (height, _intrinsic_height); - + _solver.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 (); + _solver.updateVariables (); Duple ret; @@ -191,6 +170,10 @@ ConstraintPacker::preferred_size (Duple& minimum, Duple& natural) const natural.y = height.value (); minimum = natural; +#endif + natural.x = 100; + natural.y = 100; + minimum = natural; cerr << "CP::sr returns " << natural<< endl; } @@ -202,36 +185,22 @@ ConstraintPacker::size_allocate (Rect const & r) Item::size_allocate (r); - 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); + if (_need_constraint_update) { + update_constraints (); } - for (ConstraintList::const_iterator c = constraint_list.begin(); c != constraint_list.end(); ++c) { - s.addConstraint (*c); - } + _solver.suggestValue (width, r.width()); + _solver.suggestValue (height, r.height()); + _solver.updateVariables (); + +#if 0 + _solver.dump (cerr); + + for (ConstrainedItemMap::const_iterator o = constrained_map.begin(); o != constrained_map.end(); ++o) { + o->second->dump (cerr); + } +#endif - s.updateVariables (); apply (0); _bounding_box_dirty = true; @@ -324,4 +293,23 @@ ConstraintPacker::update_constraints () _solver.reset (); _solver.addEditVariable (width, kiwi::strength::strong); _solver.addEditVariable (height, kiwi::strength::strong); + + 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); + + _solver.addConstraint (ci->width() >= min.width() | kiwi::strength::required); + _solver.addConstraint (ci->height() >= min.height() | kiwi::strength::required); + _solver.addConstraint (ci->width() == natural.width() | kiwi::strength::medium); + _solver.addConstraint (ci->height() == natural.width() | kiwi::strength::medium); + + add_constraints (_solver, ci); + } + + for (ConstraintList::const_iterator c = constraint_list.begin(); c != constraint_list.end(); ++c) { + _solver.addConstraint (*c); + } } diff --git a/libs/canvas/constraint_test.cc b/libs/canvas/constraint_test.cc index 8c15429760..ed28c235ed 100644 --- a/libs/canvas/constraint_test.cc +++ b/libs/canvas/constraint_test.cc @@ -61,7 +61,6 @@ main (int argc, char* argv[]) vbox->set_fill_color (0xff0000ff); vbox->set_margin (20); -#if 1 vbox->pack_start (r1, PackOptions(PackExpand|PackFill)); vbox->pack_start (r2, PackOptions(PackExpand|PackFill)); vbox->pack_start (r3, PackOptions(PackExpand|PackFill)); @@ -90,7 +89,7 @@ main (int argc, char* argv[]) hbox1->pack_start (r6, PackOptions(PackExpand|PackFill)); BoxConstrainedItem* hb1; - ConstrainedItem* ci; + BoxConstrainedItem* ci; hb1 = vbox->pack_start (hbox1, PackOptions (PackExpand|PackFill)); @@ -105,6 +104,8 @@ main (int argc, char* argv[]) ci = vbox->pack_start (circle, PackOptions (PackExpand|PackFill)); ci->add_constraint (ci->height() == 0.5 * hb1->height()); ci->add_constraint (ci->center_x() == ci4->center_x()); + ci->add_constraint (ci->top_padding() == 10); + ci->add_constraint (ci->bottom_padding() == 10); cBox* hbox2 = new cBox (c, Horizontal); hbox2->name = "hbox2"; @@ -121,11 +122,11 @@ main (int argc, char* argv[]) txt->set ("hello world"); ConstrainedItem* hb2 = vbox->pack_start (hbox2, PackOptions (PackExpand|PackFill)); + ConstrainedItem* ti = hbox2->pack_start (txt, PackOptions (PackExpand), PackOptions (0)); - ConstrainedItem* ti = hbox2->pack_start (txt, PackOptions (PackExpand|PackFill)); ti->add_constraint (ti->center_x() == hb2->center_x()); - ti->add_constraint (ti->center_y() == hb2->center_y() + 20); -#endif + ti->add_constraint (ti->center_y() == hb2->center_y()); + win.show_all (); app.run (); diff --git a/libs/canvas/constraint_test4.cc b/libs/canvas/constraint_test4.cc new file mode 100644 index 0000000000..8e99c8985e --- /dev/null +++ b/libs/canvas/constraint_test4.cc @@ -0,0 +1,128 @@ +#include + +#include +#include +#include + +#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[]) +{ + Gtk::Main app (&argc, &argv); + + Gtk::Window win; + 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); + + /* Make some items */ + + 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 = "L"; + r2->name = "R"; + r3->name = "C"; + + r1->set_intrinsic_size (20, 20); + r2->set_intrinsic_size (30, 30); + r3->set_intrinsic_size (40, 40); + + Text* txt = new Text (c); + txt->name = "text"; + Pango::FontDescription font ("Sans"); + txt->set_font_description (font); + txt->set ("hello world"); + + Rectangle* bb = new Rectangle (c); + bb->set_fill_color (Gtkmm2ext::random_color()); + + Circle* circ = new Circle (c); + circ->name = "circle"; + circ->set_fill_color (Gtkmm2ext::random_color()); + circ->set_outline_color (Gtkmm2ext::random_color()); + + /* create a container */ + + ConstraintPacker* packer = new ConstraintPacker (c->root()); + + /* add stuff */ + + ConstrainedItem* left = packer->add_constrained (r1); + ConstrainedItem* right = packer->add_constrained (r2); + ConstrainedItem* center = packer->add_constrained (r3); + ConstrainedItem* text = packer->add_constrained (txt); + ConstrainedItem* bens_box = packer->add_constrained (bb); + ConstrainedItem* circle = packer->add_constrained (circ); + + /* first, constraints that connect an item dimension to the container dimensions or a constant */ + packer->constrain (left->left() == 0); + packer->constrain (left->height() == packer->height); + packer->constrain (left->top() == 0); + packer->constrain (left->width() == 0.5 * packer->width); + packer->constrain (right->right() == packer->width); + packer->constrain (center->height() == 0.5 * packer->height); + + /* second, constraints that connect an item dimension to other items */ + center->right_of (*left, 50); + right->right_of (*center); + center->same_width_as (*right); + right->same_width_as (*center); + right->same_height_as (*left); + center->top_aligned_with (*left); + right->top_aligned_with (*center); + + /* XXX this needs to somehow move into ConstraintPacker but I currently + * see no way to build a constraint from a container of + * ConstrainedItems + */ + + packer->constrain (left->width() + right->width() + center->width() + + left->left_padding() + left->right_padding() + + center->left_padding() + center->right_padding() + + right->left_padding() + right->right_padding() + == packer->width); + + /* Text at a fixed position */ + text->at (Duple (150, 50)); + /* Rectangle of fixed position and size */ + bens_box->box (Rect (40, 40, 80, 80)); + + /* a circle sized and centered */ + circle->size (Duple (30, 30)); + circle->centered_on (*center); + + win.show_all (); + app.run (); + + return 0; +} diff --git a/libs/canvas/wscript b/libs/canvas/wscript index 10e93772d9..0e949aee07 100644 --- a/libs/canvas/wscript +++ b/libs/canvas/wscript @@ -190,6 +190,15 @@ def build(bld): constraint_test3.name = 'constraint_test3' constraint_test3.target = 'constraint_test3' constraint_test3.install_path = '' + + constraint_test4_src = [ 'constraint_test4.cc' ] + constraint_test4 = bld (features = 'cxx cxxprogram') + constraint_test4.source = constraint_test4_src + constraint_test4.includes = obj.includes + ['../pbd', '../gtkmm2ext'] + constraint_test4.use = [ 'GTKMM', 'libcanvas', 'libgtkmm2ext' ] + constraint_test4.name = 'constraint_test4' + constraint_test4.target = 'constraint_test4' + constraint_test4.install_path = '' def shutdown(): autowaf.shutdown()