gtk/tests/testwidgettransforms.c
Benjamin Otte a079fd2def widget: Fix transform refcounting in allocate()
Make the transform (transfer full).

1. This makes sure we actually reference the transform. Previously we
   did not.
2. Most callers create a new transform to pass to us. Now they don't
   have to uref it anymore.
2019-05-29 16:34:56 +02:00

343 lines
11 KiB
C

#include <gtk/gtk.h>
static const char *css =
"test>button {"
" all: unset; "
" background-color: white;"
" border: 30px solid teal;"
" margin: 40px;"
" padding: 40px;"
"}"
"test>button:hover {"
" background-color: blue;"
"}"
"test image {"
" background-color: purple;"
"}"
;
/* Just so we can avoid a signal */
GtkWidget *transform_tester;
GtkWidget *test_widget;
GtkWidget *test_child;
float scale = 1;
gboolean do_picking = TRUE;
static const GdkRGBA RED = {1, 0, 0, 0.4};
static const GdkRGBA GREEN = {0, 1, 0, 0.7};
static const GdkRGBA BLUE = {0, 0, 1, 0.4};
static const GdkRGBA BLACK = {0, 0, 0, 1 };
/* ######################################################################### */
/* ############################## MatrixChooser ############################ */
/* ######################################################################### */
#define GTK_TYPE_MATRIX_CHOOSER (gtk_matrix_chooser_get_type ())
G_DECLARE_FINAL_TYPE (GtkMatrixChooser, gtk_matrix_chooser, GTK, MATRIX_CHOOSER, GtkWidget)
struct _GtkMatrixChooser
{
GtkWidget parent_instance;
};
G_DEFINE_TYPE (GtkMatrixChooser, gtk_matrix_chooser, GTK_TYPE_WIDGET)
static void
gtk_matrix_chooser_init (GtkMatrixChooser *self)
{
}
static void
gtk_matrix_chooser_class_init (GtkMatrixChooserClass *klass)
{
}
/* ######################################################################### */
/* ############################# TransformTester ########################### */
/* ######################################################################### */
#define TEST_WIDGET_MIN_SIZE 100
#define GTK_TYPE_TRANSFORM_TESTER (gtk_transform_tester_get_type ())
G_DECLARE_FINAL_TYPE (GtkTransformTester, gtk_transform_tester, GTK, TRANSFORM_TESTER, GtkWidget);
struct _GtkTransformTester
{
GtkWidget parent_instance;
GtkWidget *test_widget;
int pick_increase;
};
G_DEFINE_TYPE (GtkTransformTester, gtk_transform_tester, GTK_TYPE_WIDGET);
static void
gtk_transform_tester_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkTransformTester *self = (GtkTransformTester *)widget;
if (self->test_widget)
{
gtk_widget_measure (self->test_widget, orientation, for_size,
minimum, natural, NULL, NULL);
}
}
static void
gtk_transform_tester_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkTransformTester *self = (GtkTransformTester *)widget;
GskTransform *global_transform;
int w, h;
if (!self->test_widget)
return;
scale += 2.5f;
gtk_widget_measure (self->test_widget, GTK_ORIENTATION_HORIZONTAL, -1,
&w, NULL, NULL, NULL);
gtk_widget_measure (self->test_widget, GTK_ORIENTATION_VERTICAL, w,
&h, NULL, NULL, NULL);
g_message ("%s: %d, %d", __FUNCTION__, w, h);
global_transform = NULL;
global_transform = gsk_transform_translate (global_transform, &GRAPHENE_POINT_INIT (width / 2.0f, height / 2.0f));
global_transform = gsk_transform_rotate (global_transform, scale);
global_transform = gsk_transform_translate (global_transform, &GRAPHENE_POINT_INIT (-w / 2.0f, -h / 2.0f));
gtk_widget_allocate (self->test_widget,
w, h,
-1,
global_transform);
}
static void
gtk_transform_tester_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkTransformTester *self = (GtkTransformTester *)widget;
const int width = gtk_widget_get_width (widget);
const int height = gtk_widget_get_height (widget);
const int inc = self->pick_increase;
graphene_rect_t child_bounds;
graphene_rect_t self_bounds;
int x, y;
GTK_WIDGET_CLASS (gtk_transform_tester_parent_class)->snapshot (widget, snapshot);
if (!do_picking ||
!gtk_widget_compute_bounds (self->test_widget, widget, &child_bounds) ||
!gtk_widget_compute_bounds (self->test_widget, self->test_widget, &self_bounds))
return;
{
const struct {
graphene_point_t coords;
GdkRGBA color;
} points[4] = {
{ self_bounds.origin, {1, 0, 0, 1} },
{ GRAPHENE_POINT_INIT (self_bounds.origin.x + self_bounds.size.width, self_bounds.origin.y), {0, 1, 0, 1} },
{ GRAPHENE_POINT_INIT (self_bounds.origin.x + self_bounds.size.width, self_bounds.origin.y + self_bounds.size.height), {0, 0, 1, 1} },
{ GRAPHENE_POINT_INIT (self_bounds.origin.x, self_bounds.origin.y + self_bounds.size.height), {1, 0, 1, 1} }
};
for (x = 0; x < G_N_ELEMENTS (points); x ++)
{
int px, py;
gtk_widget_translate_coordinates (self->test_widget, widget,
points[x].coords.x, points[x].coords.y,
&px, &py);
gtk_snapshot_append_color (snapshot, &points[x].color,
&GRAPHENE_RECT_INIT (px, py,
4,
4));
}
}
/* Now add custom drawing */
for (x = 0; x < width; x += inc)
{
for (y = 0; y < height; y += inc)
{
const float px = x;
const float py = y;
GtkWidget *picked;
#if 1
picked = gtk_widget_pick (widget, px, py, GTK_PICK_DEFAULT);
#else
{
int dx, dy;
gtk_widget_translate_coordinates (widget, self->test_widget, px, py, &dx, &dy);
picked = gtk_widget_pick (self->test_widget, dx, dy, GTK_PICK_DEFAULT);
}
#endif
if (picked == self->test_widget)
gtk_snapshot_append_color (snapshot, &GREEN,
&GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
else if (picked == test_child)
gtk_snapshot_append_color (snapshot, &BLUE,
&GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
else
gtk_snapshot_append_color (snapshot, &RED,
&GRAPHENE_RECT_INIT (px - (inc / 2), py - (inc / 2), inc, inc));
}
}
gtk_snapshot_append_color (snapshot, &BLACK,
&GRAPHENE_RECT_INIT (child_bounds.origin.x,
child_bounds.origin.y,
child_bounds.size.width,
1));
gtk_snapshot_append_color (snapshot, &BLACK,
&GRAPHENE_RECT_INIT (child_bounds.origin.x + child_bounds.size.width,
child_bounds.origin.y,
1,
child_bounds.size.height));
gtk_snapshot_append_color (snapshot, &BLACK,
&GRAPHENE_RECT_INIT (child_bounds.origin.x,
child_bounds.origin.y + child_bounds.size.height,
child_bounds.size.width,
1));
gtk_snapshot_append_color (snapshot, &BLACK,
&GRAPHENE_RECT_INIT (child_bounds.origin.x,
child_bounds.origin.y,
1,
child_bounds.size.height));
}
static void
gtk_transform_tester_init (GtkTransformTester *self)
{
self->pick_increase = 4;
}
static void
gtk_transform_tester_class_init (GtkTransformTesterClass *klass)
{
GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
widget_class->measure = gtk_transform_tester_measure;
widget_class->size_allocate = gtk_transform_tester_size_allocate;
widget_class->snapshot = gtk_transform_tester_snapshot;
gtk_widget_class_set_css_name (widget_class, "test");
}
static gboolean
tick_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
gtk_widget_queue_allocate (widget);
return G_SOURCE_CONTINUE;
}
static void
gtk_transform_tester_set_test_widget (GtkTransformTester *self,
GtkWidget *test_widget)
{
g_assert (!self->test_widget);
self->test_widget = test_widget;
gtk_widget_set_parent (test_widget, (GtkWidget *)self);
gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, NULL, NULL);
}
static void
toggled_cb (GtkToggleButton *source,
gpointer user_data)
{
do_picking = gtk_toggle_button_get_active (source);
}
int
main (int argc, char **argv)
{
GtkWidget *window;
GtkWidget *matrix_chooser;
GtkWidget *box;
GtkWidget *titlebar;
GtkWidget *toggle_button;
GtkCssProvider *provider;
gtk_init ();
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);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
matrix_chooser = g_object_new (GTK_TYPE_MATRIX_CHOOSER, NULL);
transform_tester = g_object_new (GTK_TYPE_TRANSFORM_TESTER, NULL);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
titlebar = gtk_header_bar_new ();
gtk_window_set_titlebar (GTK_WINDOW (window), titlebar);
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (titlebar), TRUE);
toggle_button = gtk_toggle_button_new ();
gtk_button_set_label (GTK_BUTTON (toggle_button), "Picking");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_button), do_picking);
g_signal_connect (toggle_button, "toggled", G_CALLBACK (toggled_cb), NULL);
gtk_container_add (GTK_CONTAINER (titlebar), toggle_button);
test_widget = gtk_button_new ();
gtk_widget_set_size_request (test_widget, TEST_WIDGET_MIN_SIZE, TEST_WIDGET_MIN_SIZE);
gtk_widget_set_halign (test_widget, GTK_ALIGN_CENTER);
gtk_widget_set_valign (test_widget, GTK_ALIGN_CENTER);
test_child = gtk_image_new_from_icon_name ("weather-clear");
gtk_widget_set_halign (test_child, GTK_ALIGN_CENTER);
gtk_widget_set_valign (test_child, GTK_ALIGN_CENTER);
gtk_widget_set_size_request (test_child, TEST_WIDGET_MIN_SIZE / 2, TEST_WIDGET_MIN_SIZE / 2);
gtk_container_add (GTK_CONTAINER (test_widget), test_child);
gtk_transform_tester_set_test_widget (GTK_TRANSFORM_TESTER (transform_tester), test_widget);
gtk_widget_set_vexpand (transform_tester, TRUE);
gtk_container_add (GTK_CONTAINER (box), transform_tester);
gtk_container_add (GTK_CONTAINER (box), matrix_chooser);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_window_set_default_size ((GtkWindow *)window, 200, 200);
g_signal_connect (window, "close-request", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show (window);
gtk_main ();
return 0;
}