[gtk/wip/baedert/transforms6: 64/78] Add picking/translation/compute_bounds unit tests



commit cc1c2896f0c35d0b3ef5d3e7ca90da8c649690b1
Author: Timm Bäder <mail baedert org>
Date:   Sat Aug 11 22:15:29 2018 +0200

    Add picking/translation/compute_bounds unit tests

 testsuite/gtk/meson.build |   1 +
 testsuite/gtk/translate.c | 397 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 398 insertions(+)
---
diff --git a/testsuite/gtk/meson.build b/testsuite/gtk/meson.build
index d86e035eff..ebb041f20d 100644
--- a/testsuite/gtk/meson.build
+++ b/testsuite/gtk/meson.build
@@ -51,6 +51,7 @@ tests = [
   ['textbuffer'],
   ['textiter'],
   ['treelistmodel'],
+  ['translate'],
   ['treemodel', ['treemodel.c', 'liststore.c', 'treestore.c', 'filtermodel.c',
                  'modelrefcount.c', 'sortmodel.c', 'gtktreemodelrefcount.c']],
   ['treepath'],
diff --git a/testsuite/gtk/translate.c b/testsuite/gtk/translate.c
new file mode 100644
index 0000000000..b12cfc6e83
--- /dev/null
+++ b/testsuite/gtk/translate.c
@@ -0,0 +1,397 @@
+
+#include <gtk/gtk.h>
+
+static const char *css =
+"button, box {"
+"  all: unset; "
+"}"
+".with-border {"
+"  border: 10px solid white;"
+"}"
+;
+
+static void
+same_widget (void)
+{
+  GtkWidget *a = gtk_button_new ();
+  int i;
+
+  for (i = -1000; i < 1000; i ++)
+    {
+      int rx, ry;
+
+      gtk_widget_translate_coordinates (a, a, i, i, &rx, &ry);
+
+      g_assert_cmpint (rx, ==, i);
+      g_assert_cmpint (ry, ==, i);
+    }
+}
+
+static void
+compute_bounds (void)
+{
+  const int WIDTH = 200;
+  const int HEIGHT = 100;
+  GtkWidget *a = gtk_button_new ();
+  graphene_matrix_t transform;
+  graphene_rect_t bounds;
+
+  graphene_matrix_init_scale (&transform, 2, 1, 1);
+
+  gtk_widget_measure (a, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_size_allocate (a, &(GtkAllocation){0, 0, WIDTH, HEIGHT}, -1);
+
+  gtk_widget_compute_bounds (a, a, &bounds);
+  g_assert_cmpfloat (bounds.origin.x, ==, 0);
+  g_assert_cmpfloat (bounds.origin.y, ==, 0);
+  g_assert_cmpfloat_with_epsilon (bounds.size.width, WIDTH, 1);
+  g_assert_cmpfloat_with_epsilon (bounds.size.height, HEIGHT, 1);
+
+  gtk_widget_set_transform (a, &transform);
+  gtk_widget_compute_bounds (a, a, &bounds);
+
+  g_assert_cmpfloat_with_epsilon (bounds.size.width, WIDTH, 1);
+  g_assert_cmpfloat_with_epsilon (bounds.size.height, HEIGHT, 1);
+}
+
+static void
+compute_bounds_with_parent (void)
+{
+  const int WIDTH = 200;
+  const int HEIGHT = 100;
+  GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  GtkWidget *a = gtk_button_new ();
+  graphene_matrix_t transform;
+  graphene_rect_t bounds;
+
+  gtk_widget_set_hexpand (a, FALSE);
+  gtk_widget_set_vexpand (a, FALSE);
+  gtk_widget_set_halign (a, GTK_ALIGN_START);
+  gtk_widget_set_valign (a, GTK_ALIGN_START);
+  gtk_widget_set_size_request (a, WIDTH, HEIGHT);
+  gtk_widget_set_margin_start (a, 25);
+
+
+  gtk_container_add (GTK_CONTAINER (box), a);
+  gtk_widget_measure (a, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_measure (box, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_size_allocate (box, &(GtkAllocation){0, 0, WIDTH * 10, HEIGHT * 10}, -1);
+
+  gtk_widget_compute_bounds (a, box, &bounds);
+  g_assert_cmpfloat_with_epsilon (bounds.origin.x, 25, 1);
+  g_assert_cmpfloat_with_epsilon (bounds.origin.y, 0, 1);
+  g_assert_cmpfloat_with_epsilon (bounds.size.width, WIDTH, 1);
+  g_assert_cmpfloat_with_epsilon (bounds.size.height, HEIGHT, 1);
+
+
+  /* Now set a transform and check that the bounds returned by compute_bounds
+   * have the proper values */
+
+  graphene_matrix_init_scale (&transform, 2, 1, 1);
+  gtk_widget_set_transform (a, &transform);
+
+
+  gtk_widget_compute_bounds (a, box, &bounds);
+  /* FIXME: Positions here are borked */
+  /*g_assert_cmpfloat_with_epsilon (bounds.origin.x, 25, 1);*/
+  /*g_assert_cmpfloat_with_epsilon (bounds.origin.y, 0, 1);*/
+  g_assert_cmpfloat_with_epsilon (bounds.size.width,  WIDTH * 2, 1);
+  g_assert_cmpfloat_with_epsilon (bounds.size.height, HEIGHT,    1);
+  /*g_message ("RESULT: %f, %f, %f, %f",*/
+             /*bounds.origin.x, bounds.origin.y,*/
+             /*bounds.size.width, bounds.size.height);*/
+}
+
+static void
+translate_with_parent (void)
+{
+  const int WIDTH = 200;
+  const int HEIGHT = 100;
+  const float x_scale = 2.0f;
+  const int x_margin = 25;
+  GtkWidget *parent = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  GtkWidget *child = gtk_button_new ();
+  graphene_matrix_t transform;
+  int i;
+
+  gtk_widget_set_hexpand (child, FALSE);
+  gtk_widget_set_vexpand (child, FALSE);
+  gtk_widget_set_halign (child, GTK_ALIGN_START);
+  gtk_widget_set_valign (child, GTK_ALIGN_START);
+  gtk_widget_set_size_request (child, WIDTH, HEIGHT);
+  gtk_widget_set_margin_start (child, x_margin);
+
+  gtk_container_add (GTK_CONTAINER (parent), child);
+  gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_measure (parent, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_size_allocate (parent, &(GtkAllocation){0, 0, WIDTH * 10, HEIGHT * 10}, -1);
+
+  /* First we have no transformation. We take a coordinate and translate it from parent
+   * to child, then back from child to parent and check if we get our original coordinate. */
+  for (i = 0; i < 100; i ++)
+    {
+      double cx, cy;
+      double px, py;
+
+      gtk_widget_translate_coordinatesf (parent, child, i, i, &cx, &cy);
+
+      /* Back up */
+      gtk_widget_translate_coordinatesf (child, parent, cx, cy, &px, &py);
+
+      g_assert_cmpfloat_with_epsilon (px, i, 0.1f);
+      g_assert_cmpfloat_with_epsilon (py, i, 0.1f);
+    }
+
+
+  graphene_matrix_init_scale (&transform, x_scale, 1, 1);
+  gtk_widget_set_transform (child, &transform);
+
+  /* Same thing... */
+  for (i = 1; i < 100; i ++)
+    {
+      double cx, cy;
+      double px, py;
+
+      gtk_widget_translate_coordinatesf (parent, child, i, i, &cx, &cy);
+      /*g_message ("### %d/%d in child coords: %f/%f", i, i, cx, cy);*/
+      g_assert_cmpfloat_with_epsilon (cx, (-x_margin+i) / x_scale, 0.1f);
+      g_assert_cmpfloat_with_epsilon (cy, i, 0.1f);
+
+      /* Back up */
+      gtk_widget_translate_coordinatesf (child, parent, cx, cy, &px, &py);
+      /*g_message ("%f, %f", px, py);*/
+      /*g_message ("%f/%f in parent coords: %f/%f", cx, cy, px, py);*/
+
+      g_assert_cmpfloat_with_epsilon (px, i, 0.1f);
+      g_assert_cmpfloat_with_epsilon (py, i, 0.1f);
+    }
+
+
+  /* Now try a translation... */
+  graphene_matrix_init_translate (&transform,
+                                  &(graphene_point3d_t){20, 0, 0});
+  gtk_widget_set_transform (child, &transform);
+  gtk_widget_set_margin_start (child, 0);
+  gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_measure (parent, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_size_allocate (parent, &(GtkAllocation){0, 0, WIDTH * 10, HEIGHT * 10}, -1);
+  {
+    double dx, dy;
+
+    gtk_widget_translate_coordinatesf (parent, child, 0, 0, &dx, &dy);
+
+    g_assert_cmpfloat_with_epsilon (dx, -20, 0.1);
+    g_assert_cmpfloat_with_epsilon (dy, 0, 0.1);
+  }
+
+
+}
+
+static void
+pick (void)
+{
+  const int WIDTH = 200;
+  const int HEIGHT = 100;
+  GtkWidget *parent = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  GtkWidget *child = gtk_button_new ();
+  graphene_matrix_t transform;
+
+  gtk_widget_set_hexpand (child, TRUE);
+  gtk_widget_set_vexpand (child, TRUE);
+  gtk_widget_set_halign (child, GTK_ALIGN_FILL);
+  gtk_widget_set_valign (child, GTK_ALIGN_FILL);
+
+  gtk_container_add (GTK_CONTAINER (parent), child);
+  gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_measure (parent, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_size_allocate (parent, &(GtkAllocation){0, 0, WIDTH, HEIGHT}, -1);
+
+  g_assert (gtk_widget_get_width  (child) == WIDTH);
+  g_assert (gtk_widget_get_height (child) == HEIGHT);
+
+  /* We scale the child widget to only half its size on the x axis,
+   * which means doing a pick on the left half of the parent should
+   * return the child but a pick on the right half should return the
+   * parent. */
+  graphene_matrix_init_scale (&transform, 0.5, 1, 1);
+  gtk_widget_set_transform (child, &transform);
+
+  /*g_assert (gtk_widget_pick (parent, WIDTH * 0.25, HEIGHT / 2) == child);*/
+  /*g_assert (gtk_widget_pick (parent, WIDTH * 0.75, HEIGHT / 2) == parent);*/
+
+  /* Now we test translations by simply offsetting the child widget by its own size,
+   * which will move it to the left and entirely out of the parent's allocation. */
+  graphene_matrix_init_translate (&transform,
+                                  &(graphene_point3d_t){ - WIDTH, 0, 0 });
+  gtk_widget_set_transform (child, &transform);
+
+  /* ... which means that picking on the parent with any positive x coordinate will
+   * yield the parent widget, while negative x coordinates (up until -WIDTH) will
+   * yield the child */
+  g_assert (gtk_widget_pick (parent, WIDTH * 0.1, 0) == parent);
+  g_assert (gtk_widget_pick (parent, WIDTH * 0.9, 0) == parent);
+
+  /*double dx, dy;*/
+  /*gtk_widget_translate_coordinatesf (parent, child, - WIDTH * 0.1, 0, &dx, &dy);*/
+  /*g_message ("translate: %f, %f", dx, dy);*/
+
+
+  g_assert (gtk_widget_pick (parent, -WIDTH * 0.1, 0) == child);
+  g_assert (gtk_widget_pick (parent, -WIDTH * 0.9, 0) == child);
+}
+
+
+#if 0
+static void
+compute_bounds_css (void)
+{
+}
+
+
+static void
+single_widget_scale (void)
+{
+  GtkWidget *p = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  GtkWidget *w = gtk_button_new ();
+  graphene_matrix_t transform;
+  GtkWidget *picked;
+  int x, y;
+
+  gtk_container_add (GTK_CONTAINER (p), w);
+
+  gtk_widget_set_hexpand (w, TRUE);
+  gtk_widget_set_vexpand (w, TRUE);
+
+  graphene_matrix_init_scale (&transform, 0.5f, 0.5f, 1);
+  gtk_widget_set_transform (w, &transform);
+
+  /* Just to shut up the GtkWidget warning... */
+  gtk_widget_measure (p, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_size_allocate (p, &(GtkAllocation) {0, 0, 100, 100}, -1);
+
+  gtk_widget_translate_coordinates (p, w, 0, 0, &x, &y);
+  g_assert_cmpint (x, ==, 0);
+  g_assert_cmpint (y, ==, 0);
+
+  gtk_widget_translate_coordinates (p, w, 10, 10, &x, &y);
+  g_assert_cmpint (x, ==, 10 / 2);
+  g_assert_cmpint (y, ==, 10 / 2);
+
+
+  gtk_widget_translate_coordinates (p, w, 100, 100, &x, &y);
+  g_assert_cmpint (x, ==, 100 / 2);
+  g_assert_cmpint (y, ==, 100 / 2);
+
+  picked = gtk_widget_pick (p, 0, 0);
+  g_assert (picked == w);
+
+  picked = gtk_widget_pick (p, 51, 51);
+  g_assert (picked == p);
+}
+
+static void
+single_widget_rotate (void)
+{
+  GtkWidget *p = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  GtkWidget *w = gtk_button_new ();
+  graphene_matrix_t transform;
+  GtkWidget *picked;
+  int x, y;
+
+  gtk_container_add (GTK_CONTAINER (p), w);
+
+  gtk_widget_set_hexpand (w, TRUE);
+  gtk_widget_set_vexpand (w, TRUE);
+
+  graphene_matrix_init_rotate (&transform,
+                               45.0, /* Deg */
+                               graphene_vec3_z_axis ());
+  gtk_widget_set_transform (w, &transform);
+
+  /* Just to shut up the GtkWidget warning... */
+  gtk_widget_measure (p, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_size_allocate (p, &(GtkAllocation) {0, 0, 100, 100}, -1);
+
+  gtk_widget_translate_coordinates (p, w, 0, 0, &x, &y);
+  g_assert_cmpint (x, ==, 0);
+  g_assert_cmpint (y, ==, 0);
+
+
+  picked = gtk_widget_pick (p, 0, 0);
+  g_assert (picked == w);
+
+  picked = gtk_widget_pick (p, 0, 100);
+  g_assert (picked == w);
+
+  /* Now it gets interesting... */
+
+  /* This should return the button parent since the button is rotated away from the
+   * y axis on top */
+  picked = gtk_widget_pick (p, 20, 0);
+  g_assert (picked == p);
+
+  picked = gtk_widget_pick (p, 50, 10);
+  g_assert (picked == p);
+
+  picked = gtk_widget_pick (p, 100, 100);
+  g_assert (picked == p);
+}
+
+
+static void
+single_widget_scale_css (void)
+{
+  GtkWidget *p = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  GtkWidget *w = gtk_button_new ();
+  graphene_matrix_t transform;
+  GtkWidget *picked;
+  int x, y;
+
+  gtk_style_context_add_class (gtk_widget_get_style_context (w), "with-border");
+
+  gtk_container_add (GTK_CONTAINER (p), w);
+
+  gtk_widget_set_hexpand (w, TRUE);
+  gtk_widget_set_vexpand (w, TRUE);
+
+  graphene_matrix_init_scale (&transform, 2, 2, 1);
+  gtk_widget_set_transform (w, &transform);
+
+  /* Just to shut up the GtkWidget warning... */
+  gtk_widget_measure (p, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL, NULL, NULL);
+  gtk_widget_size_allocate (p, &(GtkAllocation) {0, 0, 100, 100}, -1);
+
+  /* This is the interesting part. Scaling by a factor of 2 should also
+   * incrase the border size by that factor, and since the border is
+   * part of the input region... */
+  /*picked = gtk_widget_pick (p, 200, 20);*/
+  picked = gtk_widget_pick (p, 199, 20);
+  g_message ("%p", picked);
+  g_assert (picked == w);
+}
+#endif
+int
+main (int argc, char **argv)
+{
+  GtkCssProvider *provider;
+
+  gtk_init ();
+
+  // TODO: Do this only conditionally and/or per-testcase.
+  provider = gtk_css_provider_new ();
+  gtk_css_provider_load_from_data (provider, css, -1);
+  gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+                                              GTK_STYLE_PROVIDER (provider),
+                                              GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/translate/same-widget", same_widget);
+  g_test_add_func ("/translate/compute-bounds", compute_bounds);
+  g_test_add_func ("/translate/compute-bounds-with-parent", compute_bounds_with_parent);
+  g_test_add_func ("/translate/translate-with-parent", translate_with_parent);
+  g_test_add_func ("/translate/pick", pick);
+
+  return g_test_run ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]