summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2023-05-14 23:14:03 -0400
committerMatthias Clasen <mclasen@redhat.com>2023-05-14 23:14:03 -0400
commitf2e45bbc87311f2de8c055f4d11c67fa47bfccdd (patch)
tree2a64e1579fc77816197d70e5fcc7ba3c9653adc3
parent9965cfbc3bfed2eed3680b89bd5e6d90cd2df35e (diff)
downloadgtk+-rounded-rect-intersections.tar.gz
Quick visualization of rounded rectsrounded-rect-intersections
-rw-r--r--tests/meson.build7
-rw-r--r--tests/testroundedrect.c312
2 files changed, 319 insertions, 0 deletions
diff --git a/tests/meson.build b/tests/meson.build
index c2d08c26de..3807ddc615 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -146,6 +146,13 @@ foreach t: gtk_tests
)
endforeach
+executable('testroundedrect',
+ sources: [ 'testroundedrect.c' ],
+ include_directories: [confinc, gdkinc],
+ c_args: test_args + common_cflags,
+ dependencies: [libgtk_static_dep, libm],
+)
+
if libsysprof_dep.found()
executable('testperf',
sources: 'testperf.c',
diff --git a/tests/testroundedrect.c b/tests/testroundedrect.c
new file mode 100644
index 0000000000..035bc40cd8
--- /dev/null
+++ b/tests/testroundedrect.c
@@ -0,0 +1,312 @@
+#include <gtk/gtk.h>
+#include <gtk/css/gtkcssparserprivate.h>
+#include <gsk/gskroundedrectprivate.h>
+
+#define TEST_TYPE_WIDGET (test_widget_get_type ())
+G_DECLARE_FINAL_TYPE (TestWidget, test_widget, TEST, WIDGET, GtkWidget)
+
+struct _TestWidget
+{
+ GtkWidget parent_instance;
+
+ GskRoundedRect rect1;
+ GskRoundedRect rect2;
+ GskRoundedRect rect3;
+ GskRoundedRectIntersection result;
+};
+
+struct _TestWidgetClass
+{
+ GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE (TestWidget, test_widget, GTK_TYPE_WIDGET)
+
+static void
+test_widget_init (TestWidget *self)
+{
+}
+
+static void
+test_widget_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ TestWidget *self = TEST_WIDGET (widget);
+
+ if (orientation == GTK_ORIENTATION_VERTICAL)
+ *minimum = *natural = MAX (self->rect1.bounds.origin.x + self->rect1.bounds.size.width,
+ self->rect2.bounds.origin.x + self->rect2.bounds.size.width);
+ else
+ *minimum = *natural = MAX (self->rect1.bounds.origin.y + self->rect1.bounds.size.height,
+ self->rect2.bounds.origin.y + self->rect2.bounds.size.height);
+}
+
+static void
+test_widget_snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
+{
+ TestWidget *self = TEST_WIDGET (widget);
+ float widths[4] = { 1, 1, 1, 1 };
+ GdkRGBA colors1[4];
+ GdkRGBA colors2[4];
+ GdkRGBA colors3[4];
+ GskRoundedRect rect3;
+
+ gdk_rgba_parse (&colors1[0], "red");
+ colors1[1] = colors1[2] = colors1[3] = colors1[0];
+
+ gdk_rgba_parse (&colors2[0], "blue");
+ colors2[1] = colors2[2] = colors2[3] = colors2[0];
+
+ gdk_rgba_parse (&colors3[0], "magenta");
+ colors3[1] = colors3[2] = colors3[3] = colors3[0];
+
+ gtk_snapshot_append_border (snapshot, &self->rect1, widths, colors1);
+ gtk_snapshot_append_border (snapshot, &self->rect2, widths, colors2);
+
+ switch (gsk_rounded_rect_intersect (&self->rect1, &self->rect2, &rect3))
+ {
+ case GSK_INTERSECTION_NONEMPTY:
+ gtk_snapshot_append_border (snapshot, &rect3, widths, colors3);
+ break;
+ default:
+ ;
+ }
+}
+
+
+static void
+test_widget_class_init (TestWidgetClass *class)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+ widget_class->snapshot = test_widget_snapshot;
+ widget_class->measure = test_widget_measure;
+}
+
+static GtkWidget *
+test_widget_new (void)
+{
+ return g_object_new (TEST_TYPE_WIDGET, NULL);
+}
+
+static void
+update_intersection (TestWidget *self)
+{
+ self->result = gsk_rounded_rect_intersect (&self->rect1, &self->rect2, &self->rect3);
+}
+
+static void
+test_widget_set_rect1 (TestWidget *self,
+ GskRoundedRect *rect)
+{
+ self->rect1 = *rect;
+ update_intersection (self);
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+static void
+test_widget_set_rect2 (TestWidget *self,
+ GskRoundedRect *rect)
+{
+ self->rect2 = *rect;
+ update_intersection (self);
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+static gboolean
+parse_rect (GtkCssParser *parser,
+ graphene_rect_t *out_rect)
+{
+ double numbers[4];
+
+ if (!gtk_css_parser_consume_number (parser, &numbers[0]) ||
+ !gtk_css_parser_consume_number (parser, &numbers[1]) ||
+ !gtk_css_parser_consume_number (parser, &numbers[2]) ||
+ !gtk_css_parser_consume_number (parser, &numbers[3]))
+ return FALSE;
+
+ graphene_rect_init (out_rect, numbers[0], numbers[1], numbers[2], numbers[3]);
+
+ return TRUE;
+}
+
+static gboolean
+parse_rounded_rect (GtkCssParser *parser,
+ GskRoundedRect *out_rect)
+{
+ graphene_rect_t r;
+ graphene_size_t corners[4];
+ double d;
+ guint i;
+
+ if (!parse_rect (parser, &r))
+ return FALSE;
+
+ if (!gtk_css_parser_try_delim (parser, '/'))
+ {
+ gsk_rounded_rect_init_from_rect (out_rect, &r, 0);
+ return TRUE;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!gtk_css_parser_has_number (parser))
+ break;
+ if (!gtk_css_parser_consume_number (parser, &d))
+ return FALSE;
+ corners[i].width = d;
+ }
+
+ if (i == 0)
+ {
+ gtk_css_parser_error_syntax (parser, "Expected a number");
+ return FALSE;
+ }
+
+ /* The magic (i - 1) >> 1 below makes it take the correct value
+ * according to spec. Feel free to check the 4 cases
+ */
+ for (; i < 4; i++)
+ corners[i].width = corners[(i - 1) >> 1].width;
+ if (gtk_css_parser_try_delim (parser, '/'))
+ {
+ gtk_css_parser_consume_token (parser);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!gtk_css_parser_has_number (parser))
+ break;
+ if (!gtk_css_parser_consume_number (parser, &d))
+ return FALSE;
+ corners[i].height = d;
+ }
+
+ if (i == 0)
+ {
+ gtk_css_parser_error_syntax (parser, "Expected a number");
+ return FALSE;
+ }
+
+ for (; i < 4; i++)
+ corners[i].height = corners[(i - 1) >> 1].height;
+ }
+ else
+ {
+ for (i = 0; i < 4; i++)
+ corners[i].height = corners[i].width;
+ }
+
+ gsk_rounded_rect_init (out_rect, &r, &corners[0], &corners[1], &corners[2], &corners[3]);
+
+ return TRUE;
+}
+
+static GtkWidget *label;
+
+static void
+update_label (GtkLabel *label,
+ GskRoundedRectIntersection result)
+{
+ const char *labels[] = {
+ "Empty", "Not empty", "Not representable", "Who knows"
+ };
+
+ gtk_label_set_label (label, labels[result]);
+}
+
+static void
+activate1_cb (GtkEntry *entry, TestWidget *test)
+{
+ GtkCssParser *parser;
+ const char *text;
+ GBytes *bytes;
+ GskRoundedRect rect;
+
+ text = gtk_editable_get_text (GTK_EDITABLE (entry));
+ bytes = g_bytes_new_static (text, strlen (text) + 1);
+ parser = gtk_css_parser_new_for_bytes (bytes, NULL, NULL, NULL, NULL);
+
+ if (parse_rounded_rect (parser, &rect))
+ {
+ test_widget_set_rect1 (test, &rect);
+ update_label (GTK_LABEL (label), test->result);
+ }
+
+ gtk_css_parser_unref (parser);
+ g_bytes_unref (bytes);
+}
+
+static void
+activate2_cb (GtkEntry *entry, TestWidget *test)
+{
+ GtkCssParser *parser;
+ const char *text;
+ GBytes *bytes;
+ GskRoundedRect rect;
+
+ text = gtk_editable_get_text (GTK_EDITABLE (entry));
+ bytes = g_bytes_new_static (text, strlen (text) + 1);
+ parser = gtk_css_parser_new_for_bytes (bytes, NULL, NULL, NULL, NULL);
+
+ if (parse_rounded_rect (parser, &rect))
+ {
+ test_widget_set_rect2 (test, &rect);
+ update_label (GTK_LABEL (label), test->result);
+ }
+
+ gtk_css_parser_unref (parser);
+ g_bytes_unref (bytes);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *box;
+ GtkWidget *grid;
+ GtkWidget *entry1;
+ GtkWidget *entry2;
+ GtkWidget *test;
+
+ gtk_init ();
+
+ window = gtk_window_new ();
+ gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_window_set_child (GTK_WINDOW (window), box);
+
+ grid = gtk_grid_new ();
+ gtk_box_append (GTK_BOX (box), grid);
+
+ test = test_widget_new ();
+ gtk_widget_set_hexpand (test, TRUE);
+ gtk_widget_set_vexpand (test, TRUE);
+ gtk_widget_set_halign (test, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign (test, GTK_ALIGN_CENTER);
+ gtk_box_append (GTK_BOX (box), test);
+
+ entry1 = gtk_entry_new ();
+ g_signal_connect (entry1, "activate", G_CALLBACK (activate1_cb), test);
+ gtk_grid_attach (GTK_GRID (grid), entry1, 0, 0, 1, 1);
+
+ entry2 = gtk_entry_new ();
+ g_signal_connect (entry2, "activate", G_CALLBACK (activate2_cb), test);
+ gtk_grid_attach (GTK_GRID (grid), entry2, 0, 1, 1, 1);
+
+ label = gtk_label_new ("");
+ gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
+
+ gtk_window_present (GTK_WINDOW (window));
+
+ while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
+ g_main_context_iteration (NULL, FALSE);
+
+ return 0;
+}