Add tweaks

Allow setting the puzzle size, and allow chosing between
the rose and the radioactive animation. Change the default
size to 3. 6 is just too hard.
This commit is contained in:
Matthias Clasen 2018-06-05 21:02:57 -04:00
parent 547d63d56a
commit a849ffbd79

View File

@ -9,13 +9,179 @@
/* Include the header for the puzzle piece */
#include "puzzlepiece.h"
#include "paintable.h"
#define ICON_TYPE_PAINTABLE (icon_paintable_get_type ())
G_DECLARE_FINAL_TYPE (IconPaintable, icon_paintable, ICON, PAINTABLE, GObject)
GdkPaintable * icon_paintable_new (GdkPaintable *paintable,
double height);
struct _IconPaintable
{
GObject parent_instance;
GdkPaintable *paintable;
double height;
double scale_factor;
};
struct _IconPaintableClass
{
GObjectClass parent_class;
};
static void
icon_paintable_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
IconPaintable *self = ICON_PAINTABLE (paintable);
if (self->scale_factor == 1.0)
{
gdk_paintable_snapshot (self->paintable, snapshot, width, height);
}
else
{
graphene_matrix_t scale_matrix;
graphene_matrix_init_scale (&scale_matrix, 1.0 / self->scale_factor, 1.0 / self->scale_factor, 1.0);
gtk_snapshot_push_transform (snapshot, &scale_matrix);
gdk_paintable_snapshot (self->paintable,
snapshot,
width * self->scale_factor,
height * self->scale_factor);
gtk_snapshot_pop (snapshot);
}
}
static GdkPaintable *
icon_paintable_paintable_get_current_image (GdkPaintable *paintable)
{
IconPaintable *self = ICON_PAINTABLE (paintable);
GdkPaintable *current_paintable, *current_self;
current_paintable = gdk_paintable_get_current_image (self->paintable);
current_self = icon_paintable_new (current_paintable, self->height);
g_object_unref (current_paintable);
return current_self;
}
static GdkPaintableFlags
icon_paintable_paintable_get_flags (GdkPaintable *paintable)
{
IconPaintable *self = ICON_PAINTABLE (paintable);
return gdk_paintable_get_flags (self->paintable);
}
static int
icon_paintable_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
IconPaintable *self = ICON_PAINTABLE (paintable);
return gdk_paintable_get_intrinsic_width (self->paintable) / self->scale_factor;
}
static int
icon_paintable_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
IconPaintable *self = ICON_PAINTABLE (paintable);
return gdk_paintable_get_intrinsic_height (self->paintable) / self->scale_factor;
}
static double icon_paintable_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
{
IconPaintable *self = ICON_PAINTABLE (paintable);
return gdk_paintable_get_intrinsic_aspect_ratio (self->paintable);
};
static void
icon_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = icon_paintable_paintable_snapshot;
iface->get_current_image = icon_paintable_paintable_get_current_image;
iface->get_flags = icon_paintable_paintable_get_flags;
iface->get_intrinsic_width = icon_paintable_paintable_get_intrinsic_width;
iface->get_intrinsic_height = icon_paintable_paintable_get_intrinsic_height;
iface->get_intrinsic_aspect_ratio = icon_paintable_paintable_get_intrinsic_aspect_ratio;
}
G_DEFINE_TYPE_EXTENDED (IconPaintable, icon_paintable, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
icon_paintable_paintable_init))
static void
icon_paintable_dispose (GObject *object)
{
IconPaintable *self = ICON_PAINTABLE (object);
if (self->paintable)
{
g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_contents, self);
g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_size, self);
g_clear_object (&self->paintable);
}
G_OBJECT_CLASS (icon_paintable_parent_class)->dispose (object);
}
static void
icon_paintable_class_init (IconPaintableClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = icon_paintable_dispose;
}
static void
icon_paintable_init (IconPaintable *self)
{
self->scale_factor = 1.0;
}
GdkPaintable *
icon_paintable_new (GdkPaintable *paintable,
double height)
{
IconPaintable *self;
g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), NULL);
g_return_val_if_fail (height > 0.0, NULL);
self = g_object_new (ICON_TYPE_PAINTABLE, NULL);
self->paintable = g_object_ref (paintable);
g_signal_connect_swapped (paintable, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
g_signal_connect_swapped (paintable, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
self->height = height;
if (gdk_paintable_get_intrinsic_height (paintable) == 0)
self->scale_factor = 1.0;
else
self->scale_factor = gdk_paintable_get_intrinsic_height (paintable) / height;
return GDK_PAINTABLE (self);
}
static GtkWidget *window = NULL;
static GtkWidget *frame = NULL;
static GtkWidget *size_spin = NULL;
static GtkWidget *rose_button = NULL;
static GdkPaintable *puzzle = NULL;
static GdkPaintable *rose = NULL;
static GdkPaintable *atom = NULL;
static gboolean solved = TRUE;
static guint width = 6;
static guint height = 6;
static guint width = 3;
static guint height = 3;
static guint pos_x;
static guint pos_y;
@ -280,24 +446,98 @@ reshuffle (void)
GtkWidget *grid;
grid = gtk_bin_get_child (GTK_BIN (frame));
shuffle_puzzle (grid);
if (solved)
start_puzzle (puzzle);
else
shuffle_puzzle (grid);
gtk_widget_grab_focus (grid);
}
static void
reconfigure (void)
{
GtkWidget *popover;
GtkWidget *grid;
width = height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (size_spin));
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rose_button)))
puzzle = rose;
else
puzzle= atom;
start_puzzle (puzzle);
popover = gtk_widget_get_ancestor (size_spin, GTK_TYPE_POPOVER);
gtk_popover_popdown (GTK_POPOVER (popover));
grid = gtk_bin_get_child (GTK_BIN (frame));
gtk_widget_grab_focus (grid);
}
GtkWidget *
do_sliding_puzzle (GtkWidget *do_widget)
{
GdkPaintable *puzzle;
if (!window)
{
GtkWidget *header;
GtkWidget *restart;
GtkWidget *tweak;
GtkWidget *popover;
GtkWidget *tweaks;
GtkWidget *apply;
GtkWidget *image;
GtkWidget *button;
GtkWidget *label;
rose = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
atom = gtk_nuclear_animation_new ();
puzzle = rose;
tweaks = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (tweaks), 10);
gtk_grid_set_column_spacing (GTK_GRID (tweaks), 10);
g_object_set (tweaks, "margin", 10, NULL);
rose_button = button = gtk_radio_button_new (NULL);
image = gtk_image_new_from_paintable (icon_paintable_new (rose, 40));
gtk_image_set_can_shrink (GTK_IMAGE (image), TRUE);
gtk_widget_set_size_request (image, 40, 40);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
gtk_grid_attach (GTK_GRID (tweaks), button, 0, 0, 1, 1);
button = gtk_radio_button_new_from_widget (button);
image = gtk_image_new_from_paintable (icon_paintable_new (atom, 40));
gtk_image_set_can_shrink (GTK_IMAGE (image), TRUE);
gtk_widget_set_size_request (image, 40, 40);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
gtk_grid_attach (GTK_GRID (tweaks), button, 1, 0, 1, 1);
label = gtk_label_new ("Size");
gtk_label_set_xalign (label, 0.0);
gtk_grid_attach (GTK_GRID (tweaks), label, 0, 1, 1, 1);
size_spin = gtk_spin_button_new_with_range (2, 10, 1);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (size_spin), width);
gtk_grid_attach (GTK_GRID (tweaks), size_spin, 1, 1, 1, 1);
apply = gtk_button_new_with_label ("Apply");
gtk_widget_set_halign (apply, GTK_ALIGN_END);
gtk_grid_attach (GTK_GRID (tweaks), apply, 1, 2, 1, 1);
g_signal_connect (apply, "clicked", G_CALLBACK (reconfigure), NULL);
popover = gtk_popover_new (NULL);
gtk_popover_set_modal (GTK_POPOVER (popover), TRUE);
gtk_container_add (GTK_CONTAINER (popover), tweaks);
restart = gtk_button_new_from_icon_name ("view-refresh-symbolic");
g_signal_connect (restart, "clicked", G_CALLBACK (reshuffle), NULL);
tweak = gtk_menu_button_new ();
gtk_menu_button_set_popover (GTK_MENU_BUTTON (tweak), popover);
gtk_button_set_icon_name (tweak, "emblem-system-symbolic");
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), tweak);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
@ -307,15 +547,10 @@ do_sliding_puzzle (GtkWidget *do_widget)
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
puzzle = GDK_PAINTABLE (gdk_texture_new_from_resource ("/sliding_puzzle/portland-rose.jpg"));
frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, (float) gdk_paintable_get_intrinsic_aspect_ratio (puzzle), FALSE);
gtk_container_add (GTK_CONTAINER (window), frame);
/* Start a puzzle with a default image */
start_puzzle (puzzle);
g_object_unref (puzzle);
}
if (!gtk_widget_get_visible (window))