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:
Přemysl Eric Janouch 2011-01-04 09:54:05 +01:00
parent 713f2821e4
commit d3e5483c84
3 changed files with 277 additions and 3 deletions

View File

@ -10,6 +10,7 @@
#include <math.h> #include <math.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "config.h" #include "config.h"
@ -39,6 +40,22 @@
/* The default screen resolution in DPI units. */ /* The default screen resolution in DPI units. */
#define DEFAULT_SCREEN_RESOLUTION 96 #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: * LdCanvasPrivate:
* @diagram: A diagram object assigned to this canvas as a model. * @diagram: A diagram object assigned to this canvas as a model.
@ -48,6 +65,9 @@
* @x: The X coordinate of the center of view. * @x: The X coordinate of the center of view.
* @y: The Y coordinate of the center of view. * @y: The Y coordinate of the center of view.
* @zoom: The current zoom of the canvas. * @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 struct _LdCanvasPrivate
{ {
@ -60,8 +80,18 @@ struct _LdCanvasPrivate
gdouble x; gdouble x;
gdouble y; gdouble y;
gdouble zoom; 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); G_DEFINE_TYPE (LdCanvas, ld_canvas, GTK_TYPE_DRAWING_AREA);
enum enum
@ -71,7 +101,11 @@ enum
PROP_LIBRARY PROP_LIBRARY
}; };
typedef struct _DrawData DrawData; enum
{
OPER_0,
OPER_ADD_OBJECT
};
/* /*
* DrawData: * DrawData:
@ -88,6 +122,9 @@ struct _DrawData
gdouble scale; gdouble scale;
}; };
typedef struct _DrawData DrawData;
static void ld_canvas_get_property (GObject *object, guint property_id, static void ld_canvas_get_property (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec); GValue *value, GParamSpec *pspec);
static void ld_canvas_set_property (GObject *object, guint property_id, 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_base_unit_in_px (GtkWidget *self);
static gdouble ld_canvas_get_scale_in_px (LdCanvas *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, static LdSymbol *resolve_diagram_symbol (LdCanvas *self,
LdDiagramSymbol *diagram_symbol); LdDiagramSymbol *diagram_symbol);
static gboolean get_symbol_clip_area_on_widget (LdCanvas *self, static gboolean get_symbol_clip_area_on_widget (LdCanvas *self,
LdDiagramSymbol *diagram_symbol, gdouble *x, gdouble *y, LdDiagramSymbol *diagram_symbol, gdouble *x, gdouble *y,
gdouble *width, gdouble *height); 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, static gboolean on_expose_event (GtkWidget *widget, GdkEventExpose *event,
gpointer user_data); gpointer user_data);
@ -123,6 +175,7 @@ ld_canvas_class_init (LdCanvasClass *klass)
{ {
GObjectClass *object_class; GObjectClass *object_class;
GtkWidgetClass *widget_class; GtkWidgetClass *widget_class;
GtkBindingSet *binding_set;
GParamSpec *pspec; GParamSpec *pspec;
widget_class = GTK_WIDGET_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass);
@ -133,6 +186,11 @@ ld_canvas_class_init (LdCanvasClass *klass)
object_class->finalize = ld_canvas_finalize; object_class->finalize = ld_canvas_finalize;
klass->set_scroll_adjustments = ld_canvas_real_set_scroll_adjustments; 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: * LdCanvas:diagram:
@ -169,6 +227,18 @@ ld_canvas_class_init (LdCanvasClass *klass)
g_cclosure_user_marshal_VOID__OBJECT_OBJECT, g_cclosure_user_marshal_VOID__OBJECT_OBJECT,
G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT); 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)); g_type_class_add_private (klass, sizeof (LdCanvasPrivate));
} }
@ -187,9 +257,21 @@ ld_canvas_init (LdCanvas *self)
g_signal_connect (self, "size-allocate", g_signal_connect (self, "size-allocate",
G_CALLBACK (on_size_allocate), NULL); 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), 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);
} }
static void 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 ================================================= */ /* ===== 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 * static LdSymbol *
resolve_diagram_symbol (LdCanvas *self, LdDiagramSymbol *diagram_symbol) 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; 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 static gboolean
on_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) 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); objects = ld_diagram_get_objects (data->self->priv->diagram);
g_slist_foreach (objects, (GFunc) draw_object, data); 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); cairo_restore (data->cr);
} }

View File

@ -48,8 +48,11 @@ struct _LdCanvasClass
/*< private >*/ /*< private >*/
GtkDrawingAreaClass parent_class; GtkDrawingAreaClass parent_class;
guint cancel_operation_signal;
void (*set_scroll_adjustments) (LdCanvas *self, void (*set_scroll_adjustments) (LdCanvas *self,
GtkAdjustment *horizontal, GtkAdjustment *vertical); 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, void ld_canvas_diagram_to_widget_coords (LdCanvas *self,
gdouble dx, gdouble dy, gdouble *wx, gdouble *wy); gdouble dx, gdouble dy, gdouble *wx, gdouble *wy);
void ld_canvas_add_object_begin (LdCanvas *self, LdDiagramObject *object);
/* TODO: The rest of the interface. */ /* TODO: The rest of the interface. */

View File

@ -761,7 +761,25 @@ on_canvas_button_release (GtkWidget *widget, GdkEventButton *event,
if (event->button != 1) if (event->button != 1)
return FALSE; 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. */ /* We've either chosen a symbol or canceled the menu, so hide it. */
if (data->active_button) if (data->active_button)