2020-11-02 16:05:57 +00:00
|
|
|
/* Paintable/Simple Paintable
|
2018-02-27 01:28:55 +00:00
|
|
|
*
|
|
|
|
* GdkPaintable is an interface used by GTK for drawings of any sort
|
|
|
|
* that do not require layouting or positioning.
|
|
|
|
*
|
|
|
|
* This demo code gives a simple example on how a paintable can
|
|
|
|
* be created.
|
|
|
|
*
|
|
|
|
* Paintables can be used in many places inside GTK widgets, but the
|
|
|
|
* most common usage is inside GtkImage and that's what we're going
|
|
|
|
* to do here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2018-02-27 02:09:33 +00:00
|
|
|
#include "paintable.h"
|
|
|
|
|
2018-02-27 01:28:55 +00:00
|
|
|
static GtkWidget *window = NULL;
|
|
|
|
|
|
|
|
/* First, add the boilerplate for the object itself.
|
|
|
|
* This part would normally go in the header.
|
|
|
|
*/
|
|
|
|
#define GTK_TYPE_NUCLEAR_ICON (gtk_nuclear_icon_get_type ())
|
|
|
|
G_DECLARE_FINAL_TYPE (GtkNuclearIcon, gtk_nuclear_icon, GTK, NUCLEAR_ICON, GObject)
|
|
|
|
|
2018-02-27 02:09:33 +00:00
|
|
|
/* Declare the struct. */
|
2018-02-27 01:28:55 +00:00
|
|
|
struct _GtkNuclearIcon
|
|
|
|
{
|
|
|
|
GObject parent_instance;
|
2018-02-27 02:09:33 +00:00
|
|
|
|
|
|
|
/* 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;
|
2018-02-27 01:28:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _GtkNuclearIconClass
|
|
|
|
{
|
|
|
|
GObjectClass parent_class;
|
|
|
|
};
|
|
|
|
|
2018-02-27 02:09:33 +00:00
|
|
|
/* 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
|
2021-08-27 21:44:42 +00:00
|
|
|
gtk_nuclear_snapshot (GtkSnapshot *snapshot,
|
|
|
|
const GdkRGBA *foreground,
|
|
|
|
const GdkRGBA *background,
|
|
|
|
double width,
|
|
|
|
double height,
|
|
|
|
double rotation)
|
2018-02-27 01:28:55 +00:00
|
|
|
{
|
|
|
|
#define RADIUS 0.3
|
2024-01-08 06:38:06 +00:00
|
|
|
GskPathBuilder *builder;
|
|
|
|
GskPath *path;
|
|
|
|
GskStroke *stroke;
|
2018-02-27 01:28:55 +00:00
|
|
|
double size;
|
|
|
|
|
2021-08-27 21:44:42 +00:00
|
|
|
gtk_snapshot_append_color (snapshot,
|
|
|
|
background,
|
|
|
|
&GRAPHENE_RECT_INIT (0, 0, width, height));
|
2018-02-27 01:28:55 +00:00
|
|
|
|
|
|
|
size = MIN (width, height);
|
2024-01-08 06:38:06 +00:00
|
|
|
|
|
|
|
gtk_snapshot_save (snapshot);
|
|
|
|
|
|
|
|
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width / 2.0, height / 2.0));
|
|
|
|
gtk_snapshot_scale (snapshot, size, size);
|
|
|
|
gtk_snapshot_rotate (snapshot, rotation);
|
|
|
|
|
|
|
|
builder = gsk_path_builder_new ();
|
|
|
|
gsk_path_builder_add_circle (builder, graphene_point_zero (), 0.1);
|
|
|
|
path = gsk_path_builder_free_to_path (builder);
|
|
|
|
gtk_snapshot_append_fill (snapshot, path, GSK_FILL_RULE_WINDING, foreground);
|
|
|
|
gsk_path_unref (path);
|
|
|
|
|
|
|
|
stroke = gsk_stroke_new (RADIUS);
|
|
|
|
gsk_stroke_set_dash (stroke, (float[1]) { RADIUS * G_PI / 3 }, 1);
|
|
|
|
builder = gsk_path_builder_new ();
|
|
|
|
gsk_path_builder_add_circle (builder, graphene_point_zero(), RADIUS);
|
|
|
|
path = gsk_path_builder_free_to_path (builder);
|
|
|
|
gtk_snapshot_append_stroke (snapshot, path, stroke, foreground);
|
|
|
|
gsk_path_unref (path);
|
|
|
|
gsk_stroke_free (stroke);
|
|
|
|
|
|
|
|
gtk_snapshot_restore (snapshot);
|
2018-02-27 01:28:55 +00:00
|
|
|
}
|
|
|
|
|
2018-02-27 02:09:33 +00:00
|
|
|
/* 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,
|
2021-08-27 21:44:42 +00:00
|
|
|
&(GdkRGBA) { 0, 0, 0, 1 }, /* black */
|
|
|
|
&(GdkRGBA) { 0.9, 0.75, 0.15, 1.0 }, /* yellow */
|
2018-02-27 02:09:33 +00:00
|
|
|
width, height,
|
2021-08-27 21:44:42 +00:00
|
|
|
nuclear->rotation);
|
2018-02-27 02:09:33 +00:00
|
|
|
}
|
|
|
|
|
2018-02-27 01:28:55 +00:00
|
|
|
static GdkPaintableFlags
|
|
|
|
gtk_nuclear_icon_get_flags (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
/* The flags are very useful to let GTK know that this image
|
|
|
|
* is never going to change.
|
|
|
|
* This allows many optimizations and should therefore always
|
|
|
|
* be set.
|
|
|
|
*/
|
|
|
|
return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_nuclear_icon_paintable_init (GdkPaintableInterface *iface)
|
|
|
|
{
|
|
|
|
iface->snapshot = gtk_nuclear_icon_snapshot;
|
|
|
|
iface->get_flags = gtk_nuclear_icon_get_flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* When defining the GType, we need to implement the GdkPaintable interface */
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GtkNuclearIcon, gtk_nuclear_icon, G_TYPE_OBJECT,
|
|
|
|
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
|
|
|
gtk_nuclear_icon_paintable_init))
|
|
|
|
|
|
|
|
/* Here's the boilerplate for the GObject declaration.
|
|
|
|
* We don't need to do anything special here, because we keep no
|
|
|
|
* data of our own.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
gtk_nuclear_icon_class_init (GtkNuclearIconClass *klass)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gtk_nuclear_icon_init (GtkNuclearIcon *nuclear)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-02-27 02:09:33 +00:00
|
|
|
/* And finally, we add a simple constructor.
|
|
|
|
* It is declared in the header so that the other examples
|
|
|
|
* can use it.
|
|
|
|
*/
|
2018-02-27 01:28:55 +00:00
|
|
|
GdkPaintable *
|
2018-02-27 02:09:33 +00:00
|
|
|
gtk_nuclear_icon_new (double rotation)
|
2018-02-27 01:28:55 +00:00
|
|
|
{
|
2018-02-27 02:09:33 +00:00
|
|
|
GtkNuclearIcon *nuclear;
|
|
|
|
|
|
|
|
nuclear = g_object_new (GTK_TYPE_NUCLEAR_ICON, NULL);
|
|
|
|
nuclear->rotation = rotation;
|
|
|
|
|
|
|
|
return GDK_PAINTABLE (nuclear);
|
2018-02-27 01:28:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GtkWidget *
|
|
|
|
do_paintable (GtkWidget *do_widget)
|
|
|
|
{
|
|
|
|
GdkPaintable *nuclear;
|
|
|
|
GtkWidget *image;
|
|
|
|
|
|
|
|
if (!window)
|
|
|
|
{
|
2020-02-14 19:55:36 +00:00
|
|
|
window = gtk_window_new ();
|
2018-02-27 01:28:55 +00:00
|
|
|
gtk_window_set_display (GTK_WINDOW (window),
|
|
|
|
gtk_widget_get_display (do_widget));
|
|
|
|
gtk_window_set_title (GTK_WINDOW (window), "Nuclear Icon");
|
|
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
|
2020-09-12 01:05:09 +00:00
|
|
|
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
2018-02-27 01:28:55 +00:00
|
|
|
|
2018-02-27 02:09:33 +00:00
|
|
|
nuclear = gtk_nuclear_icon_new (0.0);
|
2018-02-27 01:28:55 +00:00
|
|
|
image = gtk_image_new_from_paintable (nuclear);
|
2020-05-02 21:26:54 +00:00
|
|
|
gtk_window_set_child (GTK_WINDOW (window), image);
|
2018-02-27 01:28:55 +00:00
|
|
|
g_object_unref (nuclear);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gtk_widget_get_visible (window))
|
2022-11-28 04:03:14 +00:00
|
|
|
gtk_widget_set_visible (window, TRUE);
|
2018-02-27 01:28:55 +00:00
|
|
|
else
|
2020-05-09 14:26:22 +00:00
|
|
|
gtk_window_destroy (GTK_WINDOW (window));
|
2018-02-27 01:28:55 +00:00
|
|
|
|
|
|
|
return window;
|
|
|
|
}
|