Make adding symbols to the diagram possible.
This required creating a simple framework for operations to LdCanvas. It is probable that it's going to require some changes when other operations are added. The basic idea behind it seems to be good, though.
This commit is contained in:
parent
713f2821e4
commit
d3e5483c84
255
src/ld-canvas.c
255
src/ld-canvas.c
@ -10,6 +10,7 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@ -39,6 +40,22 @@
|
||||
/* The default screen resolution in DPI units. */
|
||||
#define DEFAULT_SCREEN_RESOLUTION 96
|
||||
|
||||
/*
|
||||
* OperationEnd:
|
||||
*
|
||||
* Called upon ending an operation.
|
||||
*/
|
||||
typedef void (*OperationEnd) (LdCanvas *self);
|
||||
|
||||
struct _AddObjectData
|
||||
{
|
||||
LdDiagramObject *object;
|
||||
gboolean visible;
|
||||
};
|
||||
|
||||
typedef struct _AddObjectData AddObjectData;
|
||||
|
||||
|
||||
/*
|
||||
* LdCanvasPrivate:
|
||||
* @diagram: A diagram object assigned to this canvas as a model.
|
||||
@ -48,6 +65,9 @@
|
||||
* @x: The X coordinate of the center of view.
|
||||
* @y: The Y coordinate of the center of view.
|
||||
* @zoom: The current zoom of the canvas.
|
||||
* @operation: The current operation.
|
||||
* @operation_data: Data related to the current operation.
|
||||
* @operation_end: A callback to end the operation.
|
||||
*/
|
||||
struct _LdCanvasPrivate
|
||||
{
|
||||
@ -60,8 +80,18 @@ struct _LdCanvasPrivate
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble zoom;
|
||||
|
||||
gint operation;
|
||||
OperationEnd operation_end;
|
||||
union
|
||||
{
|
||||
AddObjectData add_object;
|
||||
}
|
||||
operation_data;
|
||||
};
|
||||
|
||||
#define OPER_DATA(self, member) ((self)->priv->operation_data.member)
|
||||
|
||||
G_DEFINE_TYPE (LdCanvas, ld_canvas, GTK_TYPE_DRAWING_AREA);
|
||||
|
||||
enum
|
||||
@ -71,7 +101,11 @@ enum
|
||||
PROP_LIBRARY
|
||||
};
|
||||
|
||||
typedef struct _DrawData DrawData;
|
||||
enum
|
||||
{
|
||||
OPER_0,
|
||||
OPER_ADD_OBJECT
|
||||
};
|
||||
|
||||
/*
|
||||
* DrawData:
|
||||
@ -88,6 +122,9 @@ struct _DrawData
|
||||
gdouble scale;
|
||||
};
|
||||
|
||||
typedef struct _DrawData DrawData;
|
||||
|
||||
|
||||
static void ld_canvas_get_property (GObject *object, guint property_id,
|
||||
GValue *value, GParamSpec *pspec);
|
||||
static void ld_canvas_set_property (GObject *object, guint property_id,
|
||||
@ -104,11 +141,26 @@ static void on_size_allocate (GtkWidget *widget, GtkAllocation *allocation,
|
||||
static gdouble ld_canvas_get_base_unit_in_px (GtkWidget *self);
|
||||
static gdouble ld_canvas_get_scale_in_px (LdCanvas *self);
|
||||
|
||||
static gboolean on_motion_notify (GtkWidget *widget, GdkEventMotion *event,
|
||||
gpointer user_data);
|
||||
static gboolean on_leave_notify (GtkWidget *widget, GdkEventCrossing *event,
|
||||
gpointer user_data);
|
||||
static gboolean on_button_press (GtkWidget *widget, GdkEventButton *event,
|
||||
gpointer user_data);
|
||||
static gboolean on_button_release (GtkWidget *widget, GdkEventButton *event,
|
||||
gpointer user_data);
|
||||
|
||||
static void move_object_to_widget_coords (LdCanvas *self,
|
||||
LdDiagramObject *object, gdouble x, gdouble y);
|
||||
static LdSymbol *resolve_diagram_symbol (LdCanvas *self,
|
||||
LdDiagramSymbol *diagram_symbol);
|
||||
static gboolean get_symbol_clip_area_on_widget (LdCanvas *self,
|
||||
LdDiagramSymbol *diagram_symbol, gdouble *x, gdouble *y,
|
||||
gdouble *width, gdouble *height);
|
||||
static void queue_object_redraw (LdCanvas *self, LdDiagramObject *object);
|
||||
|
||||
static void ld_canvas_real_cancel_operation (LdCanvas *self);
|
||||
static void ld_canvas_add_object_end (LdCanvas *self);
|
||||
|
||||
static gboolean on_expose_event (GtkWidget *widget, GdkEventExpose *event,
|
||||
gpointer user_data);
|
||||
@ -123,6 +175,7 @@ ld_canvas_class_init (LdCanvasClass *klass)
|
||||
{
|
||||
GObjectClass *object_class;
|
||||
GtkWidgetClass *widget_class;
|
||||
GtkBindingSet *binding_set;
|
||||
GParamSpec *pspec;
|
||||
|
||||
widget_class = GTK_WIDGET_CLASS (klass);
|
||||
@ -133,6 +186,11 @@ ld_canvas_class_init (LdCanvasClass *klass)
|
||||
object_class->finalize = ld_canvas_finalize;
|
||||
|
||||
klass->set_scroll_adjustments = ld_canvas_real_set_scroll_adjustments;
|
||||
klass->cancel_operation = ld_canvas_real_cancel_operation;
|
||||
|
||||
binding_set = gtk_binding_set_by_class (klass);
|
||||
gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
|
||||
"cancel-operation", 0);
|
||||
|
||||
/**
|
||||
* LdCanvas:diagram:
|
||||
@ -169,6 +227,18 @@ ld_canvas_class_init (LdCanvasClass *klass)
|
||||
g_cclosure_user_marshal_VOID__OBJECT_OBJECT,
|
||||
G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
|
||||
|
||||
/**
|
||||
* LdCanvas::cancel-operation:
|
||||
*
|
||||
* Cancel any current operation.
|
||||
*/
|
||||
klass->cancel_operation_signal = g_signal_new
|
||||
("cancel-operation", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET (LdCanvasClass, cancel_operation), NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (LdCanvasPrivate));
|
||||
}
|
||||
|
||||
@ -187,9 +257,21 @@ ld_canvas_init (LdCanvas *self)
|
||||
g_signal_connect (self, "size-allocate",
|
||||
G_CALLBACK (on_size_allocate), 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, "button-press-event",
|
||||
G_CALLBACK (on_button_press), NULL);
|
||||
g_signal_connect (self, "button-release-event",
|
||||
G_CALLBACK (on_button_release), NULL);
|
||||
|
||||
g_object_set (self, "can-focus", TRUE, NULL);
|
||||
|
||||
gtk_widget_add_events (GTK_WIDGET (self),
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -557,8 +639,74 @@ ld_canvas_diagram_to_widget_coords (LdCanvas *self,
|
||||
}
|
||||
|
||||
|
||||
/* ===== Operations ======================================================== */
|
||||
|
||||
static void
|
||||
ld_canvas_real_cancel_operation (LdCanvas *self)
|
||||
{
|
||||
g_return_if_fail (LD_IS_CANVAS (self));
|
||||
|
||||
if (self->priv->operation)
|
||||
{
|
||||
if (self->priv->operation_end)
|
||||
self->priv->operation_end (self);
|
||||
self->priv->operation = OPER_0;
|
||||
self->priv->operation_end = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ld_canvas_add_object_begin:
|
||||
* @self: An #LdCanvas object.
|
||||
* @object: (transfer full): The object to be added to the diagram.
|
||||
*
|
||||
* Begin an operation for adding an object into the diagram.
|
||||
*/
|
||||
void
|
||||
ld_canvas_add_object_begin (LdCanvas *self, LdDiagramObject *object)
|
||||
{
|
||||
AddObjectData *data;
|
||||
|
||||
g_return_if_fail (LD_IS_CANVAS (self));
|
||||
g_return_if_fail (LD_IS_DIAGRAM_OBJECT (object));
|
||||
|
||||
ld_canvas_real_cancel_operation (self);
|
||||
|
||||
self->priv->operation = OPER_ADD_OBJECT;
|
||||
self->priv->operation_end = ld_canvas_add_object_end;
|
||||
|
||||
data = &OPER_DATA (self, add_object);
|
||||
data->object = object;
|
||||
}
|
||||
|
||||
static void
|
||||
ld_canvas_add_object_end (LdCanvas *self)
|
||||
{
|
||||
AddObjectData *data;
|
||||
|
||||
data = &OPER_DATA (self, add_object);
|
||||
if (data->object)
|
||||
{
|
||||
queue_object_redraw (self, data->object);
|
||||
g_object_unref (data->object);
|
||||
data->object = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ===== Events, rendering ================================================= */
|
||||
|
||||
static void
|
||||
move_object_to_widget_coords (LdCanvas *self, LdDiagramObject *object,
|
||||
gdouble x, gdouble y)
|
||||
{
|
||||
gdouble dx, dy;
|
||||
|
||||
ld_canvas_widget_to_diagram_coords (self, x, y, &dx, &dy);
|
||||
ld_diagram_object_set_x (object, floor (dx + 0.5));
|
||||
ld_diagram_object_set_y (object, floor (dy + 0.5));
|
||||
}
|
||||
|
||||
static LdSymbol *
|
||||
resolve_diagram_symbol (LdCanvas *self, LdDiagramSymbol *diagram_symbol)
|
||||
{
|
||||
@ -606,6 +754,98 @@ get_symbol_clip_area_on_widget (LdCanvas *self, LdDiagramSymbol *diagram_symbol,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
queue_object_redraw (LdCanvas *self, LdDiagramObject *object)
|
||||
{
|
||||
if (LD_IS_DIAGRAM_SYMBOL (object))
|
||||
{
|
||||
gdouble x, y, width, height;
|
||||
|
||||
if (!get_symbol_clip_area_on_widget (self, LD_DIAGRAM_SYMBOL (object),
|
||||
&x, &y, &width, &height))
|
||||
return;
|
||||
gtk_widget_queue_draw_area (GTK_WIDGET (self),
|
||||
floor (x), floor (y), ceil (width), ceil (height));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_motion_notify (GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
|
||||
{
|
||||
LdCanvas *self;
|
||||
|
||||
self = LD_CANVAS (widget);
|
||||
switch (self->priv->operation)
|
||||
{
|
||||
AddObjectData *data;
|
||||
|
||||
case OPER_ADD_OBJECT:
|
||||
data = &OPER_DATA (self, add_object);
|
||||
data->visible = TRUE;
|
||||
|
||||
queue_object_redraw (self, data->object);
|
||||
move_object_to_widget_coords (self, data->object, event->x, event->y);
|
||||
queue_object_redraw (self, data->object);
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_leave_notify (GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
|
||||
{
|
||||
LdCanvas *self;
|
||||
|
||||
self = LD_CANVAS (widget);
|
||||
switch (self->priv->operation)
|
||||
{
|
||||
AddObjectData *data;
|
||||
|
||||
case OPER_ADD_OBJECT:
|
||||
data = &OPER_DATA (self, add_object);
|
||||
data->visible = FALSE;
|
||||
|
||||
queue_object_redraw (self, data->object);
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_button_press (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
|
||||
{
|
||||
LdCanvas *self;
|
||||
|
||||
if (!gtk_widget_has_focus (widget))
|
||||
gtk_widget_grab_focus (widget);
|
||||
|
||||
self = LD_CANVAS (widget);
|
||||
switch (self->priv->operation)
|
||||
{
|
||||
AddObjectData *data;
|
||||
|
||||
case OPER_ADD_OBJECT:
|
||||
data = &OPER_DATA (self, add_object);
|
||||
|
||||
queue_object_redraw (self, data->object);
|
||||
move_object_to_widget_coords (self, data->object, event->x, event->y);
|
||||
|
||||
if (self->priv->diagram)
|
||||
ld_diagram_insert_object (self->priv->diagram, data->object, -1);
|
||||
|
||||
/* XXX: "cancel" causes confusion. */
|
||||
ld_canvas_real_cancel_operation (self);
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_button_release (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
|
||||
{
|
||||
@ -680,6 +920,17 @@ draw_diagram (GtkWidget *widget, DrawData *data)
|
||||
objects = ld_diagram_get_objects (data->self->priv->diagram);
|
||||
g_slist_foreach (objects, (GFunc) draw_object, data);
|
||||
|
||||
switch (data->self->priv->operation)
|
||||
{
|
||||
AddObjectData *op_data;
|
||||
|
||||
case OPER_ADD_OBJECT:
|
||||
op_data = &OPER_DATA (data->self, add_object);
|
||||
if (op_data->visible)
|
||||
draw_object (op_data->object, data);
|
||||
break;
|
||||
}
|
||||
|
||||
cairo_restore (data->cr);
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,11 @@ struct _LdCanvasClass
|
||||
/*< private >*/
|
||||
GtkDrawingAreaClass parent_class;
|
||||
|
||||
guint cancel_operation_signal;
|
||||
|
||||
void (*set_scroll_adjustments) (LdCanvas *self,
|
||||
GtkAdjustment *horizontal, GtkAdjustment *vertical);
|
||||
void (*cancel_operation) (LdCanvas *self);
|
||||
};
|
||||
|
||||
|
||||
@ -75,6 +78,8 @@ void ld_canvas_widget_to_diagram_coords (LdCanvas *self,
|
||||
void ld_canvas_diagram_to_widget_coords (LdCanvas *self,
|
||||
gdouble dx, gdouble dy, gdouble *wx, gdouble *wy);
|
||||
|
||||
void ld_canvas_add_object_begin (LdCanvas *self, LdDiagramObject *object);
|
||||
|
||||
/* TODO: The rest of the interface. */
|
||||
|
||||
|
||||
|
@ -761,7 +761,25 @@ on_canvas_button_release (GtkWidget *widget, GdkEventButton *event,
|
||||
if (event->button != 1)
|
||||
return FALSE;
|
||||
|
||||
/* TODO: Add the selected symbol into the document on the position. */
|
||||
if (data->active_item != -1)
|
||||
{
|
||||
LdDiagramSymbol *symbol;
|
||||
const gchar *category_name, *symbol_name;
|
||||
gchar *klass;
|
||||
|
||||
category_name = ld_symbol_category_get_name
|
||||
(g_object_get_data (G_OBJECT (data->active_button), "category"));
|
||||
symbol_name = ld_symbol_get_name
|
||||
(data->items[data->active_item].symbol);
|
||||
|
||||
klass = g_build_path (LD_LIBRARY_IDENTIFIER_SEPARATOR,
|
||||
category_name, symbol_name, NULL);
|
||||
symbol = ld_diagram_symbol_new (klass);
|
||||
g_free (klass);
|
||||
|
||||
ld_canvas_add_object_begin (self->priv->canvas,
|
||||
LD_DIAGRAM_OBJECT (symbol));
|
||||
}
|
||||
|
||||
/* We've either chosen a symbol or canceled the menu, so hide it. */
|
||||
if (data->active_button)
|
||||
|
Loading…
Reference in New Issue
Block a user