Files
gtk/demos/gtk-demo/gtkthrobber.c
Matthias Clasen e5e08cc0d7 wip: Add a drag surface resize demo
Make the one of the image sources in the clipboard
demo have a throbbing drag icon.
2023-03-07 07:21:32 -05:00

175 lines
4.5 KiB
C

/*
* Copyright © 2018 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "gtkthrobber.h"
#include "gtk.h"
struct _GtkThrobber
{
GObject parent_instance;
GdkFrameClock *clock;
GdkTexture *texture;
guint clock_tick_id;
float min, max, scale, delta;
float delta2, hot;
GdkDrag *drag;
};
struct _GtkThrobberClass
{
GObjectClass parent_class;
};
static void
gtk_throbber_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkThrobber *self = GTK_THROBBER (paintable);
gtk_snapshot_append_texture (snapshot, self->texture, &GRAPHENE_RECT_INIT (0, 0, width, height));
}
static int
gtk_throbber_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkThrobber *self = GTK_THROBBER (paintable);
return gdk_texture_get_width (self->texture) * self->scale;
}
static int
gtk_throbber_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkThrobber *self = GTK_THROBBER (paintable);
return gdk_texture_get_height (self->texture) * self->scale;
}
static void
gtk_throbber_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_throbber_paintable_snapshot;
iface->get_intrinsic_width = gtk_throbber_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_throbber_paintable_get_intrinsic_height;
}
G_DEFINE_TYPE_EXTENDED (GtkThrobber, gtk_throbber, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_throbber_paintable_init))
static void
gtk_throbber_dispose (GObject *object)
{
GtkThrobber *self = GTK_THROBBER (object);
gdk_frame_clock_end_updating (self->clock);
g_signal_handler_disconnect (self->clock, self->clock_tick_id);
self->clock_tick_id = 0;
g_clear_object (&self->clock);
g_clear_object (&self->texture);
g_clear_object (&self->drag);
G_OBJECT_CLASS (gtk_throbber_parent_class)->dispose (object);
}
static void
gtk_throbber_class_init (GtkThrobberClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = gtk_throbber_dispose;
}
static void
gtk_throbber_init (GtkThrobber *self)
{
}
static void
on_frame_clock_update (GdkFrameClock *clock,
GtkThrobber *self)
{
self->scale += self->delta;
if (self->scale >= self->max)
{
self->scale = self->max;
self->delta = - self->delta;
}
else if (self->scale <= self->min)
{
self->scale = self->min;
self->delta = - self->delta;
}
self->hot += self->delta2;
if (self->hot >= 1.)
{
self->hot = 1.;
self->delta2 = - self->delta2;
}
else if (self->hot <= 0.)
{
self->hot = 0.;
self->delta2 = - self->delta2;
}
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
gdk_drag_set_hotspot (self->drag,
gdk_texture_get_width (self->texture) * self->scale * self->hot,
gdk_texture_get_height (self->texture) * self->scale * self->hot);
}
GdkPaintable *
gtk_throbber_new (GdkFrameClock *clock,
const char *resource_path,
float min,
float max,
GdkDrag *drag)
{
GtkThrobber *self;
self = g_object_new (GTK_TYPE_THROBBER, NULL);
self->clock = g_object_ref (clock);
self->texture = gdk_texture_new_from_resource (resource_path);
self->drag = g_object_ref (drag);
self->min = min;
self->max = max;
self->scale = min;
self->delta = (max - min) / (15 * 16);
self->delta2 = 1. / (10 * 16);
self->hot = 0.;
self->clock_tick_id = g_signal_connect (self->clock, "update",
G_CALLBACK (on_frame_clock_update), self);
gdk_frame_clock_begin_updating (self->clock);
return GDK_PAINTABLE (self);
}