forked from AuroraMiddleware/gtk
gtk-demo: Add another demo
Show how to add a context menu to a custom widget, and how to make a GtkPicture lookalike.
This commit is contained in:
parent
2741431d6e
commit
d71337513f
@ -181,6 +181,11 @@
|
||||
<file>fontify.h</file>
|
||||
<file>main.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/menu">
|
||||
<file>demo3widget.c</file>
|
||||
<file>demo3widget.h</file>
|
||||
<file>demo3widget.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/shortcuts">
|
||||
<file>shortcuts.ui</file>
|
||||
<file>shortcuts-builder.ui</file>
|
||||
@ -265,6 +270,7 @@
|
||||
<file>list_store.c</file>
|
||||
<file>main.c</file>
|
||||
<file>markup.c</file>
|
||||
<file>menu.c</file>
|
||||
<file>overlay.c</file>
|
||||
<file>overlay2.c</file>
|
||||
<file>paint.c</file>
|
||||
|
243
demos/gtk-demo/demo3widget.c
Normal file
243
demos/gtk-demo/demo3widget.c
Normal file
@ -0,0 +1,243 @@
|
||||
#include <math.h>
|
||||
#include "demo3widget.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_PAINTABLE = 1,
|
||||
PROP_SCALE
|
||||
};
|
||||
|
||||
struct _Demo3Widget
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GdkPaintable *paintable;
|
||||
float scale;
|
||||
|
||||
GtkWidget *menu;
|
||||
};
|
||||
|
||||
struct _Demo3WidgetClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (Demo3Widget, demo3_widget, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
demo3_widget_init (Demo3Widget *self)
|
||||
{
|
||||
self->scale = 1.f;
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
demo3_widget_dispose (GObject *object)
|
||||
{
|
||||
Demo3Widget *self = DEMO3_WIDGET (object);
|
||||
|
||||
g_clear_object (&self->paintable);
|
||||
g_clear_pointer (&self->menu, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (demo3_widget_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
demo3_widget_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
Demo3Widget *self = DEMO3_WIDGET (widget);
|
||||
int x, y, width, height;
|
||||
double w, h;
|
||||
|
||||
width = gtk_widget_get_width (widget);
|
||||
height = gtk_widget_get_height (widget);
|
||||
|
||||
w = self->scale * gdk_paintable_get_intrinsic_width (self->paintable);
|
||||
h = self->scale * gdk_paintable_get_intrinsic_height (self->paintable);
|
||||
|
||||
x = MAX (0, (width - ceil (w)) / 2);
|
||||
y = MAX (0, (height - ceil (h)) / 2);
|
||||
|
||||
gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
|
||||
gdk_paintable_snapshot (self->paintable, snapshot, w, h);
|
||||
gtk_snapshot_restore (snapshot);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
demo3_widget_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
Demo3Widget *self = DEMO3_WIDGET (widget);
|
||||
int size;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
size = gdk_paintable_get_intrinsic_width (self->paintable);
|
||||
else
|
||||
size = gdk_paintable_get_intrinsic_height (self->paintable);
|
||||
|
||||
*minimum = *natural = self->scale * size;
|
||||
}
|
||||
|
||||
static void
|
||||
demo3_widget_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
Demo3Widget *self = DEMO3_WIDGET (widget);
|
||||
|
||||
/* Since we are not using a layout manager (who would do this
|
||||
* for us), we need to allocate a size for our menu by calling
|
||||
* gtk_native_check_resize().
|
||||
*/
|
||||
gtk_native_check_resize (GTK_NATIVE (self->menu));
|
||||
}
|
||||
|
||||
static void
|
||||
demo3_widget_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Demo3Widget *self = DEMO3_WIDGET (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PAINTABLE:
|
||||
g_clear_object (&self->paintable);
|
||||
self->paintable = g_value_dup_object (value);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (object));
|
||||
break;
|
||||
|
||||
case PROP_SCALE:
|
||||
self->scale = g_value_get_float (value);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (object));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
demo3_widget_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
Demo3Widget *self = DEMO3_WIDGET (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PAINTABLE:
|
||||
g_value_set_object (value, self->paintable);
|
||||
break;
|
||||
|
||||
case PROP_SCALE:
|
||||
g_value_set_float (value, self->scale);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pressed_cb (GtkGestureClick *gesture,
|
||||
guint n_press,
|
||||
double x,
|
||||
double y,
|
||||
Demo3Widget *self)
|
||||
{
|
||||
/* We are placing our menu at the point where
|
||||
* the click happened, before popping it up.
|
||||
*/
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (self->menu),
|
||||
&(const GdkRectangle){ x, y, 1, 1 });
|
||||
gtk_popover_popup (GTK_POPOVER (self->menu));
|
||||
}
|
||||
|
||||
static void
|
||||
zoom_cb (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
Demo3Widget *self = DEMO3_WIDGET (widget);
|
||||
float scale;
|
||||
|
||||
if (g_str_equal (action_name, "zoom.in"))
|
||||
scale = MIN (10, self->scale * M_SQRT2);
|
||||
else if (g_str_equal (action_name, "zoom.out"))
|
||||
scale = MAX (0.01, self->scale / M_SQRT2);
|
||||
else
|
||||
scale = 1.0;
|
||||
|
||||
gtk_widget_action_set_enabled (widget, "zoom.in", scale < 10);
|
||||
gtk_widget_action_set_enabled (widget, "zoom.out", scale > 0.01);
|
||||
gtk_widget_action_set_enabled (widget, "zoom.reset", scale != 1);
|
||||
|
||||
g_object_set (widget, "scale", scale, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
demo3_widget_class_init (Demo3WidgetClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = demo3_widget_dispose;
|
||||
object_class->set_property = demo3_widget_set_property;
|
||||
object_class->get_property = demo3_widget_get_property;
|
||||
|
||||
widget_class->snapshot = demo3_widget_snapshot;
|
||||
widget_class->measure = demo3_widget_measure;
|
||||
widget_class->size_allocate = demo3_widget_size_allocate;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PAINTABLE,
|
||||
g_param_spec_object ("paintable", "Paintable", "Paintable",
|
||||
GDK_TYPE_PAINTABLE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SCALE,
|
||||
g_param_spec_float ("scale", "Scale", "Scale",
|
||||
0.0, 10.0, 1.0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/* These are the actions that we are using in the menu */
|
||||
gtk_widget_class_install_action (widget_class, "zoom.in", NULL, zoom_cb);
|
||||
gtk_widget_class_install_action (widget_class, "zoom.out", NULL, zoom_cb);
|
||||
gtk_widget_class_install_action (widget_class, "zoom.reset", NULL, zoom_cb);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/menu/demo3widget.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, Demo3Widget, menu);
|
||||
gtk_widget_class_bind_template_callback (widget_class, pressed_cb);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
demo3_widget_new (const char *resource)
|
||||
{
|
||||
Demo3Widget *self;
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_resource (resource, NULL);
|
||||
paintable = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf));
|
||||
|
||||
self = g_object_new (DEMO3_TYPE_WIDGET, "paintable", paintable, NULL);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
g_object_unref (paintable);
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
8
demos/gtk-demo/demo3widget.h
Normal file
8
demos/gtk-demo/demo3widget.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define DEMO3_TYPE_WIDGET (demo3_widget_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (Demo3Widget, demo3_widget, DEMO3, WIDGET, GtkWidget)
|
||||
|
||||
GtkWidget * demo3_widget_new (const char *resource);
|
30
demos/gtk-demo/demo3widget.ui
Normal file
30
demos/gtk-demo/demo3widget.ui
Normal file
@ -0,0 +1,30 @@
|
||||
<interface>
|
||||
<menu id="model">
|
||||
<item>
|
||||
<attribute name="label">Zoom Out</attribute>
|
||||
<attribute name="action">zoom.out</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Zoom In</attribute>
|
||||
<attribute name="action">zoom.in</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">1∶1</attribute>
|
||||
<attribute name="action">zoom.reset</attribute>
|
||||
</item>
|
||||
</menu>
|
||||
<template class="Demo3Widget">
|
||||
<child>
|
||||
<object class="GtkPopoverMenu" id="menu">
|
||||
<property name="has-arrow">0</property>
|
||||
<property name="menu-model">model</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGestureClick">
|
||||
<property name="button">3</property>
|
||||
<signal name="pressed" handler="pressed_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
47
demos/gtk-demo/menu.c
Normal file
47
demos/gtk-demo/menu.c
Normal file
@ -0,0 +1,47 @@
|
||||
/* Menu
|
||||
* #Keywords: action, zoom
|
||||
*
|
||||
* Demonstrates how to add a context menu to a custom widget
|
||||
* and connect it with widget actions.
|
||||
*
|
||||
* The custom widget we create here is similar to a GtkPicture,
|
||||
* but allows setting a zoom level for the displayed paintable.
|
||||
*
|
||||
* Our context menu has items to change the zoom level.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "demo3widget.h"
|
||||
|
||||
|
||||
GtkWidget *
|
||||
do_menu (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *sw;
|
||||
GtkWidget *widget;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Menu");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
|
||||
widget = demo3_widget_new ("/transparent/portland-rose.jpg");
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), widget);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
@ -44,6 +44,7 @@ demos = files([
|
||||
'links.c',
|
||||
'listbox.c',
|
||||
'listbox2.c',
|
||||
'menu.c',
|
||||
'flowbox.c',
|
||||
'list_store.c',
|
||||
'listview_applauncher.c',
|
||||
@ -112,7 +113,8 @@ extra_demo_sources = files(['main.c',
|
||||
'demo2layout.c',
|
||||
'singular_value_decomposition.c',
|
||||
'four_point_transform.c',
|
||||
'demo2widget.c'])
|
||||
'demo2widget.c',
|
||||
'demo3widget.c'])
|
||||
|
||||
if harfbuzz_dep.found() and pangoft_dep.found()
|
||||
demos += files('font_features.c')
|
||||
|
Loading…
Reference in New Issue
Block a user