summaryrefslogtreecommitdiff
path: root/libs/canvas/test
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2013-04-04 00:32:52 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2013-04-04 00:32:52 -0400
commitaaea166135ace01709f7e0be64f40be80f4107ec (patch)
tree0e794ef7a723e4aaf909b841a6816e405b4ceca1 /libs/canvas/test
parent1d8bac08c0c00d44e22c581768a275e1b21a99a7 (diff)
initial commit of hand merging, plus getting "ancient" waf script to work correctly
Diffstat (limited to 'libs/canvas/test')
-rw-r--r--libs/canvas/test/arrow.cc37
-rw-r--r--libs/canvas/test/arrow.h12
-rw-r--r--libs/canvas/test/group.cc296
-rw-r--r--libs/canvas/test/group.h24
-rw-r--r--libs/canvas/test/gtk_drag.cc68
-rw-r--r--libs/canvas/test/gtk_many.cc39
-rw-r--r--libs/canvas/test/gtk_movement.cc97
-rw-r--r--libs/canvas/test/gtk_scene.cc66
-rw-r--r--libs/canvas/test/gtk_viewport.cc65
-rw-r--r--libs/canvas/test/hello_world.cc13
-rw-r--r--libs/canvas/test/item.cc28
-rw-r--r--libs/canvas/test/item.h12
-rw-r--r--libs/canvas/test/optimizing_lookup_table.cc141
-rw-r--r--libs/canvas/test/optimizing_lookup_table.h25
-rw-r--r--libs/canvas/test/polygon.cc49
-rw-r--r--libs/canvas/test/polygon.h12
-rw-r--r--libs/canvas/test/render.cc86
-rw-r--r--libs/canvas/test/render.h14
-rw-r--r--libs/canvas/test/test.xml9
-rw-r--r--libs/canvas/test/testrunner.cpp27
-rw-r--r--libs/canvas/test/types.cc54
-rw-r--r--libs/canvas/test/types.h18
-rw-r--r--libs/canvas/test/wave_view.cc164
-rw-r--r--libs/canvas/test/wave_view.h26
-rw-r--r--libs/canvas/test/xml.cc53
-rw-r--r--libs/canvas/test/xml.h17
26 files changed, 1452 insertions, 0 deletions
diff --git a/libs/canvas/test/arrow.cc b/libs/canvas/test/arrow.cc
new file mode 100644
index 0000000000..9112b6f52a
--- /dev/null
+++ b/libs/canvas/test/arrow.cc
@@ -0,0 +1,37 @@
+#include "canvas/group.h"
+#include "canvas/types.h"
+#include "canvas/arrow.h"
+#include "canvas/canvas.h"
+#include "arrow.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (ArrowTest);
+
+void
+ArrowTest::bounding_box ()
+{
+ ImageCanvas canvas;
+ Arrow arrow (canvas.root ());
+
+ for (int i = 0; i < 2; ++i) {
+ arrow.set_show_head (i, true);
+ arrow.set_head_outward (i, true);
+ arrow.set_head_height (i, 16);
+ arrow.set_head_width (i, 12);
+ arrow.set_x (0);
+ arrow.set_y0 (0);
+ arrow.set_y1 (128);
+ }
+
+ arrow.set_outline_width (0);
+
+ boost::optional<Rect> bbox = arrow.bounding_box ();
+
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == -6);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 6);
+ CPPUNIT_ASSERT (bbox.get().y1 == 128);
+}
diff --git a/libs/canvas/test/arrow.h b/libs/canvas/test/arrow.h
new file mode 100644
index 0000000000..f837efc871
--- /dev/null
+++ b/libs/canvas/test/arrow.h
@@ -0,0 +1,12 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class ArrowTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (ArrowTest);
+ CPPUNIT_TEST (bounding_box);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void bounding_box ();
+};
diff --git a/libs/canvas/test/group.cc b/libs/canvas/test/group.cc
new file mode 100644
index 0000000000..914b940c5e
--- /dev/null
+++ b/libs/canvas/test/group.cc
@@ -0,0 +1,296 @@
+#include "canvas/group.h"
+#include "canvas/types.h"
+#include "canvas/rectangle.h"
+#include "canvas/canvas.h"
+#include "group.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (GroupTest);
+
+/* Do some basic checks on the group's computation of its bounding box */
+void
+GroupTest::bounding_box ()
+{
+ /* a group with 4 rectangles in it */
+ ImageCanvas canvas;
+ Rectangle a (canvas.root(), Rect (0, 0, 32, 32));
+ a.set_outline_width (0);
+ Rectangle b (canvas.root(), Rect (0, 33, 32, 64));
+ b.set_outline_width (0);
+ Rectangle c (canvas.root(), Rect (33, 0, 64, 32));
+ c.set_outline_width (0);
+ Rectangle d (canvas.root(), Rect (33, 33, 64, 64));
+ d.set_outline_width (0);
+ boost::optional<Rect> bbox = canvas.root()->bounding_box ();
+
+ /* check the bounding box */
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 64);
+ CPPUNIT_ASSERT (bbox.get().y1 == 64);
+
+ /* check that adding an item resets the bbox */
+ Rectangle e (canvas.root(), Rect (64, 64, 128, 128));
+ bbox = canvas.root()->bounding_box ();
+
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 128.25);
+ CPPUNIT_ASSERT (bbox.get().y1 == 128.25);
+}
+
+/* Check that a group containing only items with no bounding box itself has no bounding box */
+void
+GroupTest::null_bounding_box ()
+{
+ ImageCanvas canvas;
+
+ Group empty (canvas.root());
+
+ boost::optional<Rect> bbox = empty.bounding_box ();
+ CPPUNIT_ASSERT (!bbox.is_initialized ());
+}
+
+/* Do some basic tests on layering */
+void
+GroupTest::layers ()
+{
+ /* Set up 4 rectangles; order from the bottom is
+ a - b - c - d
+ */
+ ImageCanvas canvas;
+ Rectangle a (canvas.root(), Rect (0, 0, 32, 32));
+ Rectangle b (canvas.root(), Rect (0, 0, 32, 32));
+ Rectangle c (canvas.root(), Rect (0, 0, 32, 32));
+ Rectangle d (canvas.root(), Rect (0, 0, 32, 32));
+
+ /* Put a on top and check */
+ a.raise_to_top ();
+
+ list<Item*>::const_iterator i = canvas.root()->items().begin();
+ CPPUNIT_ASSERT (*i++ == &b);
+ CPPUNIT_ASSERT (*i++ == &c);
+ CPPUNIT_ASSERT (*i++ == &d);
+ CPPUNIT_ASSERT (*i++ == &a);
+
+ /* Put a on the bottom and check */
+ a.lower_to_bottom ();
+
+ i = canvas.root()->items().begin();
+ CPPUNIT_ASSERT (*i++ == &a);
+ CPPUNIT_ASSERT (*i++ == &b);
+ CPPUNIT_ASSERT (*i++ == &c);
+ CPPUNIT_ASSERT (*i++ == &d);
+
+ /* Check raise by a number of levels */
+
+ a.raise (2);
+
+ i = canvas.root()->items().begin();
+ CPPUNIT_ASSERT (*i++ == &b);
+ CPPUNIT_ASSERT (*i++ == &c);
+ CPPUNIT_ASSERT (*i++ == &a);
+ CPPUNIT_ASSERT (*i++ == &d);
+
+ a.raise (4);
+
+ i = canvas.root()->items().begin();
+ CPPUNIT_ASSERT (*i++ == &b);
+ CPPUNIT_ASSERT (*i++ == &c);
+ CPPUNIT_ASSERT (*i++ == &d);
+ CPPUNIT_ASSERT (*i++ == &a);
+}
+
+/* Check that groups notice when their children change */
+void
+GroupTest::children_changing ()
+{
+ ImageCanvas canvas;
+
+ /* Put a rectangle in the root group */
+ Rectangle a (canvas.root(), Rect (0, 0, 32, 32));
+ a.set_outline_width (0);
+
+ /* Check that initial bbox */
+ boost::optional<Rect> bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 32);
+ CPPUNIT_ASSERT (bbox.get().y1 == 32);
+
+ /* Change the rectangle's size and check the parent */
+ a.set (Rect (0, 0, 48, 48));
+ bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 48);
+ CPPUNIT_ASSERT (bbox.get().y1 == 48);
+
+ /* Change the rectangle's line width and check the parent */
+ a.set_outline_width (1);
+ bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == -0.5);
+ CPPUNIT_ASSERT (bbox.get().y0 == -0.5);
+ CPPUNIT_ASSERT (bbox.get().x1 == 48.5);
+ CPPUNIT_ASSERT (bbox.get().y1 == 48.5);
+}
+
+/* Check that a group notices when its grandchildren change */
+void
+GroupTest::grandchildren_changing ()
+{
+ ImageCanvas canvas;
+
+ /* Put a child group B in the root group */
+ Group B (canvas.root());
+
+ /* Grandchild rectangle */
+ Rectangle a (&B, Rect (0, 0, 32, 32));
+ a.set_outline_width (0);
+
+ /* Check the initial bboxes */
+ boost::optional<Rect> bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 32);
+ CPPUNIT_ASSERT (bbox.get().y1 == 32);
+
+ bbox = B.bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 32);
+ CPPUNIT_ASSERT (bbox.get().y1 == 32);
+
+ /* Change the grandchild and check its parent and grandparent */
+ a.set (Rect (0, 0, 48, 48));
+
+ bbox = canvas.root()->bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 48);
+ CPPUNIT_ASSERT (bbox.get().y1 == 48);
+
+ bbox = B.bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == 0);
+ CPPUNIT_ASSERT (bbox.get().y0 == 0);
+ CPPUNIT_ASSERT (bbox.get().x1 == 48);
+ CPPUNIT_ASSERT (bbox.get().y1 == 48);
+}
+
+/* Basic tests on the code to find items at a particular point */
+void
+GroupTest::add_items_at_point ()
+{
+ ImageCanvas canvas;
+
+ Group gA (canvas.root());
+ gA.set_position (Duple (128, 64));
+
+ Group gB (&gA);
+ gB.set_position (Duple (64, 32));
+
+ /* two rectangles in the same place, rB on top of rA */
+ Rectangle rA (&gB);
+ rA.set_position (Duple (4, 2));
+ rA.set (Rect (0, 0, 8, 4));
+ Rectangle rB (&gB);
+ rB.set_position (Duple (4, 2));
+ rB.set (Rect (0, 0, 8, 4));
+
+ /* rC below those two */
+ Rectangle rC (&gB);
+ rC.set_position (Duple (12, 6));
+ rC.set (Rect (0, 0, 8, 4));
+
+ vector<Item const *> items;
+ canvas.root()->add_items_at_point (Duple (128 + 64 + 4 + 4, 64 + 32 + 2 + 2), items);
+ CPPUNIT_ASSERT (items.size() == 5);
+ vector<Item const *>::iterator i = items.begin ();
+ CPPUNIT_ASSERT (*i++ == canvas.root ());
+ CPPUNIT_ASSERT (*i++ == &gA);
+ CPPUNIT_ASSERT (*i++ == &gB);
+ CPPUNIT_ASSERT (*i++ == &rA);
+ CPPUNIT_ASSERT (*i++ == &rB);
+
+ items.clear ();
+ canvas.root()->add_items_at_point (Duple (128 + 64 + 12 + 4, 64 + 32 + 6 + 2), items);
+ CPPUNIT_ASSERT (items.size() == 4);
+ i = items.begin ();
+ CPPUNIT_ASSERT (*i++ == canvas.root ());
+ CPPUNIT_ASSERT (*i++ == &gA);
+ CPPUNIT_ASSERT (*i++ == &gB);
+ CPPUNIT_ASSERT (*i++ == &rC);
+}
+
+static double
+double_random ()
+{
+ return ((double) rand() / RAND_MAX);
+}
+
+/* Check the find items at point code more thoroughly */
+void
+GroupTest::torture_add_items_at_point ()
+{
+ int const n_rectangles = 10000;
+ int const n_tests = 1000;
+ double const rough_size = 1000;
+ srand (1);
+
+ ImageCanvas canvas;
+
+ list<Item*> rectangles;
+
+ for (int i = 0; i < n_rectangles; ++i) {
+ Rectangle* r = new Rectangle (canvas.root());
+ double const x = double_random () * rough_size / 2;
+ double const y = double_random () * rough_size / 2;
+ double const w = double_random () * rough_size / 2;
+ double const h = double_random () * rough_size / 2;
+ r->set (Rect (x, y, x + w, y + h));
+ rectangles.push_back (r);
+ }
+
+ for (int i = 0; i < n_tests; ++i) {
+ Duple test (double_random() * rough_size, double_random() * rough_size);
+
+ /* ask the group what's at this point */
+ vector<Item const *> items_A;
+ canvas.root()->add_items_at_point (test, items_A);
+
+ /* work it out ourselves */
+ vector<Item*> items_B;
+ if (canvas.root()->bounding_box() && canvas.root()->bounding_box().get().contains (test)) {
+ items_B.push_back (canvas.root());
+ }
+
+ for (list<Item*>::iterator j = rectangles.begin(); j != rectangles.end(); ++j) {
+ boost::optional<Rect> bbox = (*j)->bounding_box ();
+ assert (bbox);
+ if (bbox.get().contains (test)) {
+ items_B.push_back (*j);
+ }
+ }
+
+ CPPUNIT_ASSERT (items_A.size() == items_B.size());
+ vector<Item const *>::iterator j = items_A.begin ();
+ vector<Item*>::iterator k = items_B.begin ();
+ while (j != items_A.end ()) {
+ CPPUNIT_ASSERT (*j == *k);
+ ++j;
+ ++k;
+ }
+ }
+}
+
diff --git a/libs/canvas/test/group.h b/libs/canvas/test/group.h
new file mode 100644
index 0000000000..1dcb371d2f
--- /dev/null
+++ b/libs/canvas/test/group.h
@@ -0,0 +1,24 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class GroupTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (GroupTest);
+ CPPUNIT_TEST (bounding_box);
+ CPPUNIT_TEST (null_bounding_box);
+ CPPUNIT_TEST (layers);
+ CPPUNIT_TEST (children_changing);
+ CPPUNIT_TEST (grandchildren_changing);
+ CPPUNIT_TEST (add_items_at_point);
+ CPPUNIT_TEST (torture_add_items_at_point);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void bounding_box ();
+ void null_bounding_box ();
+ void layers ();
+ void children_changing ();
+ void grandchildren_changing ();
+ void add_items_at_point ();
+ void torture_add_items_at_point ();
+};
diff --git a/libs/canvas/test/gtk_drag.cc b/libs/canvas/test/gtk_drag.cc
new file mode 100644
index 0000000000..8628c4cfd4
--- /dev/null
+++ b/libs/canvas/test/gtk_drag.cc
@@ -0,0 +1,68 @@
+#include <iostream>
+#include <gtkmm.h>
+#include "canvas/canvas.h"
+#include "canvas/rectangle.h"
+#include "canvas/pixbuf.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+Rectangle* rectangle = 0;
+
+bool
+event (GdkEvent* ev)
+{
+ static bool dragging = false;
+ static Duple offset;
+
+ if (ev->type == GDK_BUTTON_PRESS) {
+ GdkEventButton* b = reinterpret_cast<GdkEventButton*> (ev);
+ if (b->button == 1) {
+ dragging = true;
+ offset = Duple (b->x, b->y) - rectangle->position ();
+ rectangle->grab ();
+ cout << "Dragging offset=" << offset << "\n";
+ }
+ } else if (ev->type == GDK_BUTTON_RELEASE) {
+ GdkEventButton* b = reinterpret_cast<GdkEventButton*> (ev);
+ cout << "Release.\n";
+ if (b->button == 1) {
+ dragging = false;
+ rectangle->ungrab ();
+ cout << "Drag complete.\n";
+ }
+ } else if (ev->type == GDK_MOTION_NOTIFY) {
+ GdkEventMotion* m = reinterpret_cast<GdkEventMotion*> (ev);
+ if (dragging) {
+ rectangle->set_position (Duple (m->x, m->y) - offset);
+ cout << "Move to " << (Duple (m->x, m->y) - offset) << "\n";
+ }
+ }
+
+ return true;
+}
+
+int main (int argc, char* argv[])
+{
+ Gtk::Main kit (argc, argv);
+
+ Gtk::Window window;
+ window.set_title ("Hello world");
+ window.set_size_request (768, 768);
+
+ Gtk::Adjustment hadj (0, 0, 1e3);
+ Gtk::Adjustment vadj (0, 0, 1e3);
+ GtkCanvasViewport viewport (hadj, vadj);
+ GtkCanvas* canvas = viewport.canvas ();
+
+ rectangle = new Rectangle (canvas->root(), Rect (64, 64, 128, 128));
+ rectangle->set_outline_color (0xff0000aa);
+ rectangle->Event.connect (sigc::ptr_fun (event));
+
+ window.add (viewport);
+ canvas->show ();
+ window.show_all ();
+
+ Gtk::Main::run (window);
+ return 0;
+}
diff --git a/libs/canvas/test/gtk_many.cc b/libs/canvas/test/gtk_many.cc
new file mode 100644
index 0000000000..e75ce05ac0
--- /dev/null
+++ b/libs/canvas/test/gtk_many.cc
@@ -0,0 +1,39 @@
+#include <iostream>
+#include <gtkmm.h>
+#include "canvas/canvas.h"
+#include "canvas/rectangle.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+int main (int argc, char* argv[])
+{
+ Gtk::Main kit (argc, argv);
+
+ Gtk::Window window;
+ window.set_title ("Hello world");
+ window.set_size_request (512, 512);
+ GtkCanvas canvas;
+ canvas.set_size_request (2048, 2048);
+
+ int const N = 10000;
+ double Ns = sqrt (N);
+ int max_x = 1024;
+ int max_y = 1024;
+
+ for (int x = 0; x < Ns; ++x) {
+ for (int y = 0; y < Ns; ++y) {
+ Rectangle* r = new Rectangle (canvas.root ());
+ r->set (Rect (x * max_x / Ns, y * max_y / Ns, (x + 1) * max_x / Ns, (y + 1) * max_y / Ns));
+ }
+ }
+
+ Gtk::ScrolledWindow scroller;
+ scroller.add (canvas);
+ window.add (scroller);
+ canvas.show ();
+ window.show_all ();
+
+ Gtk::Main::run (window);
+ return 0;
+}
diff --git a/libs/canvas/test/gtk_movement.cc b/libs/canvas/test/gtk_movement.cc
new file mode 100644
index 0000000000..24a517da71
--- /dev/null
+++ b/libs/canvas/test/gtk_movement.cc
@@ -0,0 +1,97 @@
+#include <iostream>
+#include <gtkmm.h>
+#include "canvas/canvas.h"
+#include "canvas/rectangle.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+Rectangle* rectangle[2];
+
+void
+bigger_clicked ()
+{
+ Rect r = rectangle[0]->get ();
+ r.x1 += 16;
+ r.y1 += 16;
+ rectangle[0]->set (r);
+}
+
+void
+smaller_clicked ()
+{
+ Rect r = rectangle[0]->get ();
+ r.x1 -= 16;
+ r.y1 -= 16;
+ rectangle[0]->set (r);
+}
+
+void
+left_clicked ()
+{
+ Duple p = rectangle[0]->position ();
+ p.x -= 16;
+ rectangle[0]->set_position (p);
+}
+
+void
+right_clicked ()
+{
+ Duple p = rectangle[0]->position ();
+ p.x += 16;
+ rectangle[0]->set_position (p);
+}
+
+int main (int argc, char* argv[])
+{
+ Gtk::Main kit (argc, argv);
+
+ Gtk::Window window;
+ window.set_title ("Hello world");
+ window.set_size_request (512, 512);
+ GtkCanvas canvas;
+ canvas.set_size_request (2048, 2048);
+
+ rectangle[0] = new Rectangle (canvas.root(), Rect (64, 64, 128, 128));
+ rectangle[0]->set_outline_color (0xff0000aa);
+ rectangle[1] = new Rectangle (canvas.root(), Rect (64, 64, 128, 128));
+ rectangle[1]->set_position (Duple (256, 256));
+ rectangle[1]->set_outline_width (4);
+ rectangle[1]->set_outline_color (0x00ff00ff);
+ rectangle[1]->set_fill (true);
+ rectangle[1]->set_fill_color (0x00ffffff);
+ rectangle[1]->set_outline_what ((Rectangle::What) (Rectangle::LEFT | Rectangle::RIGHT));
+
+ Gtk::VBox overall_box;
+
+ Gtk::ScrolledWindow scroller;
+ scroller.add (canvas);
+ overall_box.pack_start (scroller);
+
+ Gtk::HBox button_box;
+
+ Gtk::Button bigger ("Bigger");
+ bigger.signal_clicked().connect (sigc::ptr_fun (&bigger_clicked));
+ button_box.pack_start (bigger);
+
+ Gtk::Button smaller ("Smaller");
+ smaller.signal_clicked().connect (sigc::ptr_fun (&smaller_clicked));
+ button_box.pack_start (smaller);
+
+ Gtk::Button left ("Left");
+ left.signal_clicked().connect (sigc::ptr_fun (&left_clicked));
+ button_box.pack_start (left);
+
+ Gtk::Button right ("Right");
+ right.signal_clicked().connect (sigc::ptr_fun (&right_clicked));
+ button_box.pack_start (right);
+
+ overall_box.pack_start (button_box, false, false);
+
+ window.add (overall_box);
+ canvas.show ();
+ window.show_all ();
+
+ Gtk::Main::run (window);
+ return 0;
+}
diff --git a/libs/canvas/test/gtk_scene.cc b/libs/canvas/test/gtk_scene.cc
new file mode 100644
index 0000000000..95e9b9c299
--- /dev/null
+++ b/libs/canvas/test/gtk_scene.cc
@@ -0,0 +1,66 @@
+#include <iostream>
+#include <gtkmm.h>
+#include "canvas/canvas.h"
+#include "canvas/rectangle.h"
+#include "canvas/line.h"
+#include "canvas/pixbuf.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+bool
+foo (GdkEvent* ev)
+{
+ cout << "click.\n";
+ return true;
+}
+
+int main (int argc, char* argv[])
+{
+ Gtk::Main kit (argc, argv);
+
+ Gtk::Window window;
+ window.set_title ("Hello world");
+ window.set_size_request (512, 512);
+
+ Gtk::VBox overall_vbox;
+ Gtk::HScrollbar h_scroll;
+ Gtk::VScrollbar v_scroll;
+
+ GtkCanvasViewport viewport (*h_scroll.get_adjustment(), *v_scroll.get_adjustment());
+ GtkCanvas* canvas = viewport.canvas ();
+
+ overall_vbox.pack_start (viewport, true, true);
+ overall_vbox.pack_start (h_scroll, false, false);
+
+ Rectangle a (canvas->root(), Rect (64, 64, 128, 128));
+ a.set_outline_color (0xff0000aa);
+ Rectangle b (canvas->root(), Rect (64, 64, 128, 128));
+ b.set_position (Duple (256, 256));
+ b.set_outline_width (4);
+ b.set_outline_what (0x2 | 0x8);
+ b.set_outline_color (0x0000ffff);
+ b.Event.connect (sigc::ptr_fun (foo));
+
+ Rectangle c (canvas->root(), Rect (2048, 2048, 2096, 2096));
+
+ Rectangle d (canvas->root(), Rect (0, 256, COORD_MAX, 284));
+ d.name = "d";
+
+ Line e (canvas->root());
+ e.set (Duple (256, 0), Duple (256, COORD_MAX));
+ e.name = "e";
+ e.set_outline_color (0xff0000ff);
+
+ Pixbuf pixbuf (canvas->root());
+ pixbuf.set_position (Duple (192, 192));
+ Glib::RefPtr<Gdk::Pixbuf> p = Gdk::Pixbuf::create_from_file ("../../libs/canvas/test/test.png");
+ pixbuf.set (p);
+
+ window.add (overall_vbox);
+ canvas->show ();
+ window.show_all ();
+
+ Gtk::Main::run (window);
+ return 0;
+}
diff --git a/libs/canvas/test/gtk_viewport.cc b/libs/canvas/test/gtk_viewport.cc
new file mode 100644
index 0000000000..90bf819d86
--- /dev/null
+++ b/libs/canvas/test/gtk_viewport.cc
@@ -0,0 +1,65 @@
+#include <iostream>
+#include <gtkmm.h>
+#include "canvas/canvas.h"
+#include "canvas/rectangle.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+Gtk::Adjustment* hadj;
+Gtk::Adjustment* vadj;
+
+void
+left_clicked ()
+{
+ hadj->set_value (hadj->get_value() - 64);
+}
+
+void
+right_clicked ()
+{
+ hadj->set_value (hadj->get_value() + 64);
+}
+
+int main (int argc, char* argv[])
+{
+ Gtk::Main kit (argc, argv);
+
+ Gtk::Window window;
+ window.set_title ("Hello world");
+ GtkCanvas canvas;
+
+ Rectangle a (canvas.root(), Rect (64, 64, 128, 128));
+ a.set_outline_color (0xff0000aa);
+ Rectangle b (canvas.root(), Rect (64, 64, 128, 128));
+ b.set_position (Duple (256, 256));
+ b.set_outline_width (4);
+ b.set_outline_color (0x00ff00ff);
+
+ Gtk::HBox button_box;
+
+ Gtk::Button left ("Left");
+ left.signal_clicked().connect (sigc::ptr_fun (&left_clicked));
+ button_box.pack_start (left);
+
+ Gtk::Button right ("Right");
+ right.signal_clicked().connect (sigc::ptr_fun (&right_clicked));
+ button_box.pack_start (right);
+
+ hadj = new Gtk::Adjustment (0, 0, 1e3);
+ vadj = new Gtk::Adjustment (0, 0, 1e3);
+
+ Gtk::Viewport viewport (*hadj, *vadj);
+ viewport.add (canvas);
+
+ Gtk::VBox overall_box;
+ overall_box.pack_start (viewport);
+ overall_box.pack_start (button_box, false, false);
+
+ window.add (overall_box);
+ canvas.show ();
+ window.show_all ();
+
+ Gtk::Main::run (window);
+ return 0;
+}
diff --git a/libs/canvas/test/hello_world.cc b/libs/canvas/test/hello_world.cc
new file mode 100644
index 0000000000..38944f9220
--- /dev/null
+++ b/libs/canvas/test/hello_world.cc
@@ -0,0 +1,13 @@
+#include "canvas/canvas.h"
+#include "canvas/rectangle.h"
+
+using namespace ArdourCanvas;
+
+int main ()
+{
+ ImageCanvas* c = new ImageCanvas;
+ Rectangle* r = new Rectangle (c->root ());
+ r->set (Rect (0, 0, 256, 256));
+ c->render_to_image (Rect (0, 0, 1024, 1024));
+ c->write_to_png ("foo.png");
+}
diff --git a/libs/canvas/test/item.cc b/libs/canvas/test/item.cc
new file mode 100644
index 0000000000..96ea2d2f15
--- /dev/null
+++ b/libs/canvas/test/item.cc
@@ -0,0 +1,28 @@
+#include "canvas/group.h"
+#include "canvas/item.h"
+#include "canvas/canvas.h"
+#include "canvas/rectangle.h"
+#include "item.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (ItemTest);
+
+void
+ItemTest::item_to_canvas ()
+{
+ ImageCanvas canvas;
+ Group gA (canvas.root ());
+ gA.set_position (Duple (128, 128));
+ Group gB (&gA);
+ gB.set_position (Duple (45, 55));
+ Rectangle rA (&gB);
+ rA.set_position (Duple (99, 23));
+
+ Rect const r = rA.item_to_canvas (Rect (3, 6, 7, 9));
+ CPPUNIT_ASSERT (r.x0 == (128 + 45 + 99 + 3));
+ CPPUNIT_ASSERT (r.y0 == (128 + 55 + 23 + 6));
+ CPPUNIT_ASSERT (r.x1 == (128 + 45 + 99 + 7));
+ CPPUNIT_ASSERT (r.y1 == (128 + 55 + 23 + 9));
+}
diff --git a/libs/canvas/test/item.h b/libs/canvas/test/item.h
new file mode 100644
index 0000000000..f69cb03f44
--- /dev/null
+++ b/libs/canvas/test/item.h
@@ -0,0 +1,12 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class ItemTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (ItemTest);
+ CPPUNIT_TEST (item_to_canvas);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void item_to_canvas ();
+};
diff --git a/libs/canvas/test/optimizing_lookup_table.cc b/libs/canvas/test/optimizing_lookup_table.cc
new file mode 100644
index 0000000000..8449b26498
--- /dev/null
+++ b/libs/canvas/test/optimizing_lookup_table.cc
@@ -0,0 +1,141 @@
+#include "canvas/lookup_table.h"
+#include "canvas/types.h"
+#include "canvas/rectangle.h"
+#include "canvas/group.h"
+#include "canvas/canvas.h"
+#include "optimizing_lookup_table.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (OptimizingLookupTableTest);
+
+void
+OptimizingLookupTableTest::build_1 ()
+{
+ ImageCanvas canvas;
+ Rectangle a (canvas.root(), Rect (0, 0, 32, 32));
+ a.set_outline_width (0);
+ Rectangle b (canvas.root(), Rect (0, 33, 32, 64));
+ b.set_outline_width (0);
+ Rectangle c (canvas.root(), Rect (33, 0, 64, 32));
+ c.set_outline_width (0);
+ Rectangle d (canvas.root(), Rect (33, 33, 64, 64));
+ d.set_outline_width (0);
+ OptimizingLookupTable table (*canvas.root(), 1);
+
+ CPPUNIT_ASSERT (table._items_per_cell == 1);
+ CPPUNIT_ASSERT (table._cell_size.x == 32);
+ CPPUNIT_ASSERT (table._cell_size.y == 32);
+ CPPUNIT_ASSERT (table._cells[0][0].front() == &a);
+ CPPUNIT_ASSERT (table._cells[0][1].front() == &b);
+ CPPUNIT_ASSERT (table._cells[1][0].front() == &c);
+ CPPUNIT_ASSERT (table._cells[1][1].front() == &d);
+}
+
+void
+OptimizingLookupTableTest::build_2 ()
+{
+ ImageCanvas canvas;
+ Rectangle a (canvas.root(), Rect (0, 0, 713, 1024));
+ a.set_outline_width (0);
+ Rectangle b (canvas.root(), Rect (0, 0, 0, 1024));
+ b.set_outline_width (0);
+ OptimizingLookupTable table (*canvas.root(), 64);
+}
+
+void
+OptimizingLookupTableTest::build_negative ()
+{
+ ImageCanvas canvas;
+ Rectangle a (canvas.root(), Rect (-32, -32, 32, 32));
+ OptimizingLookupTable table (*canvas.root(), 1);
+}
+
+void
+OptimizingLookupTableTest::get_small ()
+{
+ ImageCanvas canvas;
+ Rectangle a (canvas.root(), Rect (0, 0, 32, 32));
+ a.set_outline_width (0);
+ Rectangle b (canvas.root(), Rect (0, 33, 32, 64));
+ b.set_outline_width (0);
+ Rectangle c (canvas.root(), Rect (33, 0, 64, 32));
+ c.set_outline_width (0);
+ Rectangle d (canvas.root(), Rect (33, 33, 64, 64));
+ d.set_outline_width (0);
+ OptimizingLookupTable table (*canvas.root(), 1);
+
+ vector<Item*> items = table.get (Rect (16, 16, 48, 48));
+ CPPUNIT_ASSERT (items.size() == 4);
+
+ items = table.get (Rect (32, 32, 33, 33));
+ CPPUNIT_ASSERT (items.size() == 1);
+}
+
+void
+OptimizingLookupTableTest::get_big ()
+{
+ ImageCanvas canvas;
+
+ double const s = 8;
+ int const N = 1024;
+
+ for (int x = 0; x < N; ++x) {
+ for (int y = 0; y < N; ++y) {
+ Rectangle* r = new Rectangle (canvas.root());
+ r->set_outline_width (0);
+ r->set (Rect (x * s, y * s, (x + 1) * s, (y + 1) * s));
+ }
+ }
+
+ OptimizingLookupTable table (*canvas.root(), 16);
+ vector<Item*> items = table.get (Rect (0, 0, 15, 15));
+ CPPUNIT_ASSERT (items.size() == 16);
+}
+
+/** Check that calling OptimizingLookupTable::get() returns things in the correct order.
+ * The order should be the same as it is in the owning group.
+ */
+void
+OptimizingLookupTableTest::check_ordering ()
+{
+ ImageCanvas canvas;
+
+ Rectangle a (canvas.root (), Rect (0, 0, 64, 64));
+ Rectangle b (canvas.root (), Rect (0, 0, 64, 64));
+ Rectangle c (canvas.root (), Rect (0, 0, 64, 64));
+
+ /* since there have been bugs introduced due to sorting pointers,
+ get these rectangles in ascending order of their address
+ */
+
+ list<Item*> items;
+ items.push_back (&a);
+ items.push_back (&b);
+ items.push_back (&c);
+ items.sort ();
+
+ /* now arrange these items in the group in reverse order of address */
+
+ for (list<Item*>::reverse_iterator i = items.rbegin(); i != items.rend(); ++i) {
+ (*i)->raise_to_top ();
+ }
+
+ /* ask the LUT for the items */
+
+ canvas.root()->ensure_lut ();
+ vector<Item*> lut_items = canvas.root()->_lut->get (Rect (0, 0, 64, 64));
+ CPPUNIT_ASSERT (lut_items.size() == 3);
+
+ /* check that they are in the right order */
+
+ vector<Item*>::iterator i = lut_items.begin ();
+ list<Item*>::reverse_iterator j = items.rbegin ();
+
+ while (i != lut_items.end ()) {
+ CPPUNIT_ASSERT (*i == *j);
+ ++i;
+ ++j;
+ }
+}
diff --git a/libs/canvas/test/optimizing_lookup_table.h b/libs/canvas/test/optimizing_lookup_table.h
new file mode 100644
index 0000000000..a7c0b494bb
--- /dev/null
+++ b/libs/canvas/test/optimizing_lookup_table.h
@@ -0,0 +1,25 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class OptimizingLookupTableTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (OptimizingLookupTableTest);
+ CPPUNIT_TEST (build_1);
+ CPPUNIT_TEST (build_2);
+ CPPUNIT_TEST (build_negative);
+ CPPUNIT_TEST (get_big);
+ CPPUNIT_TEST (get_small);
+ CPPUNIT_TEST (check_ordering);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void build_1 ();
+ void build_2 ();
+ void build_negative ();
+ void get_big ();
+ void get_small ();
+ void check_ordering ();
+};
+
+
+
diff --git a/libs/canvas/test/polygon.cc b/libs/canvas/test/polygon.cc
new file mode 100644
index 0000000000..353246ffe0
--- /dev/null
+++ b/libs/canvas/test/polygon.cc
@@ -0,0 +1,49 @@
+#include "canvas/group.h"
+#include "canvas/types.h"
+#include "canvas/polygon.h"
+#include "canvas/canvas.h"
+#include "polygon.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (PolygonTest);
+
+void
+PolygonTest::bounding_box ()
+{
+ ImageCanvas canvas;
+ Group group (canvas.root ());
+ Polygon polygon (&group);
+
+ /* should have no initial bounding box */
+ CPPUNIT_ASSERT (!polygon.bounding_box().is_initialized());
+
+ Points points;
+ points.push_back (Duple (-6, -6));
+ points.push_back (Duple ( 6, -6));
+ points.push_back (Duple ( 6, 6));
+ points.push_back (Duple (-6, 6));
+ polygon.set (points);
+
+ /* should now have a bounding box around those points,
+ taking into account default line width
+ */
+ boost::optional<Rect> bbox = polygon.bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == -6.25);
+ CPPUNIT_ASSERT (bbox.get().x1 == 6.25);
+ CPPUNIT_ASSERT (bbox.get().y0 == -6.25);
+ CPPUNIT_ASSERT (bbox.get().y1 == 6.25);
+
+ /* and its parent group should have noticed and adjusted
+ its bounding box
+ */
+
+ bbox = group.bounding_box ();
+ CPPUNIT_ASSERT (bbox.is_initialized ());
+ CPPUNIT_ASSERT (bbox.get().x0 == -6.25);
+ CPPUNIT_ASSERT (bbox.get().x1 == 6.25);
+ CPPUNIT_ASSERT (bbox.get().y0 == -6.25);
+ CPPUNIT_ASSERT (bbox.get().y1 == 6.25);
+}
diff --git a/libs/canvas/test/polygon.h b/libs/canvas/test/polygon.h
new file mode 100644
index 0000000000..b8f6fab17d
--- /dev/null
+++ b/libs/canvas/test/polygon.h
@@ -0,0 +1,12 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class PolygonTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (PolygonTest);
+ CPPUNIT_TEST (bounding_box);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void bounding_box ();
+};
diff --git a/libs/canvas/test/render.cc b/libs/canvas/test/render.cc
new file mode 100644
index 0000000000..96bd7eb166
--- /dev/null
+++ b/libs/canvas/test/render.cc
@@ -0,0 +1,86 @@
+#include <pangomm/init.h>
+#include "canvas/canvas.h"
+#include "canvas/line.h"
+#include "canvas/rectangle.h"
+#include "canvas/polygon.h"
+#include "canvas/arrow.h"
+#include "canvas/text.h"
+#include "render.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (RenderTest);
+
+void
+RenderTest::check (string const & name)
+{
+ stringstream s;
+ s << "diff -q " << name << ".png " << "../../libs/canvas/test/" << name << ".png";
+ int r = system (s.str().c_str());
+ CPPUNIT_ASSERT (WEXITSTATUS (r) == 0);
+}
+
+void
+RenderTest::basics ()
+{
+ ImageCanvas canvas (Duple (256, 256));
+
+ /* line */
+ Group line_group (canvas.root ());
+ line_group.set_position (Duple (0, 0));
+ Line line (&line_group);
+ line.set (Duple (0, 0), Duple (32, 32));
+ line.set_outline_width (2);
+
+ /* rectangle */
+ Group rectangle_group (canvas.root ());
+ rectangle_group.set_position (Duple (64, 0));
+ Rectangle rectangle (&rectangle_group);
+ rectangle.set (Rect (0, 0, 32, 32));
+ rectangle.set_outline_width (2);
+ rectangle.set_outline_color (0x00ff00ff);
+ rectangle.set_fill_color (0x0000ffff);
+
+ /* poly line */
+ Group poly_line_group (canvas.root ());
+ poly_line_group.set_position (Duple (0, 64));
+ PolyLine poly_line (&poly_line_group);
+ Points points;
+ points.push_back (Duple (0, 0));
+ points.push_back (Duple (16, 48));
+ points.push_back (Duple (32, 32));
+ poly_line.set (points);
+ poly_line.set_outline_color (0xff0000ff);
+ poly_line.set_outline_width (2);
+
+ /* polygon */
+ Group polygon_group (canvas.root ());
+ polygon_group.set_position (Duple (64, 64));
+ Polygon polygon (&polygon_group);
+ polygon.set (points);
+ polygon.set_outline_color (0xff00ffff);
+ polygon.set_fill_color (0xcc00ffff);
+ polygon.set_outline_width (2);
+
+ /* arrow */
+ Group arrow_group (canvas.root ());
+ arrow_group.set_position (Duple (128, 0));
+ Arrow arrow (&arrow_group);
+ arrow.set_outline_width (2);
+ arrow.set_x (32);
+ arrow.set_y0 (0);
+ arrow.set_y1 (64);
+
+ /* text */
+ Pango::init ();
+ Group text_group (canvas.root ());
+ text_group.set_position (Duple (128, 64));
+ Text text (&text_group);
+ text.set ("Hello world!");
+
+ canvas.render_to_image (Rect (0, 0, 256, 256));
+ canvas.write_to_png ("render_basics.png");
+
+ check ("render_basics");
+}
diff --git a/libs/canvas/test/render.h b/libs/canvas/test/render.h
new file mode 100644
index 0000000000..7596a56573
--- /dev/null
+++ b/libs/canvas/test/render.h
@@ -0,0 +1,14 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class RenderTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (RenderTest);
+ CPPUNIT_TEST (basics);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void basics ();
+ void check (std::string const &);
+};
+
diff --git a/libs/canvas/test/test.xml b/libs/canvas/test/test.xml
new file mode 100644
index 0000000000..9b976649a6
--- /dev/null
+++ b/libs/canvas/test/test.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Canvas>
+ <Group x-position="0" y-position="0" visible="yes">
+ <Rectangle x0="0" y0="0" x1="16" y1="16" outline-what="15" x-position="0" y-position="0" visible="yes" outline-color="305419896" outline="yes" outline-width="0.5" fill-color="255" fill="yes"/>
+ <Group x-position="64" y-position="72" visible="yes">
+ <Line x0="41" y0="43" x1="44" y1="46" x-position="0" y-position="0" visible="yes" outline-color="255" outline="yes" outline-width="0.5"/>
+ </Group>
+ </Group>
+</Canvas>
diff --git a/libs/canvas/test/testrunner.cpp b/libs/canvas/test/testrunner.cpp
new file mode 100644
index 0000000000..468af59ae4
--- /dev/null
+++ b/libs/canvas/test/testrunner.cpp
@@ -0,0 +1,27 @@
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TestRunner.h>
+#include <cppunit/BriefTestProgressListener.h>
+
+int
+main()
+{
+ CppUnit::TestResult testresult;
+
+ CppUnit::TestResultCollector collectedresults;
+ testresult.addListener (&collectedresults);
+
+ CppUnit::BriefTestProgressListener progress;
+ testresult.addListener (&progress);
+
+ CppUnit::TestRunner testrunner;
+ testrunner.addTest (CppUnit::TestFactoryRegistry::getRegistry ().makeTest ());
+ testrunner.run (testresult);
+
+ CppUnit::CompilerOutputter compileroutputter (&collectedresults, std::cerr);
+ compileroutputter.write ();
+
+ return collectedresults.wasSuccessful () ? 0 : 1;
+}
diff --git a/libs/canvas/test/types.cc b/libs/canvas/test/types.cc
new file mode 100644
index 0000000000..69667466de
--- /dev/null
+++ b/libs/canvas/test/types.cc
@@ -0,0 +1,54 @@
+#include "canvas/types.h"
+#include "types.h"
+
+using namespace std;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (TypesTest);
+
+void
+TypesTest::intersect ()
+{
+ {
+ Rect a (0, 0, 1024, 1024);
+ Rect b (0, 0, 512, 512);
+ boost::optional<Rect> c = a.intersection (b);
+
+ CPPUNIT_ASSERT (c.is_initialized ());
+ CPPUNIT_ASSERT (c->x0 == 0);
+ CPPUNIT_ASSERT (c->x1 == 512);
+ CPPUNIT_ASSERT (c->y0 == 0);
+ CPPUNIT_ASSERT (c->y1 == 512);
+ }
+
+ {
+ Rect a (0, 0, 512, 512);
+ Rect b (513, 513, 1024, 1024);
+ boost::optional<Rect> c = a.intersection (b);
+
+ CPPUNIT_ASSERT (!c.is_initialized ());
+ }
+}
+
+void
+TypesTest::extend ()
+{
+ {
+ Rect a (50, 60, 70, 80);
+ Rect b (100, 110, 120, 130);
+ Rect c = a.extend (b);
+
+ CPPUNIT_ASSERT (c.x0 == 50);
+ CPPUNIT_ASSERT (c.y0 == 60);
+ CPPUNIT_ASSERT (c.x1 == 120);
+ CPPUNIT_ASSERT (c.y1 == 130);
+ }
+}
+
+void
+TypesTest::test_safe_add ()
+{
+ CPPUNIT_ASSERT (safe_add (4, 9) == 13);
+ CPPUNIT_ASSERT (safe_add (4, COORD_MAX) == COORD_MAX);
+ CPPUNIT_ASSERT (safe_add (COORD_MAX, 4) == COORD_MAX);
+}
diff --git a/libs/canvas/test/types.h b/libs/canvas/test/types.h
new file mode 100644
index 0000000000..3a5c0dac9b
--- /dev/null
+++ b/libs/canvas/test/types.h
@@ -0,0 +1,18 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class TypesTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (TypesTest);
+ CPPUNIT_TEST (intersect);
+ CPPUNIT_TEST (extend);
+ CPPUNIT_TEST (test_safe_add);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void intersect ();
+ void extend ();
+ void test_safe_add ();
+};
+
+
diff --git a/libs/canvas/test/wave_view.cc b/libs/canvas/test/wave_view.cc
new file mode 100644
index 0000000000..9b95930cf1
--- /dev/null
+++ b/libs/canvas/test/wave_view.cc
@@ -0,0 +1,164 @@
+#include <gtkmm/main.h>
+#include "pbd/textreceiver.h"
+#include "gtkmm2ext/utils.h"
+#include "midi++/manager.h"
+#include "ardour/session.h"
+#include "ardour/audioengine.h"
+#include "ardour/source_factory.h"
+#include "ardour/audiosource.h"
+#include "ardour/audiofilesource.h"
+#include "ardour/region_factory.h"
+#include "ardour/audioregion.h"
+#include "canvas/wave_view.h"
+#include "canvas/canvas.h"
+#include "wave_view.h"
+
+using namespace std;
+using namespace PBD;
+using namespace ARDOUR;
+using namespace ArdourCanvas;
+
+CPPUNIT_TEST_SUITE_REGISTRATION (WaveViewTest);
+
+TextReceiver text_receiver ("test");
+
+void
+WaveViewTest::setUp ()
+{
+ init (false, true);
+ Gtkmm2ext::init ();
+ SessionEvent::create_per_thread_pool ("test", 512);
+
+ Gtk::Main kit ();
+ Gtk::Main::init_gtkmm_internals ();
+
+ text_receiver.listen_to (error);
+ text_receiver.listen_to (info);
+ text_receiver.listen_to (fatal);
+ text_receiver.listen_to (warning);
+
+ AudioFileSource::set_build_peakfiles (true);
+ AudioFileSource::set_build_missing_peakfiles (true);
+
+ AudioEngine engine ("test", "");
+ MIDI::Manager::create (engine.jack ());
+ CPPUNIT_ASSERT (engine.start () == 0);
+
+ Session session (engine, "tmp_session", "tmp_session");
+ engine.set_session (&session);
+
+ char buf[256];
+ getcwd (buf, sizeof (buf));
+ string const path = string_compose ("%1/../../libs/canvas/test/sine.wav", buf);
+
+ boost::shared_ptr<Source> source = SourceFactory::createReadable (
+ DataType::AUDIO, session, path, 0, (Source::Flag) 0, false, true
+ );
+
+ boost::shared_ptr<AudioFileSource> audio_file_source = boost::dynamic_pointer_cast<AudioFileSource> (source);
+
+ audio_file_source->setup_peakfile ();
+
+ PBD::PropertyList properties;
+ properties.add (Properties::position, 128);
+ properties.add (Properties::length, audio_file_source->readable_length ());
+ _region = RegionFactory::create (source, properties, false);
+ _audio_region = boost::dynamic_pointer_cast<AudioRegion> (_region);
+}
+
+void
+WaveViewTest::make_canvas ()
+{
+ /* this leaks various things, but hey ho */
+
+ _canvas = new ImageCanvas (Duple (256, 256));
+ _wave_view = new WaveView (_canvas->root(), _audio_region);
+ _wave_view->set_frames_per_pixel ((double) (44100 / 1000) / 64);
+ _wave_view->set_height (64);
+}
+
+void
+WaveViewTest::all ()
+{
+ /* XXX: we run these all from the same method so that the setUp code only
+ gets called once; there are various singletons etc. in Ardour which don't
+ like being recreated.
+ */
+
+ render_all_at_once ();
+ render_in_pieces ();
+ cache ();
+}
+
+void
+WaveViewTest::render_all_at_once ()
+{
+ make_canvas ();
+
+ _canvas->render_to_image (Rect (0, 0, 256, 256));
+ _canvas->write_to_png ("waveview_1.png");
+
+ /* XXX: doesn't check the result! */
+}
+
+void
+WaveViewTest::render_in_pieces ()
+{
+ make_canvas ();
+
+ cout << "\n\n--------------> PIECES\n";
+ _canvas->render_to_image (Rect (0, 0, 128, 256));
+ _canvas->render_to_image (Rect (128, 0, 256, 256));
+ _canvas->write_to_png ("waveview_2.png");
+ cout << "\n\n<-------------- PIECES\n";
+
+ /* XXX: doesn't check the result! */
+}
+
+void
+WaveViewTest::cache ()
+{
+ make_canvas ();
+
+ /* Whole of the render area needs caching from scratch */
+
+ _wave_view->invalidate_whole_cache ();
+
+ Rect whole (0, 0, 256, 256);
+ _canvas->render_to_image (whole);
+
+ CPPUNIT_ASSERT (_wave_view->_cache.size() == 1);
+ CPPUNIT_ASSERT (_wave_view->_cache.front()->start() == 0);
+ CPPUNIT_ASSERT (_wave_view->_cache.front()->end() == 256);
+
+ _wave_view->invalidate_whole_cache ();
+
+ /* Render a bit in the middle */
+
+ Rect part1 (128, 0, 196, 256);
+ _canvas->render_to_image (part1);
+
+ CPPUNIT_ASSERT (_wave_view->_cache.size() == 1);
+ CPPUNIT_ASSERT (_wave_view->_cache.front()->start() == 128);
+ CPPUNIT_ASSERT (_wave_view->_cache.front()->end() == 196);
+
+ /* Now render the whole thing and check that the cache sorts itself out */
+
+ _canvas->render_to_image (whole);
+
+ CPPUNIT_ASSERT (_wave_view->_cache.size() == 3);
+
+ list<WaveView::CacheEntry*>::iterator i = _wave_view->_cache.begin ();
+
+ CPPUNIT_ASSERT ((*i)->start() == 0);
+ CPPUNIT_ASSERT ((*i)->end() == 128);
+ ++i;
+
+ CPPUNIT_ASSERT ((*i)->start() == 128);
+ CPPUNIT_ASSERT ((*i)->end() == 196);
+ ++i;
+
+ CPPUNIT_ASSERT ((*i)->start() == 196);
+ CPPUNIT_ASSERT ((*i)->end() == 256);
+ ++i;
+}
diff --git a/libs/canvas/test/wave_view.h b/libs/canvas/test/wave_view.h
new file mode 100644
index 0000000000..69f7ce772f
--- /dev/null
+++ b/libs/canvas/test/wave_view.h
@@ -0,0 +1,26 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class WaveViewTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (WaveViewTest);
+ CPPUNIT_TEST (all);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void setUp ();
+ void all ();
+
+private:
+ void make_canvas ();
+ void render_all_at_once ();
+ void render_in_pieces ();
+ void cache ();
+
+ ArdourCanvas::ImageCanvas* _canvas;
+ ArdourCanvas::WaveView* _wave_view;
+ boost::shared_ptr<ARDOUR::Region> _region;
+ boost::shared_ptr<ARDOUR::AudioRegion> _audio_region;
+};
+
+
diff --git a/libs/canvas/test/xml.cc b/libs/canvas/test/xml.cc
new file mode 100644
index 0000000000..ef6871dc76
--- /dev/null
+++ b/libs/canvas/test/xml.cc
@@ -0,0 +1,53 @@
+#include "pbd/xml++.h"
+#include "xml.h"
+#include "canvas/canvas.h"
+#include "canvas/rectangle.h"
+#include "canvas/line.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION (XMLTest);
+
+using namespace std;
+using namespace ArdourCanvas;
+
+void
+XMLTest::check (string const & name)
+{
+ stringstream s;
+ s << "diff -q " << name << ".xml " << "../../libs/canvas/test/" << name << ".xml";
+ int r = system (s.str().c_str());
+ CPPUNIT_ASSERT (WEXITSTATUS (r) == 0);
+}
+
+void
+XMLTest::get ()
+{
+ ImageCanvas canvas;
+
+ Rectangle r (canvas.root(), Rect (0, 0, 16, 16));
+ r.set_outline_color (0x12345678);
+ Group g (canvas.root());
+ g.set_position (Duple (64, 72));
+ Line l (&g);
+ l.set (Duple (41, 43), Duple (44, 46));
+
+ XMLTree* tree = canvas.get_state ();
+ tree->write ("test.xml");
+
+ check ("test");
+}
+
+void
+XMLTest::set ()
+{
+ XMLTree* tree = new XMLTree ("../../libs/canvas/test/test.xml");
+ ImageCanvas canvas (tree);
+
+ list<Item*> root_items = canvas.root()->items ();
+ CPPUNIT_ASSERT (root_items.size() == 2);
+
+ list<Item*>::iterator i = root_items.begin();
+ Rectangle* r = dynamic_cast<Rectangle*> (*i++);
+ CPPUNIT_ASSERT (r);
+ CPPUNIT_ASSERT (r->outline_color() == 0x12345678);
+ CPPUNIT_ASSERT (dynamic_cast<Group*> (*i++));
+}
diff --git a/libs/canvas/test/xml.h b/libs/canvas/test/xml.h
new file mode 100644
index 0000000000..fbe606c028
--- /dev/null
+++ b/libs/canvas/test/xml.h
@@ -0,0 +1,17 @@
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+class XMLTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (XMLTest);
+ CPPUNIT_TEST (get);
+ CPPUNIT_TEST (set);
+ CPPUNIT_TEST_SUITE_END ();
+
+public:
+ void get ();
+ void set ();
+
+private:
+ void check (std::string const &);
+};