summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimm Bäder <mail@baedert.org>2018-08-11 22:15:29 +0200
committerTimm Bäder <mail@baedert.org>2019-02-14 06:57:23 +0100
commit43ac1e7ca12587b29c63ef1cfedc20842c8194c2 (patch)
tree6922151df46b17ed1753c470a2da6f82539a6f7a
parentedd8183a2cfe691dc185032de19ad49992ded741 (diff)
downloadgtk+-43ac1e7ca12587b29c63ef1cfedc20842c8194c2.tar.gz
Add picking/translation/compute_bounds unit tests
-rw-r--r--testsuite/gtk/meson.build1
-rw-r--r--testsuite/gtk/translate.c397
2 files changed, 398 insertions, 0 deletions
diff --git a/testsuite/gtk/meson.build b/testsuite/gtk/meson.build
index c02e4ab177..8c661cbbb8 100644
--- a/testsuite/gtk/meson.build
+++ b/testsuite/gtk/meson.build
@@ -53,6 +53,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 ();
+}