gtk-demo: Reorganize the dnd demo

Introduce a CanvasItem widget to make things a
bit less ad hoc.
This commit is contained in:
Matthias Clasen 2020-05-22 12:35:18 -04:00
parent dff5986ec2
commit 965483eb67

View File

@ -7,6 +7,186 @@
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (CanvasItem, canvas_item, CANVAS, ITEM, GtkWidget)
struct _CanvasItem {
GtkWidget parent;
GtkWidget *label;
double x, y;
double angle;
double delta;
};
struct _CanvasItemClass {
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (CanvasItem, canvas_item, GTK_TYPE_WIDGET)
static int n_items = 0;
static void
set_color (CanvasItem *item,
GdkRGBA *color)
{
char *css;
char *str;
GtkStyleContext *context;
GtkCssProvider *provider;
str = gdk_rgba_to_string (color);
css = g_strdup_printf ("* { background: %s; padding: 10px; }", str);
context = gtk_widget_get_style_context (item->label);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css, -1);
gtk_style_context_add_provider (gtk_widget_get_style_context (item->label), GTK_STYLE_PROVIDER (provider), 800);
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
g_free (str);
g_free (css);
}
static gboolean
item_drag_drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y)
{
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest)));
set_color (item, g_value_get_boxed (value));
return TRUE;
}
static void
apply_transform (CanvasItem *item)
{
GtkWidget *canvas = gtk_widget_get_parent (GTK_WIDGET (item));
GskTransform *transform;
transform = gsk_transform_rotate (gsk_transform_translate (NULL, &(graphene_point_t){item->x, item->y}),
item->angle + item->delta);
gtk_fixed_set_child_transform (GTK_FIXED (canvas), GTK_WIDGET (item), transform);
gsk_transform_unref (transform);
}
static void
angle_changed (GtkGestureRotate *gesture,
double angle,
double delta)
{
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
item->delta = angle / M_PI * 180.0;
apply_transform (item);
}
static void
rotate_done (GtkGesture *gesture)
{
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
item->angle = item->angle + item->delta;
item->delta = 0;
}
static void
click_done (GtkGesture *gesture)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
GtkWidget *canvas = gtk_widget_get_parent (item);
GtkWidget *last_child;
last_child = gtk_widget_get_last_child (canvas);
if (item != last_child)
gtk_widget_insert_after (item, canvas, last_child);
}
static void
canvas_item_init (CanvasItem *item)
{
char *text;
char *id;
GdkRGBA rgba;
GtkDropTarget *dest;
GtkGesture *gesture;
n_items++;
text = g_strdup_printf ("Item %d", n_items);
item->label = gtk_label_new (text);
g_free (text);
gtk_widget_set_parent (item->label, GTK_WIDGET (item));
gtk_widget_add_css_class (item->label, "frame");
id = g_strdup_printf ("item%d", n_items);
gtk_widget_set_name (item->label, id);
g_free (id);
gdk_rgba_parse (&rgba, "yellow");
set_color (item, &rgba);
item->x = 0;
item->y = 0;
item->angle = 0;
dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_rotate_new ();
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
}
static void
canvas_item_dispose (GObject *object)
{
CanvasItem *item = CANVAS_ITEM (object);
g_clear_pointer (&item->label, gtk_widget_unparent);
G_OBJECT_CLASS (canvas_item_parent_class)->dispose (object);
}
static void
canvas_item_class_init (CanvasItemClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = canvas_item_dispose;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
}
static GtkWidget *
canvas_item_new (double x,
double y)
{
CanvasItem *item = g_object_new (canvas_item_get_type (), NULL);
item->x = x;
item->y = y;
return GTK_WIDGET (item);
}
static GdkContentProvider *
prepare (GtkDragSource *source,
double x,
@ -18,7 +198,8 @@ prepare (GtkDragSource *source,
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = gtk_widget_pick (canvas, x, y, GTK_PICK_DEFAULT);
if (!GTK_IS_LABEL (item))
item = gtk_widget_get_ancestor (item, canvas_item_get_type ());
if (!item)
return NULL;
g_object_set_data (G_OBJECT (canvas), "dragged-item", item);
@ -66,47 +247,25 @@ drag_cancel (GtkDragSource *source,
return FALSE;
}
typedef struct {
double x, y;
double angle;
double delta;
} TransformData;
static void
apply_transform (GtkWidget *item)
{
GtkWidget *canvas = gtk_widget_get_parent (item);
TransformData *data;
GskTransform *transform;
data = g_object_get_data (G_OBJECT (item), "transform-data");
transform = gsk_transform_rotate (gsk_transform_translate (NULL, &(graphene_point_t){data->x, data->y}),
data->angle + data->delta);
gtk_fixed_set_child_transform (GTK_FIXED (canvas), item, transform);
gsk_transform_unref (transform);
}
static gboolean
drag_drop (GtkDropTarget *target,
const GValue *value,
double x,
double y)
{
GtkWidget *item;
TransformData *transform_data;
CanvasItem *item;
GtkWidget *canvas;
GtkWidget *last_child;
item = g_value_get_object (value);
transform_data = g_object_get_data (G_OBJECT (item), "transform-data");
transform_data->x = x;
transform_data->y = y;
item->x = x;
item->y = y;
canvas = gtk_widget_get_parent (item);
canvas = gtk_widget_get_parent (GTK_WIDGET (item));
last_child = gtk_widget_get_last_child (canvas);
if (item != last_child)
gtk_widget_insert_after (item, canvas, last_child);
if (GTK_WIDGET (item) != last_child)
gtk_widget_insert_after (GTK_WIDGET (item), canvas, last_child);
apply_transform (item);
@ -115,8 +274,6 @@ drag_drop (GtkDropTarget *target,
static double pos_x, pos_y;
static GtkWidget * canvas_item_new (double x, double y);
static void
new_item_cb (GtkWidget *button, gpointer data)
{
@ -125,7 +282,7 @@ new_item_cb (GtkWidget *button, gpointer data)
item = canvas_item_new (pos_x, pos_y);
gtk_fixed_put (GTK_FIXED (canvas), item, 0, 0);
apply_transform (item);
apply_transform (CANVAS_ITEM (item));
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
}
@ -134,14 +291,14 @@ static void
edit_label_done (GtkWidget *entry, gpointer data)
{
GtkWidget *canvas = gtk_widget_get_parent (entry);
GtkWidget *label;
CanvasItem *item;
int x, y;
gtk_fixed_get_child_position (GTK_FIXED (canvas), entry, &x, &y);
label = GTK_WIDGET (g_object_get_data (G_OBJECT (entry), "label"));
gtk_label_set_text (GTK_LABEL (label), gtk_editable_get_text (GTK_EDITABLE (entry)));
gtk_widget_show (label);
item = CANVAS_ITEM (g_object_get_data (G_OBJECT (entry), "item"));
gtk_label_set_text (GTK_LABEL (item->label), gtk_editable_get_text (GTK_EDITABLE (entry)));
gtk_widget_show (GTK_WIDGET (item));
gtk_fixed_remove (GTK_FIXED (canvas), entry);
}
@ -150,23 +307,24 @@ static void
edit_cb (GtkWidget *button, GtkWidget *child)
{
GtkWidget *canvas = gtk_widget_get_parent (child);
CanvasItem *item = CANVAS_ITEM (child);
GtkWidget *entry;
int x, y;
gtk_fixed_get_child_position (GTK_FIXED (canvas), child, &x, &y);
if (GTK_IS_LABEL (child))
{
GtkWidget *entry = gtk_entry_new ();
entry = gtk_entry_new ();
g_object_set_data (G_OBJECT (entry), "label", child);
g_object_set_data (G_OBJECT (entry), "item", item);
gtk_editable_set_text (GTK_EDITABLE (entry), gtk_label_get_text (GTK_LABEL (child)));
gtk_editable_set_width_chars (GTK_EDITABLE (entry), 12);
g_signal_connect (entry, "activate", G_CALLBACK (edit_label_done), NULL);
gtk_fixed_put (GTK_FIXED (canvas), entry, x, y);
gtk_widget_grab_focus (entry);
gtk_widget_hide (child);
}
gtk_editable_set_text (GTK_EDITABLE (entry),
gtk_label_get_text (GTK_LABEL (item->label)));
gtk_editable_set_width_chars (GTK_EDITABLE (entry), 12);
g_signal_connect (entry, "activate", G_CALLBACK (edit_label_done), NULL);
gtk_fixed_put (GTK_FIXED (canvas), entry, x, y);
gtk_widget_grab_focus (entry);
gtk_widget_hide (child);
if (button)
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
@ -194,6 +352,7 @@ pressed_cb (GtkGesture *gesture,
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
child = gtk_widget_pick (widget, x, y, GTK_PICK_DEFAULT);
child = gtk_widget_get_ancestor (child, canvas_item_get_type ());
if (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)) == GDK_BUTTON_SECONDARY)
{
@ -250,6 +409,7 @@ released_cb (GtkGesture *gesture,
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
child = gtk_widget_pick (widget, x, y, 0);
child = gtk_widget_get_ancestor (child, canvas_item_get_type ());
if (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)) == GDK_BUTTON_PRIMARY)
{
@ -292,131 +452,6 @@ canvas_new (void)
return canvas;
}
static void
set_color (GtkWidget *item,
GdkRGBA *color)
{
char *css;
char *str;
GtkStyleContext *context;
GtkCssProvider *provider;
str = gdk_rgba_to_string (color);
css = g_strdup_printf ("* { background: %s; padding: 10px; }", str);
context = gtk_widget_get_style_context (item);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css, -1);
gtk_style_context_add_provider (gtk_widget_get_style_context (item), GTK_STYLE_PROVIDER (provider), 800);
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
g_free (str);
g_free (css);
}
static gboolean
item_drag_drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
set_color (item, g_value_get_boxed (value));
return TRUE;
}
static void
angle_changed (GtkGestureRotate *gesture,
double angle,
double delta)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
TransformData *data = g_object_get_data (G_OBJECT (item), "transform-data");
data->delta = angle / M_PI * 180.0;
apply_transform (item);
}
static void
rotate_done (GtkGesture *gesture)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
TransformData *data = g_object_get_data (G_OBJECT (item), "transform-data");
data->angle = data->angle + data->delta;
data->delta = 0;
}
static void
click_done (GtkGesture *gesture)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
GtkWidget *canvas = gtk_widget_get_parent (item);
GtkWidget *last_child;
last_child = gtk_widget_get_last_child (canvas);
if (item != last_child)
gtk_widget_insert_after (item, canvas, last_child);
}
static int n_items = 0;
static GtkWidget *
canvas_item_new (double x,
double y)
{
GtkWidget *widget;
char *label;
char *id;
TransformData *transform_data;
GdkRGBA rgba;
GtkDropTarget *dest;
GtkGesture *gesture;
n_items++;
label = g_strdup_printf ("Item %d", n_items);
id = g_strdup_printf ("item%d", n_items);
gdk_rgba_parse (&rgba, "yellow");
widget = gtk_label_new (label);
gtk_widget_add_css_class (widget, "frame");
gtk_widget_set_name (widget, id);
set_color (widget, &rgba);
transform_data = g_new0 (TransformData, 1);
transform_data->x = x;
transform_data->y = y;
transform_data->angle = 0.0;
g_object_set_data_full (G_OBJECT (widget), "transform-data", transform_data, g_free);
g_free (label);
g_free (id);
dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_rotate_new ();
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture));
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture));
return widget;
}
static GtkWidget *window = NULL;
GtkWidget *
@ -465,7 +500,7 @@ do_dnd (GtkWidget *do_widget)
item = canvas_item_new (x, y);
gtk_fixed_put (GTK_FIXED (canvas), item, 0, 0);
apply_transform (item);
apply_transform (CANVAS_ITEM (item));
x += 150;
y += 100;