gtk2/tests/testdnd3.c
Matthias Clasen 0297039b38 Add another dnd testcase
This one tests nested drop sites and interaction between
DND and other gestures.
2020-01-08 18:48:22 -05:00

401 lines
11 KiB
C

#include <gtk/gtk.h>
static GdkContentProvider *
prepare (GtkDragSource *source, double x, double y)
{
GtkWidget *canvas;
GtkWidget *item;
GdkContentProvider *provider;
GBytes *bytes;
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))
return NULL;
bytes = g_bytes_new (&item, sizeof (gpointer));
provider = gdk_content_provider_new_for_bytes ("CANVAS_ITEM", bytes);
g_bytes_unref (bytes);
g_object_set_data (G_OBJECT (canvas), "dragged-item", item);
return provider;
}
static void
drag_begin (GtkDragSource *source, GdkDrag *drag)
{
GtkWidget *canvas;
GtkWidget *item;
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = g_object_get_data (G_OBJECT (canvas), "dragged-item");
gtk_widget_set_opacity (item, 0.5);
}
static void
drag_end (GtkDragSource *source, GdkDrag *drag)
{
GtkWidget *canvas;
GtkWidget *item;
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = g_object_get_data (G_OBJECT (canvas), "dragged-item");
g_object_set_data (G_OBJECT (canvas), "dragged-item", NULL);
gtk_widget_set_opacity (item, 1.0);
}
typedef struct {
GtkWidget *canvas;
double x;
double y;
} DropData;
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 void
got_data (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GdkDrop *drop = GDK_DROP (source);
DropData *data = user_data;
GInputStream *stream;
GBytes *bytes;
GtkWidget *item;
const char *mime_type;
GError *error = NULL;
TransformData *transform_data;
GtkWidget *canvas;
GtkWidget *last_child;
stream = gdk_drop_read_finish (drop, result, &mime_type, &error);
bytes = g_input_stream_read_bytes (stream, sizeof (gpointer), NULL, NULL);
item = (gpointer) *(gpointer *)g_bytes_get_data (bytes, NULL);
transform_data = g_object_get_data (G_OBJECT (item), "transform-data");
transform_data->x = data->x;
transform_data->y = data->y;
canvas = gtk_widget_get_parent (item);
last_child = gtk_widget_get_last_child (canvas);
if (item != last_child)
gtk_widget_insert_after (item, canvas, last_child);
apply_transform (item);
gdk_drop_finish (drop, GDK_ACTION_MOVE);
g_bytes_unref (bytes);
g_object_unref (stream);
g_free (data);
}
static gboolean
drag_drop (GtkDropTarget *dest,
GdkDrop *drop,
int x,
int y)
{
DropData *data;
data = g_new (DropData, 1);
data->canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
data->x = x;
data->y = y;
gdk_drop_read_async (drop, (const char *[]){"CANVAS_ITEM", NULL}, G_PRIORITY_DEFAULT, NULL, got_data, data);
return TRUE;
}
static GtkWidget *
canvas_new (void)
{
GtkWidget *canvas;
GtkDragSource *source;
GtkDropTarget *dest;
GdkContentFormats *formats;
canvas = gtk_fixed_new ();
gtk_widget_set_hexpand (canvas, TRUE);
gtk_widget_set_vexpand (canvas, TRUE);
gtk_style_context_add_class (gtk_widget_get_style_context (canvas), "frame");
source = gtk_drag_source_new ();
gtk_drag_source_set_actions (source, GDK_ACTION_MOVE);
g_signal_connect (source, "prepare", G_CALLBACK (prepare), NULL);
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), NULL);
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (source));
formats = gdk_content_formats_new ((const char *[]){"CANVAS_ITEM", NULL}, 1);
dest = gtk_drop_target_new (formats, GDK_ACTION_MOVE);
g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), NULL);
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (dest));
gdk_content_formats_unref (formats);
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 void
got_color (GObject *source,
GAsyncResult *result,
gpointer data)
{
GdkDrop *drop = GDK_DROP (source);
GtkDropTarget *dest = data;
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
const GValue *value;
GdkRGBA *color;
value = gdk_drop_read_value_finish (drop, result, NULL);
color = g_value_get_boxed (value);
set_color (item, color);
gdk_drop_finish (drop, GDK_ACTION_COPY);
}
static gboolean
item_drag_drop (GtkDropTarget *dest,
GdkDrop *drop,
int x,
int y)
{
if (gtk_drop_target_find_mimetype (dest))
{
gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, dest);
return TRUE;
}
return FALSE;
}
static gboolean
item_drag_motion (GtkDropTarget *dest,
GdkDrop *drop,
int x,
int y)
{
if (gtk_drop_target_find_mimetype (dest) != NULL)
{
gdk_drop_status (drop, GDK_ACTION_COPY);
return TRUE;
}
return FALSE;
}
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 GtkWidget *
canvas_item_new (int i,
double x,
double y,
double angle)
{
GtkWidget *widget;
char *label;
char *id;
TransformData *transform_data;
GdkRGBA rgba;
GtkDropTarget *dest;
GdkContentFormats *formats;
GtkGesture *gesture;
label = g_strdup_printf ("Item %d", i);
id = g_strdup_printf ("item%d", i);
gdk_rgba_parse (&rgba, "yellow");
widget = gtk_label_new (label);
gtk_style_context_add_class (gtk_widget_get_style_context (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 = angle;
g_object_set_data_full (G_OBJECT (widget), "transform-data", transform_data, g_free);
g_free (label);
g_free (id);
formats = gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA);
dest = gtk_drop_target_new (formats, GDK_ACTION_COPY);
g_signal_connect (dest, "drag-drop", G_CALLBACK (item_drag_drop), NULL);
g_signal_connect (dest, "drag-motion", G_CALLBACK (item_drag_motion), NULL);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
gdk_content_formats_unref (formats);
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;
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *sw;
GtkWidget *canvas;
GtkWidget *widget;
GtkWidget *box, *box2, *box3;
const char *colors[] = {
"red", "green", "blue", "magenta", "orange", "gray", "black", "yellow",
"white", "gray", "brown", "pink", "cyan", "bisque", "gold", "maroon",
"navy", "orchid", "olive", "peru", "salmon", "silver", "wheat",
NULL
};
int i;
int x, y;
gtk_init ();
widget = gtk_color_button_new ();
gtk_widget_destroy (widget);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (window), box);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add (GTK_CONTAINER (box), box2);
canvas = canvas_new ();
gtk_container_add (GTK_CONTAINER (box2), canvas);
x = y = 40;
for (i = 0; i < 4; i++)
{
GtkWidget *item;
item = canvas_item_new (i, x, y, 0);
gtk_container_add (GTK_CONTAINER (canvas), item);
apply_transform (item);
x += 150;
y += 100;
}
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_NEVER);
gtk_container_add (GTK_CONTAINER (box), sw);
box3 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_style_context_add_class (gtk_widget_get_style_context (box3), "linked");
gtk_container_add (GTK_CONTAINER (sw), box3);
for (i = 0; colors[i]; i++)
{
GdkRGBA rgba;
GtkWidget *swatch;
gdk_rgba_parse (&rgba, colors[i]);
swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
"rgba", &rgba,
"selectable", FALSE,
NULL);
gtk_container_add (GTK_CONTAINER (box3), swatch);
}
gtk_widget_show (window);
gtk_main ();
return 0;
}