mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 21:51:08 +00:00
demos: Add an animated paintable demo
This builds on the paintable demo.
This commit is contained in:
parent
357175f0b1
commit
3d9cb477aa
@ -183,6 +183,7 @@
|
||||
<file>overlay2.c</file>
|
||||
<file>pagesetup.c</file>
|
||||
<file>paintable.c</file>
|
||||
<file>paintable_animated.c</file>
|
||||
<file>panes.c</file>
|
||||
<file>pickers.c</file>
|
||||
<file>pixbufs.c</file>
|
||||
|
@ -46,6 +46,7 @@ demos = files([
|
||||
'overlay.c',
|
||||
'overlay2.c',
|
||||
'paintable.c',
|
||||
'paintable_animated.c',
|
||||
'panes.c',
|
||||
'pickers.c',
|
||||
'pixbufs.c',
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
/* First, add the boilerplate for the object itself.
|
||||
@ -21,14 +23,16 @@ static GtkWidget *window = NULL;
|
||||
#define GTK_TYPE_NUCLEAR_ICON (gtk_nuclear_icon_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkNuclearIcon, gtk_nuclear_icon, GTK, NUCLEAR_ICON, GObject)
|
||||
|
||||
GdkPaintable *gtk_nuclear_icon_new (void);
|
||||
|
||||
/* Declare the struct. We have no custom data, so it's very
|
||||
* bare.
|
||||
*/
|
||||
/* Declare the struct. */
|
||||
struct _GtkNuclearIcon
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
/* We store this rotation value here.
|
||||
* We are not doing with it here, but it will come in
|
||||
* very useful in the followup demos.
|
||||
*/
|
||||
double rotation;
|
||||
};
|
||||
|
||||
struct _GtkNuclearIconClass
|
||||
@ -36,21 +40,20 @@ struct _GtkNuclearIconClass
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* Here, we implement the functionality required by the GdkPaintable interface */
|
||||
static void
|
||||
gtk_nuclear_icon_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
/* This is the function that draws the actual icon.
|
||||
* We make it a custom function and define it in the paintable.h header
|
||||
* so that it can be called from all the other demos, too.
|
||||
*/
|
||||
void
|
||||
gtk_nuclear_snapshot (GtkSnapshot *snapshot,
|
||||
double width,
|
||||
double height,
|
||||
double rotation)
|
||||
{
|
||||
#define RADIUS 0.3
|
||||
cairo_t *cr;
|
||||
double size;
|
||||
|
||||
/* The snapshot function is the only function we need to implement.
|
||||
* It does the actual drawing of the paintable.
|
||||
*/
|
||||
|
||||
gtk_snapshot_append_color (snapshot,
|
||||
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 },
|
||||
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
||||
@ -64,6 +67,7 @@ gtk_nuclear_icon_snapshot (GdkPaintable *paintable,
|
||||
"Radioactive Icon");
|
||||
cairo_translate (cr, width / 2.0, height / 2.0);
|
||||
cairo_scale (cr, size, size);
|
||||
cairo_rotate (cr, rotation);
|
||||
|
||||
cairo_arc (cr, 0, 0, 0.1, - G_PI, G_PI);
|
||||
cairo_fill (cr);
|
||||
@ -76,6 +80,24 @@ gtk_nuclear_icon_snapshot (GdkPaintable *paintable,
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
/* Here, we implement the functionality required by the GdkPaintable interface */
|
||||
static void
|
||||
gtk_nuclear_icon_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkNuclearIcon *nuclear = GTK_NUCLEAR_ICON (paintable);
|
||||
|
||||
/* The snapshot function is the only function we need to implement.
|
||||
* It does the actual drawing of the paintable.
|
||||
*/
|
||||
|
||||
gtk_nuclear_snapshot (snapshot,
|
||||
width, height,
|
||||
nuclear->rotation);
|
||||
}
|
||||
|
||||
static GdkPaintableFlags
|
||||
gtk_nuclear_icon_get_flags (GdkPaintable *paintable)
|
||||
{
|
||||
@ -113,11 +135,19 @@ gtk_nuclear_icon_init (GtkNuclearIcon *nuclear)
|
||||
{
|
||||
}
|
||||
|
||||
/* And finally, we add the simple constructor we declared in the header. */
|
||||
/* And finally, we add a simple constructor.
|
||||
* It is declared in the header so that the other examples
|
||||
* can use it.
|
||||
*/
|
||||
GdkPaintable *
|
||||
gtk_nuclear_icon_new (void)
|
||||
gtk_nuclear_icon_new (double rotation)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_NUCLEAR_ICON, NULL);
|
||||
GtkNuclearIcon *nuclear;
|
||||
|
||||
nuclear = g_object_new (GTK_TYPE_NUCLEAR_ICON, NULL);
|
||||
nuclear->rotation = rotation;
|
||||
|
||||
return GDK_PAINTABLE (nuclear);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@ -134,7 +164,7 @@ do_paintable (GtkWidget *do_widget)
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Nuclear Icon");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
|
||||
|
||||
nuclear = gtk_nuclear_icon_new ();
|
||||
nuclear = gtk_nuclear_icon_new (0.0);
|
||||
image = gtk_image_new_from_paintable (nuclear);
|
||||
gtk_container_add (GTK_CONTAINER (window), image);
|
||||
g_object_unref (nuclear);
|
||||
|
14
demos/gtk-demo/paintable.h
Normal file
14
demos/gtk-demo/paintable.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __PAINTABLE_H__
|
||||
#define __PAINTABLE_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
void gtk_nuclear_snapshot (GtkSnapshot *snapshot,
|
||||
double width,
|
||||
double height,
|
||||
double rotation);
|
||||
|
||||
GdkPaintable * gtk_nuclear_icon_new (double rotation);
|
||||
GdkPaintable * gtk_nuclear_animation_new (void);
|
||||
|
||||
#endif /* __PAINTABLE_H__ */
|
209
demos/gtk-demo/paintable_animated.c
Normal file
209
demos/gtk-demo/paintable_animated.c
Normal file
@ -0,0 +1,209 @@
|
||||
/* Paintable/An animated paintable
|
||||
*
|
||||
* GdkPaintable also allows paintables to change.
|
||||
*
|
||||
* This demo code gives an example of how this could work. It builds
|
||||
* on the previous simple example.
|
||||
*
|
||||
* Paintables can also change their size, this works similarly, but
|
||||
* we will not demonstrate this here as our icon does not have any size.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "paintable.h"
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
/* First, add the boilerplate for the object itself.
|
||||
* This part would normally go in the header.
|
||||
*/
|
||||
#define GTK_TYPE_NUCLEAR_ANIMATION (gtk_nuclear_animation_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkNuclearAnimation, gtk_nuclear_animation, GTK, NUCLEAR_ANIMATION, GObject)
|
||||
|
||||
/* Do a full rotation in 5 seconds.
|
||||
* We will register the timeout for doing a single step to
|
||||
* be executed every 10ms, which means after 1000 steps
|
||||
* 10s will have elapsed.
|
||||
*/
|
||||
#define MAX_PROGRESS 500
|
||||
|
||||
/* Declare the struct. */
|
||||
struct _GtkNuclearAnimation
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
/* This variable stores the progress of our animation.
|
||||
* We just count upwards until we hit MAX_PROGRESS and
|
||||
* then start from scratch.
|
||||
*/
|
||||
int progress;
|
||||
|
||||
/* This variable holds the ID of the timer that updates
|
||||
* our progress variable.
|
||||
* We need to keep track of it so that we can remove it
|
||||
* again.
|
||||
*/
|
||||
guint source_id;
|
||||
};
|
||||
|
||||
struct _GtkNuclearAnimationClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* Again, we implement the functionality required by the GdkPaintable interface */
|
||||
static void
|
||||
gtk_nuclear_animation_snapshot (GdkPaintable *paintable,
|
||||
GdkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkNuclearAnimation *nuclear = GTK_NUCLEAR_ANIMATION (paintable);
|
||||
|
||||
/* We call the function from the previous example here. */
|
||||
gtk_nuclear_snapshot (snapshot,
|
||||
width, height,
|
||||
2 * G_PI * nuclear->progress / MAX_PROGRESS);
|
||||
}
|
||||
|
||||
static GdkPaintable *
|
||||
gtk_nuclear_animation_get_current_image (GdkPaintable *paintable)
|
||||
{
|
||||
GtkNuclearAnimation *nuclear = GTK_NUCLEAR_ANIMATION (paintable);
|
||||
|
||||
/* For non-static paintables, this function needs to be implemented.
|
||||
* It must return a static paintable with the same contents
|
||||
* as this one currently has.
|
||||
*
|
||||
* Luckily we added the rotation property to the nuclear icon
|
||||
* object previously, so we can just return an instance of that one.
|
||||
*/
|
||||
return gtk_nuclear_icon_new (2 * G_PI * nuclear->progress / MAX_PROGRESS);
|
||||
}
|
||||
|
||||
static GdkPaintableFlags
|
||||
gtk_nuclear_animation_get_flags (GdkPaintable *paintable)
|
||||
{
|
||||
/* This time, we cannot set the static contents flag because our animation
|
||||
* changes the contents.
|
||||
* However, our size still doesn't change, so report that flag.
|
||||
*/
|
||||
return GDK_PAINTABLE_STATIC_SIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_nuclear_animation_paintable_init (GdkPaintableInterface *iface)
|
||||
{
|
||||
iface->snapshot = gtk_nuclear_animation_snapshot;
|
||||
iface->get_current_image = gtk_nuclear_animation_get_current_image;
|
||||
iface->get_flags = gtk_nuclear_animation_get_flags;
|
||||
}
|
||||
|
||||
/* When defining the GType, we need to implement the GdkPaintable interface */
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkNuclearAnimation, gtk_nuclear_animation, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
||||
gtk_nuclear_animation_paintable_init))
|
||||
|
||||
/* This time, we need to implement the finalize function,
|
||||
*/
|
||||
static void
|
||||
gtk_nuclear_animation_finalize (GObject *object)
|
||||
{
|
||||
GtkNuclearAnimation *nuclear = GTK_NUCLEAR_ANIMATION (object);
|
||||
|
||||
/* Remove the timeout we registered when constructing
|
||||
* the object.
|
||||
*/
|
||||
g_source_remove (nuclear->source_id);
|
||||
|
||||
/* Don't forget to chain up to the parent class' implementation
|
||||
* of the finalize function.
|
||||
*/
|
||||
G_OBJECT_CLASS (gtk_nuclear_animation_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/* In the class declaration, we need to add our finalize function.
|
||||
*/
|
||||
static void
|
||||
gtk_nuclear_animation_class_init (GtkNuclearAnimationClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = gtk_nuclear_animation_finalize;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_nuclear_animation_step (gpointer data)
|
||||
{
|
||||
GtkNuclearAnimation *nuclear = data;
|
||||
|
||||
/* Add 1 to the progress and reset it when we've reached
|
||||
* the maximum value.
|
||||
* The animation will rotate by 360 degrees at MAX_PROGRESS
|
||||
* so it will be identical to the original unrotated one.
|
||||
*/
|
||||
nuclear->progress = (nuclear->progress + 1) % MAX_PROGRESS;
|
||||
|
||||
/* Now we need to tell all listeners that we've changed out contents
|
||||
* so that they can redraw this paintable.
|
||||
*/
|
||||
gdk_paintable_invalidate_contents (GDK_PAINTABLE (nuclear));
|
||||
|
||||
/* We want this timeout function to be called repeatedly,
|
||||
* so we return this value here.
|
||||
* If this was a single-shot timeout, we could also
|
||||
* return G_SOURCE_REMOVE here to get rid of it.
|
||||
*/
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_nuclear_animation_init (GtkNuclearAnimation *nuclear)
|
||||
{
|
||||
/* Add a timer here that constantly updates our animations.
|
||||
* We want to update it often enough to guarantee a smooth animation.
|
||||
*
|
||||
* Ideally, we'd attach to the frame clock, but because we do
|
||||
* not have it available here, we just use a regular timeout
|
||||
* that hopefully triggers often enough to be smooth.
|
||||
*/
|
||||
nuclear->source_id = g_timeout_add (10,
|
||||
gtk_nuclear_animation_step,
|
||||
nuclear);
|
||||
}
|
||||
|
||||
/* And finally, we add the simple constructor we declared in the header. */
|
||||
GdkPaintable *
|
||||
gtk_nuclear_animation_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_NUCLEAR_ANIMATION, NULL);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_paintable_animated (GtkWidget *do_widget)
|
||||
{
|
||||
GdkPaintable *nuclear;
|
||||
GtkWidget *image;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Nuclear Animation");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
|
||||
|
||||
nuclear = gtk_nuclear_animation_new ();
|
||||
image = gtk_image_new_from_paintable (nuclear);
|
||||
gtk_container_add (GTK_CONTAINER (window), image);
|
||||
g_object_unref (nuclear);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
Loading…
Reference in New Issue
Block a user