From 540cffee89fffe606cc2eea226d5d5c911b6e817 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 11 Aug 2020 16:26:04 -0400 Subject: [PATCH 1/5] gtk-demo: Drop the pixbufs demo It is from a different era, and doesn't show the apis we want to promote. The visuals live on, in the Css/Animated Backgrounds demo. --- demos/gtk-demo/demo.gresource.xml | 12 -- demos/gtk-demo/meson.build | 1 - demos/gtk-demo/pixbufs.c | 228 ------------------------------ 3 files changed, 241 deletions(-) delete mode 100644 demos/gtk-demo/pixbufs.c diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index b2712d8dba..bee2c4042b 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -165,17 +165,6 @@ floppybuddy.gif gtk-logo.webm - - apple-red.png - background.jpg - gnome-applets.png - gnome-calendar.png - gnome-foot.png - gnome-gmush.png - gnome-gimp.png - gnome-gsame.png - gnu-keys.png - application_demo.c assistant.c @@ -241,7 +230,6 @@ password_entry.c peg_solitaire.c pickers.c - pixbufs.c printing.c revealer.c rotated_text.c diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build index 9e0eaf2e9b..86f0b431b1 100644 --- a/demos/gtk-demo/meson.build +++ b/demos/gtk-demo/meson.build @@ -62,7 +62,6 @@ demos = files([ 'password_entry.c', 'peg_solitaire.c', 'pickers.c', - 'pixbufs.c', 'printing.c', 'revealer.c', 'rotated_text.c', diff --git a/demos/gtk-demo/pixbufs.c b/demos/gtk-demo/pixbufs.c deleted file mode 100644 index c2de1bb343..0000000000 --- a/demos/gtk-demo/pixbufs.c +++ /dev/null @@ -1,228 +0,0 @@ -/* Pixbufs - * - * A GdkPixbuf represents an image, normally in RGB or RGBA format. - * Pixbufs are normally used to load files from disk and perform - * image scaling. - * - * This demo is not all that educational, but looks cool. It was written - * by Extreme Pixbuf Hacker Federico Mena Quintero. It also shows - * off how to use GtkDrawingArea to do a simple animation. - * - * Look at the Image demo for additional pixbuf usage examples. - * - */ - -#include -#include -#include - -#define BACKGROUND_NAME "/pixbufs/background.jpg" - -static const char *image_names[] = { - "/pixbufs/apple-red.png", - "/pixbufs/gnome-applets.png", - "/pixbufs/gnome-calendar.png", - "/pixbufs/gnome-foot.png", - "/pixbufs/gnome-gmush.png", - "/pixbufs/gnome-gimp.png", - "/pixbufs/gnome-gsame.png", - "/pixbufs/gnu-keys.png" -}; - -#define N_IMAGES G_N_ELEMENTS (image_names) - -/* demo window */ -static GtkWidget *window = NULL; - -/* Current frame */ -static GdkPixbuf *frame; - -/* Background image */ -static GdkPixbuf *background; -static int back_width, back_height; - -/* Images */ -static GdkPixbuf *images[N_IMAGES]; - -/* Widgets */ -static GtkWidget *da; - -/* Loads the images for the demo and returns whether the operation succeeded */ -static gboolean -load_pixbufs (GError **error) -{ - int i; - - if (background) - return TRUE; /* already loaded earlier */ - - background = gdk_pixbuf_new_from_resource (BACKGROUND_NAME, error); - if (!background) - return FALSE; /* Note that "error" was filled with a GError */ - - back_width = gdk_pixbuf_get_width (background); - back_height = gdk_pixbuf_get_height (background); - - for (i = 0; i < N_IMAGES; i++) - { - images[i] = gdk_pixbuf_new_from_resource (image_names[i], error); - - if (!images[i]) - return FALSE; /* Note that "error" was filled with a GError */ - } - - return TRUE; -} - -/* Expose callback for the drawing area */ -static void -draw_func (GtkDrawingArea *area, - cairo_t *cr, - int width, - int height, - gpointer data) -{ - gdk_cairo_set_source_pixbuf (cr, frame, 0, 0); - cairo_paint (cr); -} - -#define CYCLE_TIME 3000000 /* 3 seconds */ - -static gint64 start_time; - -/* Handler to regenerate the frame */ -static gboolean -on_tick (GtkWidget *widget, - GdkFrameClock *frame_clock, - gpointer data) -{ - gint64 current_time; - double f; - int i; - double xmid, ymid; - double radius; - - gdk_pixbuf_copy_area (background, 0, 0, back_width, back_height, - frame, 0, 0); - - if (start_time == 0) - start_time = gdk_frame_clock_get_frame_time (frame_clock); - - current_time = gdk_frame_clock_get_frame_time (frame_clock); - f = ((current_time - start_time) % CYCLE_TIME) / (double)CYCLE_TIME; - - xmid = back_width / 2.0; - ymid = back_height / 2.0; - - radius = MIN (xmid, ymid) / 2.0; - - for (i = 0; i < N_IMAGES; i++) - { - double ang; - int xpos, ypos; - int iw, ih; - double r; - GdkRectangle r1, r2, dest; - double k; - - ang = 2.0 * G_PI * (double) i / N_IMAGES - f * 2.0 * G_PI; - - iw = gdk_pixbuf_get_width (images[i]); - ih = gdk_pixbuf_get_height (images[i]); - - r = radius + (radius / 3.0) * sin (f * 2.0 * G_PI); - - xpos = floor (xmid + r * cos (ang) - iw / 2.0 + 0.5); - ypos = floor (ymid + r * sin (ang) - ih / 2.0 + 0.5); - - k = (i & 1) ? sin (f * 2.0 * G_PI) : cos (f * 2.0 * G_PI); - k = 2.0 * k * k; - k = MAX (0.25, k); - - r1.x = xpos; - r1.y = ypos; - r1.width = iw * k; - r1.height = ih * k; - - r2.x = 0; - r2.y = 0; - r2.width = back_width; - r2.height = back_height; - - if (gdk_rectangle_intersect (&r1, &r2, &dest)) - gdk_pixbuf_composite (images[i], - frame, - dest.x, dest.y, - dest.width, dest.height, - xpos, ypos, - k, k, - GDK_INTERP_NEAREST, - ((i & 1) - ? MAX (127, fabs (255 * sin (f * 2.0 * G_PI))) - : MAX (127, fabs (255 * cos (f * 2.0 * G_PI))))); - } - - gtk_widget_queue_draw (da); - - return G_SOURCE_CONTINUE; -} - -GtkWidget * -do_pixbufs (GtkWidget *do_widget) -{ - if (!window) - { - GError *error; - - window = gtk_window_new (); - gtk_window_set_display (GTK_WINDOW (window), - gtk_widget_get_display (do_widget)); - gtk_window_set_title (GTK_WINDOW (window), "Pixbufs"); - gtk_window_set_resizable (GTK_WINDOW (window), FALSE); - g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window); - - error = NULL; - if (!load_pixbufs (&error)) - { - GtkWidget *dialog; - - dialog = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - "Failed to load an image: %s", - error->message); - - g_error_free (error); - - g_signal_connect (dialog, "response", - G_CALLBACK (gtk_window_destroy), NULL); - - gtk_widget_show (dialog); - } - else - { - frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, back_width, back_height); - - da = gtk_drawing_area_new (); - - gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), back_width); - gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), back_height); - gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL); - - gtk_window_set_child (GTK_WINDOW (window), da); - - gtk_widget_add_tick_callback (da, on_tick, NULL, NULL); - } - } - - if (!gtk_widget_get_visible (window)) - gtk_widget_show (window); - else - { - gtk_window_destroy (GTK_WINDOW (window)); - g_object_unref (frame); - } - - return window; -} From 9b0a5b1fde07e68b7097d39f71708b284e80ea57 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 10 Aug 2020 21:31:49 -0400 Subject: [PATCH 2/5] Add sizes to toplevelsize warnings Might as well be informative while we're annoying. --- gdk/gdktoplevelsize.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gdk/gdktoplevelsize.c b/gdk/gdktoplevelsize.c index 276e63f951..187939ba55 100644 --- a/gdk/gdktoplevelsize.c +++ b/gdk/gdktoplevelsize.c @@ -123,13 +123,19 @@ gdk_toplevel_size_validate (GdkToplevelSize *size) { if (size->min_width > size->bounds_width || size->min_height > size->bounds_height) - g_warning ("GdkToplevelSize: min_size exceeds bounds"); + g_warning ("GdkToplevelSize: min_size (%d, %d) exceeds bounds (%d, %d)", + size->min_width, size->min_height, + size->bounds_width, size->bounds_height); if (size->width > size->bounds_width || size->height > size->bounds_height) - g_warning ("GdkToplevelSize: size exceeds bounds"); + g_warning ("GdkToplevelSize: size (%d, %d) exceeds bounds (%d, %d)", + size->width, size->height, + size->bounds_width, size->bounds_height); if (size->min_width > size->width || size->min_height > size->height) - g_warning ("GdkToplevelSize: min_size exceeds size"); + g_warning ("GdkToplevelSize: min_size (%d, %d) exceeds size (%d, %d)", + size->min_width, size->min_height, + size->width, size->height); } From 5e2aeee9b0eda40890874a5bf0c614da18c8f9f5 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 11 Aug 2020 21:14:05 -0400 Subject: [PATCH 3/5] gtk-demo: Add a layout manager demo This is more or less a copy of the layout manager example from clutter. --- demos/gtk-demo/demo.gresource.xml | 9 ++ demos/gtk-demo/demochild.c | 72 ++++++++++++ demos/gtk-demo/demochild.h | 8 ++ demos/gtk-demo/demolayout.c | 189 ++++++++++++++++++++++++++++++ demos/gtk-demo/demolayout.h | 13 ++ demos/gtk-demo/demowidget.c | 121 +++++++++++++++++++ demos/gtk-demo/demowidget.h | 11 ++ demos/gtk-demo/layoutmanager.c | 61 ++++++++++ demos/gtk-demo/meson.build | 6 +- 9 files changed, 489 insertions(+), 1 deletion(-) create mode 100644 demos/gtk-demo/demochild.c create mode 100644 demos/gtk-demo/demochild.h create mode 100644 demos/gtk-demo/demolayout.c create mode 100644 demos/gtk-demo/demolayout.h create mode 100644 demos/gtk-demo/demowidget.c create mode 100644 demos/gtk-demo/demowidget.h create mode 100644 demos/gtk-demo/layoutmanager.c diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index bee2c4042b..9f02e51b16 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -124,6 +124,14 @@ gnome-fs-directory.png gnome-fs-regular.png + + demolayout.h + demolayout.c + demowidget.h + demowidget.c + demochild.h + demochild.c + listview_filebrowser.ui listview_filebrowser.css @@ -206,6 +214,7 @@ iconview_edit.c images.c infobar.c + layoutmanager.c links.c listbox.c listbox2.c diff --git a/demos/gtk-demo/demochild.c b/demos/gtk-demo/demochild.c new file mode 100644 index 0000000000..147cf606f9 --- /dev/null +++ b/demos/gtk-demo/demochild.c @@ -0,0 +1,72 @@ +#include "demochild.h" + +/* This is a trivial child widget just for demo purposes. + * It draws a 32x32 square in fixed color. + */ + +struct _DemoChild +{ + GtkWidget parent_instance; + GdkRGBA color; +}; + +struct _DemoChildClass +{ + GtkWidgetClass parent_class; +}; + +G_DEFINE_TYPE (DemoChild, demo_child, GTK_TYPE_WIDGET) + +static void +demo_child_init (DemoChild *self) +{ +} + +static void +demo_child_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + DemoChild *self = DEMO_CHILD (widget); + int width, height; + + width = gtk_widget_get_width (widget); + height = gtk_widget_get_height (widget); + + gtk_snapshot_append_color (snapshot, &self->color, + &GRAPHENE_RECT_INIT(0, 0, width, height)); +} + +static void +demo_child_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + *minimum = *natural = 32; +} + +static void +demo_child_class_init (DemoChildClass *class) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + widget_class->snapshot = demo_child_snapshot; + widget_class->measure = demo_child_measure; +} + +GtkWidget * +demo_child_new (const char *color) +{ + DemoChild *self; + + self = g_object_new (DEMO_TYPE_CHILD, + "tooltip-text", color, + NULL); + + gdk_rgba_parse (&self->color, color); + + return GTK_WIDGET (self); +} diff --git a/demos/gtk-demo/demochild.h b/demos/gtk-demo/demochild.h new file mode 100644 index 0000000000..0a6c6e991c --- /dev/null +++ b/demos/gtk-demo/demochild.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +#define DEMO_TYPE_CHILD (demo_child_get_type ()) +G_DECLARE_FINAL_TYPE (DemoChild, demo_child, DEMO, CHILD, GtkWidget) + +GtkWidget * demo_child_new (const char *color); diff --git a/demos/gtk-demo/demolayout.c b/demos/gtk-demo/demolayout.c new file mode 100644 index 0000000000..fed244a3af --- /dev/null +++ b/demos/gtk-demo/demolayout.c @@ -0,0 +1,189 @@ +#include "demolayout.h" + +struct _DemoLayout +{ + GtkLayoutManager parent_instance; + + float position; + int pos[16]; +}; + +struct _DemoLayoutClass +{ + GtkLayoutManagerClass parent_class; +}; + +G_DEFINE_TYPE (DemoLayout, demo_layout, GTK_TYPE_LAYOUT_MANAGER) + +static void +demo_layout_measure (GtkLayoutManager *layout_manager, + GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkWidget *child; + int minimum_size = 0; + int natural_size = 0; + + for (child = gtk_widget_get_first_child (widget); + child != NULL; + child = gtk_widget_get_next_sibling (child)) + { + int child_min = 0, child_nat = 0; + + if (!gtk_widget_should_layout (child)) + continue; + + gtk_widget_measure (child, orientation, -1, + &child_min, &child_nat, + NULL, NULL); + minimum_size = MAX (minimum_size, child_min); + natural_size = MAX (natural_size, child_nat); + } + + /* A back-of-a-napkin calculation to reserve enough + * space for arranging 16 children in a circle. + */ + *minimum = 16 * minimum_size / G_PI + minimum_size; + *natural = 16 * natural_size / G_PI + natural_size; +} + +static void +demo_layout_allocate (GtkLayoutManager *layout_manager, + GtkWidget *widget, + int width, + int height, + int baseline) +{ + DemoLayout *self = DEMO_LAYOUT (layout_manager); + GtkWidget *child; + int i; + int child_width = 0; + int child_height = 0; + int x0, y0; + float r; + float t; + + t = self->position; + + for (child = gtk_widget_get_first_child (widget); + child != NULL; + child = gtk_widget_get_next_sibling (child)) + { + GtkRequisition child_req; + + if (!gtk_widget_should_layout (child)) + continue; + + gtk_widget_get_preferred_size (child, &child_req, NULL); + + child_width = MAX (child_width, child_req.width); + child_height = MAX (child_height, child_req.height); + } + + /* the center of our layout */ + x0 = (width / 2); + y0 = (height / 2); + + /* the radius for our circle of children */ + r = 8 * child_width / G_PI; + + for (child = gtk_widget_get_first_child (widget), i = 0; + child != NULL; + child = gtk_widget_get_next_sibling (child), i++) + { + GtkRequisition child_req; + float a = self->pos[i] * G_PI / 8; + int gx, gy; + int cx, cy; + int x, y; + + if (!gtk_widget_should_layout (child)) + continue; + + gtk_widget_get_preferred_size (child, &child_req, NULL); + + /* The grid position of child. */ + gx = x0 + (i % 4 - 2) * child_width; + gy = y0 + (i / 4 - 2) * child_height; + + /* The circle position of child. Note that we + * are adjusting the position by half the child size + * to place the center of child on a centered circle. + * This assumes that the children don't use align flags + * or uneven margins that would shift the center. + */ + cx = x0 + sin (a) * r - child_req.width / 2; + cy = y0 + cos (a) * r - child_req.height / 2; + + /* we interpolate between the two layouts according to + * the position value that has been set on the layout. + */ + x = t * cx + (1 - t) * gx; + y = t * cy + (1 - t) * gy; + + gtk_widget_size_allocate (child, + &(const GtkAllocation){ x, y, child_width, child_height}, + -1); + } +} + +static GtkSizeRequestMode +demo_layout_get_request_mode (GtkLayoutManager *layout_manager, + GtkWidget *widget) +{ + return GTK_SIZE_REQUEST_CONSTANT_SIZE; +} + +static void +demo_layout_class_init (DemoLayoutClass *klass) +{ + GtkLayoutManagerClass *layout_class = GTK_LAYOUT_MANAGER_CLASS (klass); + + layout_class->get_request_mode = demo_layout_get_request_mode; + layout_class->measure = demo_layout_measure; + layout_class->allocate = demo_layout_allocate; +} + +static void +demo_layout_init (DemoLayout *self) +{ + int i; + + for (i = 0; i < 16; i++) + self->pos[i] = i; +} + +GtkLayoutManager * +demo_layout_new (void) +{ + return g_object_new (DEMO_TYPE_LAYOUT, NULL); +} + +void +demo_layout_set_position (DemoLayout *layout, + float position) +{ + layout->position = position; +} + +/* Shuffle the circle positions of the children. + * Should be called when we are in the grid layout. + */ +void +demo_layout_shuffle (DemoLayout *layout) +{ + int i, j, tmp; + + for (i = 0; i < 16; i++) + { + j = g_random_int_range (0, i + 1); + tmp = layout->pos[i]; + layout->pos[i] = layout->pos[j]; + layout->pos[j] = tmp; + } +} diff --git a/demos/gtk-demo/demolayout.h b/demos/gtk-demo/demolayout.h new file mode 100644 index 0000000000..8672ba2f3c --- /dev/null +++ b/demos/gtk-demo/demolayout.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#define DEMO_TYPE_LAYOUT (demo_layout_get_type ()) + +G_DECLARE_FINAL_TYPE (DemoLayout, demo_layout, DEMO, LAYOUT, GtkLayoutManager) + +GtkLayoutManager * demo_layout_new (void); + +void demo_layout_set_position (DemoLayout *layout, + float position); +void demo_layout_shuffle (DemoLayout *layout); diff --git a/demos/gtk-demo/demowidget.c b/demos/gtk-demo/demowidget.c new file mode 100644 index 0000000000..16c5c28ad3 --- /dev/null +++ b/demos/gtk-demo/demowidget.c @@ -0,0 +1,121 @@ +#include "demowidget.h" +#include "demolayout.h" + +/* parent widget */ + +struct _DemoWidget +{ + GtkWidget parent_instance; + + gboolean backward; /* whether we go 0 -> 1 or 1 -> 0 */ + gint64 start_time; /* time the transition started */ + guint tick_id; /* our tick cb */ +}; + +struct _DemoWidgetClass +{ + GtkWidgetClass parent_class; +}; + +G_DEFINE_TYPE (DemoWidget, demo_widget, GTK_TYPE_WIDGET) + +/* The widget is controlling the transition by calling + * demo_layout_set_position() in a tick callback. + * + * We take half a second to go from one layout to the other. + */ + +#define DURATION (0.5 * G_TIME_SPAN_SECOND) + +static gboolean +transition (GtkWidget *widget, + GdkFrameClock *frame_clock, + gpointer data) +{ + DemoWidget *self = DEMO_WIDGET (widget); + DemoLayout *demo_layout = DEMO_LAYOUT (gtk_widget_get_layout_manager (widget)); + gint64 now = g_get_monotonic_time (); + + gtk_widget_queue_allocate (widget); + + if (self->backward) + demo_layout_set_position (demo_layout, 1.0 - (now - self->start_time) / DURATION); + else + demo_layout_set_position (demo_layout, (now - self->start_time) / DURATION); + + if (now - self->start_time >= DURATION) + { + self->backward = !self->backward; + demo_layout_set_position (demo_layout, self->backward ? 1.0 : 0.0); + /* keep things interesting by shuffling the positions */ + if (!self->backward) + demo_layout_shuffle (demo_layout); + self->tick_id = 0; + + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + +static void +clicked (GtkGestureClick *gesture, + guint n_press, + double x, + double y, + gpointer data) +{ + DemoWidget *self = data; + + if (self->tick_id != 0) + return; + + self->start_time = g_get_monotonic_time (); + self->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), transition, NULL, NULL); +} + +static void +demo_widget_init (DemoWidget *self) +{ + GtkGesture *gesture; + + gesture = gtk_gesture_click_new (); + g_signal_connect (gesture, "pressed", G_CALLBACK (clicked), self); + gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture)); +} + +static void +demo_widget_dispose (GObject *object) +{ + GtkWidget *child; + + while ((child = gtk_widget_get_first_child (GTK_WIDGET (object)))) + gtk_widget_unparent (child); + + G_OBJECT_CLASS (demo_widget_parent_class)->dispose (object); +} + +static void +demo_widget_class_init (DemoWidgetClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + object_class->dispose = demo_widget_dispose; + + /* here is where we use our custom layout manager */ + gtk_widget_class_set_layout_manager_type (widget_class, DEMO_TYPE_LAYOUT); +} + +GtkWidget * +demo_widget_new (void) +{ + return g_object_new (DEMO_TYPE_WIDGET, NULL); +} + +void +demo_widget_add_child (DemoWidget *self, + GtkWidget *child) +{ + gtk_widget_set_parent (child, GTK_WIDGET (self)); +} diff --git a/demos/gtk-demo/demowidget.h b/demos/gtk-demo/demowidget.h new file mode 100644 index 0000000000..cd8a5d4778 --- /dev/null +++ b/demos/gtk-demo/demowidget.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#define DEMO_TYPE_WIDGET (demo_widget_get_type ()) +G_DECLARE_FINAL_TYPE (DemoWidget, demo_widget, DEMO, WIDGET, GtkWidget) + +GtkWidget * demo_widget_new (void); + +void demo_widget_add_child (DemoWidget *self, + GtkWidget *child); diff --git a/demos/gtk-demo/layoutmanager.c b/demos/gtk-demo/layoutmanager.c new file mode 100644 index 0000000000..3a715d0fc8 --- /dev/null +++ b/demos/gtk-demo/layoutmanager.c @@ -0,0 +1,61 @@ +/* Layout Manager + * + * This examples shows a simple example of a custom layout manager + * and a widget using it. The layout manager places the children + * of the widget in a grid or a circle, or something in between. + * + * The widget is animating the transition between the two layouts. + * Click to start the transition. + */ + +#include + +#include "demowidget.h" +#include "demochild.h" + + +GtkWidget * +do_layoutmanager (GtkWidget *parent) +{ + static GtkWidget *window = NULL; + + if (!window) + { + GtkWidget *widget; + GtkWidget *child; + const char *color[] = { + "red", "orange", "yellow", "green", + "blue", "grey", "magenta", "lime", + "yellow", "firebrick", "aqua", "purple", + "tomato", "pink", "thistle", "maroon" + }; + int i; + + window = gtk_window_new (); + gtk_window_set_title (GTK_WINDOW (window), "Layout Manager"); + gtk_window_set_default_size (GTK_WINDOW (window), 600, 600); + g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window); + + widget = demo_widget_new (); + + for (i = 0; i < 16; i++) + { + child = demo_child_new (color[i]); + gtk_widget_set_margin_start (child, 4); + gtk_widget_set_margin_end (child, 4); + gtk_widget_set_margin_top (child, 4); + gtk_widget_set_margin_bottom (child, 4); + demo_widget_add_child (DEMO_WIDGET (widget), child); + } + + gtk_window_set_child (GTK_WINDOW (window), widget); + } + + if (!gtk_widget_get_visible (window)) + gtk_widget_show (window); + else + gtk_window_destroy (GTK_WINDOW (window)); + + return window; + +} diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build index 86f0b431b1..3cf3762d77 100644 --- a/demos/gtk-demo/meson.build +++ b/demos/gtk-demo/meson.build @@ -38,6 +38,7 @@ demos = files([ 'iconview_edit.c', 'images.c', 'infobar.c', + 'layoutmanager.c', 'links.c', 'listbox.c', 'listbox2.c', @@ -98,7 +99,10 @@ extra_demo_sources = files(['main.c', 'puzzlepiece.c', 'bluroverlay.c', 'demoimage.c', - 'demotaggedentry.c']) + 'demotaggedentry.c', + 'demochild.c', + 'demolayout.c', + 'demowidget.c']) if harfbuzz_dep.found() and pangoft_dep.found() demos += files('font_features.c') From 3340a5ee042095b25cf4529ea9af84fc173cf188 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 11 Aug 2020 23:03:31 -0400 Subject: [PATCH 4/5] gtk-demo: Visual improvement to solitaire Make the fields visible. --- demos/gtk-demo/peg_solitaire.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/demos/gtk-demo/peg_solitaire.c b/demos/gtk-demo/peg_solitaire.c index 379a336e47..1f5dfa30d8 100644 --- a/demos/gtk-demo/peg_solitaire.c +++ b/demos/gtk-demo/peg_solitaire.c @@ -334,6 +334,14 @@ create_board (GtkWidget *window) int x, y; GtkDragSource *source; GtkDropTarget *target; + GtkCssProvider *provider; + const char css[] = + ".solitaire-field {" + " border: 1px solid lightgray;" + "}"; + + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, css, -1); grid = gtk_grid_new (); gtk_widget_set_halign (grid, GTK_ALIGN_CENTER); @@ -352,6 +360,10 @@ create_board (GtkWidget *window) continue; image = gtk_image_new (); + gtk_style_context_add_provider (gtk_widget_get_style_context (image), + GTK_STYLE_PROVIDER (provider), + 800); + gtk_widget_add_css_class (image, "solitaire-field"); gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE); if (x != 3 || y != 3) { @@ -393,6 +405,8 @@ create_board (GtkWidget *window) gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (target)); } } + + g_object_unref (provider); } static void From 0a9acd10d23f7a2a30a342d57a2ad3a7f66fd416 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 11 Aug 2020 23:26:06 -0400 Subject: [PATCH 5/5] gtk-demo: Celebrate losses too Everybody is a winner! --- demos/gtk-demo/peg_solitaire.c | 58 ++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/demos/gtk-demo/peg_solitaire.c b/demos/gtk-demo/peg_solitaire.c index 1f5dfa30d8..43ed92f331 100644 --- a/demos/gtk-demo/peg_solitaire.c +++ b/demos/gtk-demo/peg_solitaire.c @@ -125,12 +125,15 @@ ended (GObject *object) } static void -celebrate (void) +celebrate (gboolean win) { char *path; GtkMediaStream *stream; - path = g_build_filename (GTK_DATADIR, "sounds", "freedesktop", "stereo", "complete.oga", NULL); + if (win) + path = g_build_filename (GTK_DATADIR, "sounds", "freedesktop", "stereo", "complete.oga", NULL); + else + path = g_build_filename (GTK_DATADIR, "sounds", "freedesktop", "stereo", "dialog-error.oga", NULL); stream = gtk_media_file_new_for_filename (path); gtk_media_stream_set_volume (stream, 1.0); gtk_media_stream_play (stream); @@ -139,14 +142,40 @@ celebrate (void) g_free (path); } +static int +check_move (GtkGrid *grid, + int x, + int y, + int dx, + int dy) +{ + GtkWidget *image; + /* We have a peg at x, y. + * Check if we can move the peg to x + 2*dx, y + 2*dy + */ + image = gtk_grid_get_child_at (grid, x + dx, y + dy); + if (!GTK_IS_IMAGE (image) || + !SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image)))) + return 0; + + image = gtk_grid_get_child_at (grid, x + 2*dx, y + 2*dy); + if (!GTK_IMAGE (image) || + SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image)))) + return 0; + + return 1; +} + static void -check_for_win (GtkGrid *grid) +check_for_end (GtkGrid *grid) { GtkWidget *image; int x, y; int pegs; + int moves; pegs = 0; + moves = 0; for (x = 0; x < 7; x++) { for (y = 0; y < 7; y++) @@ -154,16 +183,25 @@ check_for_win (GtkGrid *grid) image = gtk_grid_get_child_at (grid, x, y); if (GTK_IS_IMAGE (image) && SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image)))) - pegs++; + { + pegs++; + moves += check_move (grid, x, y, 1, 0); + moves += check_move (grid, x, y, -1, 0); + moves += check_move (grid, x, y, 0, 1); + moves += check_move (grid, x, y, 0, -1); + } + + if (pegs > 1 && moves > 0) + break; } } - if (pegs > 1) - return; - image = gtk_grid_get_child_at (grid, 3, 3); - if (SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image)))) - celebrate (); + if (pegs == 1 && + SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image)))) + celebrate (TRUE); + else if (moves == 0) + celebrate (FALSE); } @@ -320,7 +358,7 @@ drop_drop (GtkDropTarget *target, gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (peg)); /* Maybe we have something to celebrate */ - check_for_win (grid); + check_for_end (grid); /* Success! */ return TRUE;