Add drag and drop support for symbols.
This commit is contained in:
parent
c12c6fbf56
commit
3b85eeec8d
|
@ -30,21 +30,6 @@
|
||||||
#define SYMBOL_HEIGHT 40 /* Height of a symbol. */
|
#define SYMBOL_HEIGHT 40 /* Height of a symbol. */
|
||||||
#define SYMBOL_SPACING 10 /* Spacing between symbols, and also borders. */
|
#define SYMBOL_SPACING 10 /* Spacing between symbols, and also borders. */
|
||||||
|
|
||||||
/*
|
|
||||||
* LdCategorySymbolViewPrivate:
|
|
||||||
* @category: a category object assigned as a model.
|
|
||||||
* @path: path to the category within the library.
|
|
||||||
* @layout: (element-type SymbolData *): current layout of symbols.
|
|
||||||
* @height_negotiation: whether we are negotiating height right now.
|
|
||||||
*/
|
|
||||||
struct _LdCategorySymbolViewPrivate
|
|
||||||
{
|
|
||||||
LdCategory *category;
|
|
||||||
gchar *path;
|
|
||||||
GSList *layout;
|
|
||||||
guint height_negotiation : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
LdSymbol *symbol; /* The associated symbol, ref'ed. */
|
LdSymbol *symbol; /* The associated symbol, ref'ed. */
|
||||||
|
@ -56,6 +41,23 @@ typedef struct
|
||||||
}
|
}
|
||||||
SymbolData;
|
SymbolData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LdCategorySymbolViewPrivate:
|
||||||
|
* @category: a category object assigned as a model.
|
||||||
|
* @path: path to the category within the library.
|
||||||
|
* @layout: (element-type SymbolData *): current layout of symbols.
|
||||||
|
* @preselected: currently preselected symbol.
|
||||||
|
* @height_negotiation: whether we are negotiating height right now.
|
||||||
|
*/
|
||||||
|
struct _LdCategorySymbolViewPrivate
|
||||||
|
{
|
||||||
|
LdCategory *category;
|
||||||
|
gchar *path;
|
||||||
|
GSList *layout;
|
||||||
|
SymbolData *preselected;
|
||||||
|
guint height_negotiation : 1;
|
||||||
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
|
@ -103,6 +105,112 @@ ld_category_symbol_view_class_init (LdCategorySymbolViewClass *klass)
|
||||||
g_type_class_add_private (klass, sizeof (LdCategorySymbolViewPrivate));
|
g_type_class_add_private (klass, sizeof (LdCategorySymbolViewPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
symbol_redraw (LdCategorySymbolView *self, SymbolData *symbol)
|
||||||
|
{
|
||||||
|
gtk_widget_queue_draw_area (GTK_WIDGET (self),
|
||||||
|
symbol->rect.x,
|
||||||
|
symbol->rect.y,
|
||||||
|
symbol->rect.width,
|
||||||
|
symbol->rect.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
symbol_deselect (LdCategorySymbolView *self)
|
||||||
|
{
|
||||||
|
if (!self->priv->preselected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
symbol_redraw (self, self->priv->preselected);
|
||||||
|
self->priv->preselected = NULL;
|
||||||
|
gtk_drag_source_unset (GTK_WIDGET (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_leave_notify (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
|
||||||
|
{
|
||||||
|
symbol_deselect (LD_CATEGORY_SYMBOL_VIEW (widget));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_motion_notify (GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
|
||||||
|
{
|
||||||
|
LdCategorySymbolView *self;
|
||||||
|
GSList *iter;
|
||||||
|
|
||||||
|
if (event->state & GDK_BUTTON1_MASK)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
self = LD_CATEGORY_SYMBOL_VIEW (widget);
|
||||||
|
for (iter = self->priv->layout; iter; iter = iter->next)
|
||||||
|
{
|
||||||
|
SymbolData *data;
|
||||||
|
|
||||||
|
data = iter->data;
|
||||||
|
if (event->x < data->rect.x
|
||||||
|
|| event->y < data->rect.y
|
||||||
|
|| event->x >= data->rect.x + data->rect.width
|
||||||
|
|| event->y >= data->rect.y + data->rect.height)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (data != self->priv->preselected)
|
||||||
|
{
|
||||||
|
GtkTargetEntry target = {"ld-symbol", GTK_TARGET_SAME_APP, 0};
|
||||||
|
|
||||||
|
symbol_deselect (self);
|
||||||
|
self->priv->preselected = data;
|
||||||
|
symbol_redraw (self, data);
|
||||||
|
|
||||||
|
gtk_drag_source_set (widget,
|
||||||
|
GDK_BUTTON1_MASK, &target, 1, GDK_ACTION_COPY);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol_deselect (self);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_drag_data_get
|
||||||
|
(GtkWidget *widget, GdkDragContext *ctx, GtkSelectionData *selection_data,
|
||||||
|
guint target_type, guint time, gpointer user_data)
|
||||||
|
{
|
||||||
|
LdCategorySymbolView *self;
|
||||||
|
|
||||||
|
self = LD_CATEGORY_SYMBOL_VIEW (widget);
|
||||||
|
g_return_if_fail (self->priv->preselected != NULL);
|
||||||
|
|
||||||
|
gtk_selection_data_set (selection_data,
|
||||||
|
gtk_selection_data_get_target (selection_data),
|
||||||
|
8, (guchar *) self->priv->preselected->path,
|
||||||
|
strlen (self->priv->preselected->path));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_drag_begin (GtkWidget *widget, GdkDragContext *ctx, gpointer user_data)
|
||||||
|
{
|
||||||
|
LdCategorySymbolView *self;
|
||||||
|
GdkPixbuf *pbuf;
|
||||||
|
|
||||||
|
self = LD_CATEGORY_SYMBOL_VIEW (widget);
|
||||||
|
g_return_if_fail (self->priv->preselected != NULL);
|
||||||
|
|
||||||
|
/* Some of the larger previews didn't work, and we have to get rid of
|
||||||
|
* the icon later when we're hovering above LdDiagramView anyway. */
|
||||||
|
pbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
|
||||||
|
gdk_pixbuf_fill (pbuf, 0x00000000);
|
||||||
|
gtk_drag_set_icon_pixbuf (ctx, pbuf, 0, 0);
|
||||||
|
g_object_unref (pbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_drag_end (GtkWidget *widget, GdkDragContext *ctx, gpointer user_data)
|
||||||
|
{
|
||||||
|
symbol_deselect (LD_CATEGORY_SYMBOL_VIEW (widget));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ld_category_symbol_view_init (LdCategorySymbolView *self)
|
ld_category_symbol_view_init (LdCategorySymbolView *self)
|
||||||
{
|
{
|
||||||
|
@ -116,6 +224,18 @@ ld_category_symbol_view_init (LdCategorySymbolView *self)
|
||||||
g_signal_connect (self, "expose-event",
|
g_signal_connect (self, "expose-event",
|
||||||
G_CALLBACK (on_expose_event), NULL);
|
G_CALLBACK (on_expose_event), NULL);
|
||||||
|
|
||||||
|
g_signal_connect (self, "motion-notify-event",
|
||||||
|
G_CALLBACK (on_motion_notify), NULL);
|
||||||
|
g_signal_connect (self, "leave-notify-event",
|
||||||
|
G_CALLBACK (on_leave_notify), NULL);
|
||||||
|
|
||||||
|
g_signal_connect (self, "drag-begin",
|
||||||
|
G_CALLBACK (on_drag_begin), NULL);
|
||||||
|
g_signal_connect (self, "drag-data-get",
|
||||||
|
G_CALLBACK (on_drag_data_get), NULL);
|
||||||
|
g_signal_connect (self, "drag-end",
|
||||||
|
G_CALLBACK (on_drag_end), NULL);
|
||||||
|
|
||||||
gtk_widget_add_events (GTK_WIDGET (self),
|
gtk_widget_add_events (GTK_WIDGET (self),
|
||||||
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK
|
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK
|
||||||
| GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
|
| GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
|
||||||
|
@ -136,6 +256,7 @@ layout_destroy (LdCategorySymbolView *self)
|
||||||
g_slist_foreach (self->priv->layout, (GFunc) symbol_data_free, NULL);
|
g_slist_foreach (self->priv->layout, (GFunc) symbol_data_free, NULL);
|
||||||
g_slist_free (self->priv->layout);
|
g_slist_free (self->priv->layout);
|
||||||
self->priv->layout = NULL;
|
self->priv->layout = NULL;
|
||||||
|
self->priv->preselected = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -331,11 +452,15 @@ on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
|
||||||
gdk_cairo_rectangle (cr, &data->rect);
|
gdk_cairo_rectangle (cr, &data->rect);
|
||||||
cairo_clip (cr);
|
cairo_clip (cr);
|
||||||
|
|
||||||
|
gdk_cairo_set_source_color (cr,
|
||||||
|
>k_widget_get_style (widget)->text[GTK_STATE_NORMAL]);
|
||||||
|
|
||||||
|
if (data == self->priv->preselected)
|
||||||
|
cairo_paint_with_alpha (cr, 0.1);
|
||||||
|
|
||||||
cairo_translate (cr, data->rect.x + data->dx, data->rect.y + data->dy);
|
cairo_translate (cr, data->rect.x + data->dx, data->rect.y + data->dy);
|
||||||
cairo_scale (cr, data->scale, data->scale);
|
cairo_scale (cr, data->scale, data->scale);
|
||||||
|
|
||||||
gdk_cairo_set_source_color (cr,
|
|
||||||
>k_widget_get_style (widget)->text[GTK_STATE_NORMAL]);
|
|
||||||
cairo_set_line_width (cr, 1 / data->scale);
|
cairo_set_line_width (cr, 1 / data->scale);
|
||||||
ld_symbol_draw (data->symbol, cr);
|
ld_symbol_draw (data->symbol, cr);
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,9 @@ Color;
|
||||||
* @y: the Y coordinate of the center of view.
|
* @y: the Y coordinate of the center of view.
|
||||||
* @zoom: the current zoom.
|
* @zoom: the current zoom.
|
||||||
* @show_grid: whether to show the grid.
|
* @show_grid: whether to show the grid.
|
||||||
|
* @dnd_symbol: currently dragged symbol.
|
||||||
|
* @dnd_last_position: last cursor movement position.
|
||||||
|
* @dnd_left: whether the user has stopped dragging.
|
||||||
* @terminal: position of the highlighted terminal.
|
* @terminal: position of the highlighted terminal.
|
||||||
* @terminal_hovered: whether a terminal is hovered.
|
* @terminal_hovered: whether a terminal is hovered.
|
||||||
* @drag_start_pos: position of the mouse pointer when dragging started.
|
* @drag_start_pos: position of the mouse pointer when dragging started.
|
||||||
|
@ -152,6 +155,10 @@ struct _LdDiagramViewPrivate
|
||||||
|
|
||||||
gboolean show_grid;
|
gboolean show_grid;
|
||||||
|
|
||||||
|
LdDiagramObject *dnd_symbol;
|
||||||
|
LdPoint dnd_last_position;
|
||||||
|
guint dnd_left : 1;
|
||||||
|
|
||||||
LdPoint terminal;
|
LdPoint terminal;
|
||||||
gboolean terminal_hovered;
|
gboolean terminal_hovered;
|
||||||
|
|
||||||
|
@ -343,6 +350,16 @@ static gboolean on_button_release (GtkWidget *widget, GdkEventButton *event,
|
||||||
static gboolean on_scroll (GtkWidget *widget, GdkEventScroll *event,
|
static gboolean on_scroll (GtkWidget *widget, GdkEventScroll *event,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
static gboolean on_drag_motion (GtkWidget *widget, GdkDragContext *drag_ctx,
|
||||||
|
gint x, gint y, guint time, gpointer user_data);
|
||||||
|
static gboolean on_drag_drop (GtkWidget *widget, GdkDragContext *drag_ctx,
|
||||||
|
gint x, gint y, guint time, gpointer user_data);
|
||||||
|
static void on_drag_data_received (GtkWidget *widget, GdkDragContext *drag_ctx,
|
||||||
|
gint x, gint y, GtkSelectionData *data, guint info,
|
||||||
|
guint time, gpointer user_data);
|
||||||
|
static void on_drag_leave (GtkWidget *widget, GdkDragContext *drag_ctx,
|
||||||
|
guint time, gpointer user_data);
|
||||||
|
|
||||||
static gboolean on_expose_event (GtkWidget *widget, GdkEventExpose *event,
|
static gboolean on_expose_event (GtkWidget *widget, GdkEventExpose *event,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
static void draw_grid (GtkWidget *widget, DrawData *data);
|
static void draw_grid (GtkWidget *widget, DrawData *data);
|
||||||
|
@ -486,6 +503,8 @@ ld_diagram_view_class_init (LdDiagramViewClass *klass)
|
||||||
static void
|
static void
|
||||||
ld_diagram_view_init (LdDiagramView *self)
|
ld_diagram_view_init (LdDiagramView *self)
|
||||||
{
|
{
|
||||||
|
GtkTargetEntry target = {"ld-symbol", GTK_TARGET_SAME_APP, 0};
|
||||||
|
|
||||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE
|
self->priv = G_TYPE_INSTANCE_GET_PRIVATE
|
||||||
(self, LD_TYPE_DIAGRAM_VIEW, LdDiagramViewPrivate);
|
(self, LD_TYPE_DIAGRAM_VIEW, LdDiagramViewPrivate);
|
||||||
|
|
||||||
|
@ -517,12 +536,23 @@ ld_diagram_view_init (LdDiagramView *self)
|
||||||
g_signal_connect (self, "scroll-event",
|
g_signal_connect (self, "scroll-event",
|
||||||
G_CALLBACK (on_scroll), NULL);
|
G_CALLBACK (on_scroll), NULL);
|
||||||
|
|
||||||
|
g_signal_connect (self, "drag-motion",
|
||||||
|
G_CALLBACK (on_drag_motion), NULL);
|
||||||
|
g_signal_connect (self, "drag-leave",
|
||||||
|
G_CALLBACK (on_drag_leave), NULL);
|
||||||
|
g_signal_connect (self, "drag-drop",
|
||||||
|
G_CALLBACK (on_drag_drop), NULL);
|
||||||
|
g_signal_connect (self, "drag-data-received",
|
||||||
|
G_CALLBACK (on_drag_data_received), NULL);
|
||||||
|
|
||||||
g_object_set (self, "can-focus", TRUE, NULL);
|
g_object_set (self, "can-focus", TRUE, NULL);
|
||||||
|
|
||||||
gtk_widget_add_events (GTK_WIDGET (self),
|
gtk_widget_add_events (GTK_WIDGET (self),
|
||||||
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK
|
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK
|
||||||
| GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
|
| GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
|
||||||
| GDK_LEAVE_NOTIFY_MASK);
|
| GDK_LEAVE_NOTIFY_MASK);
|
||||||
|
|
||||||
|
gtk_drag_dest_set (GTK_WIDGET (self), 0, &target, 1, GDK_ACTION_COPY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -541,6 +571,8 @@ ld_diagram_view_finalize (GObject *gobject)
|
||||||
}
|
}
|
||||||
if (self->priv->library)
|
if (self->priv->library)
|
||||||
g_object_unref (self->priv->library);
|
g_object_unref (self->priv->library);
|
||||||
|
if (self->priv->dnd_symbol)
|
||||||
|
g_object_unref (self->priv->dnd_symbol);
|
||||||
|
|
||||||
/* Chain up to the parent class. */
|
/* Chain up to the parent class. */
|
||||||
G_OBJECT_CLASS (ld_diagram_view_parent_class)->finalize (gobject);
|
G_OBJECT_CLASS (ld_diagram_view_parent_class)->finalize (gobject);
|
||||||
|
@ -2424,6 +2456,109 @@ on_scroll (GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_drag_motion (GtkWidget *widget, GdkDragContext *drag_ctx,
|
||||||
|
gint x, gint y, guint time, gpointer user_data)
|
||||||
|
{
|
||||||
|
LdDiagramView *self;
|
||||||
|
GdkAtom target;
|
||||||
|
|
||||||
|
self = LD_DIAGRAM_VIEW (widget);
|
||||||
|
target = gtk_drag_dest_find_target (widget, drag_ctx, NULL);
|
||||||
|
if (target == GDK_NONE)
|
||||||
|
{
|
||||||
|
gdk_drag_status (drag_ctx, 0, time);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdk_drag_status (drag_ctx,
|
||||||
|
gdk_drag_context_get_suggested_action (drag_ctx), time);
|
||||||
|
|
||||||
|
/* Discard leftovers from any previous unsuccessful drag. */
|
||||||
|
if (self->priv->dnd_left)
|
||||||
|
{
|
||||||
|
g_object_unref (self->priv->dnd_symbol);
|
||||||
|
self->priv->dnd_symbol = NULL;
|
||||||
|
self->priv->dnd_left = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->priv->dnd_last_position.x = x;
|
||||||
|
self->priv->dnd_last_position.y = y;
|
||||||
|
|
||||||
|
if (!self->priv->dnd_symbol)
|
||||||
|
gtk_drag_get_data (widget, drag_ctx, target, time);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
queue_object_draw (self, self->priv->dnd_symbol);
|
||||||
|
move_object_to_point (self, self->priv->dnd_symbol,
|
||||||
|
&self->priv->dnd_last_position);
|
||||||
|
queue_object_draw (self, self->priv->dnd_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_drag_data_received (GtkWidget *widget, GdkDragContext *drag_ctx,
|
||||||
|
gint x, gint y, GtkSelectionData *data, guint info, guint time,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LdDiagramView *self;
|
||||||
|
LdDiagramSymbol *symbol;
|
||||||
|
const gchar *klass;
|
||||||
|
|
||||||
|
self = LD_DIAGRAM_VIEW (widget);
|
||||||
|
|
||||||
|
g_return_if_fail (gtk_selection_data_get_length (data) >= 0);
|
||||||
|
g_return_if_fail (self->priv->dnd_symbol == NULL);
|
||||||
|
|
||||||
|
klass = (const gchar *) gtk_selection_data_get_data (data);
|
||||||
|
symbol = ld_diagram_symbol_new (NULL);
|
||||||
|
ld_diagram_symbol_set_class (symbol, klass);
|
||||||
|
self->priv->dnd_symbol = LD_DIAGRAM_OBJECT (symbol);
|
||||||
|
|
||||||
|
move_object_to_point (self, self->priv->dnd_symbol,
|
||||||
|
&self->priv->dnd_last_position);
|
||||||
|
queue_object_draw (self, self->priv->dnd_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_drag_leave (GtkWidget *widget, GdkDragContext *drag_ctx,
|
||||||
|
guint time, gpointer user_data)
|
||||||
|
{
|
||||||
|
LdDiagramView *self;
|
||||||
|
|
||||||
|
self = LD_DIAGRAM_VIEW (widget);
|
||||||
|
self->priv->dnd_left = TRUE;
|
||||||
|
queue_object_draw (self, self->priv->dnd_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_drag_drop (GtkWidget *widget, GdkDragContext *drag_ctx,
|
||||||
|
gint x, gint y, guint time, gpointer user_data)
|
||||||
|
{
|
||||||
|
LdDiagramView *self;
|
||||||
|
gboolean del;
|
||||||
|
|
||||||
|
del = gdk_drag_context_get_suggested_action (drag_ctx)
|
||||||
|
== GDK_ACTION_MOVE;
|
||||||
|
|
||||||
|
self = LD_DIAGRAM_VIEW (widget);
|
||||||
|
if (!self->priv->dnd_symbol)
|
||||||
|
gtk_drag_finish (drag_ctx, FALSE, del, time);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_drag_finish (drag_ctx, TRUE, del, time);
|
||||||
|
|
||||||
|
ld_diagram_insert_object (self->priv->diagram,
|
||||||
|
self->priv->dnd_symbol, -1);
|
||||||
|
g_object_unref (self->priv->dnd_symbol);
|
||||||
|
self->priv->dnd_symbol = NULL;
|
||||||
|
self->priv->dnd_left = FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
|
on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
@ -2572,6 +2707,9 @@ draw_diagram (GtkWidget *widget, DrawData *data)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->self->priv->dnd_symbol && !data->self->priv->dnd_left)
|
||||||
|
draw_object (data->self->priv->dnd_symbol, data);
|
||||||
|
|
||||||
cairo_restore (data->cr);
|
cairo_restore (data->cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue