diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ld-canvas.c | 255 | ||||
| -rw-r--r-- | src/ld-canvas.h | 5 | ||||
| -rw-r--r-- | src/ld-window-main.c | 20 | 
3 files changed, 277 insertions, 3 deletions
diff --git a/src/ld-canvas.c b/src/ld-canvas.c index 08311ff..e8c6021 100644 --- a/src/ld-canvas.c +++ b/src/ld-canvas.c @@ -10,6 +10,7 @@  #include <math.h>  #include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h>  #include "config.h" @@ -40,6 +41,22 @@  #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.   * @library: A library 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);  } diff --git a/src/ld-canvas.h b/src/ld-canvas.h index bb41b3d..74b3c33 100644 --- a/src/ld-canvas.h +++ b/src/ld-canvas.h @@ -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. */ diff --git a/src/ld-window-main.c b/src/ld-window-main.c index 16c223c..32212a1 100644 --- a/src/ld-window-main.c +++ b/src/ld-window-main.c @@ -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)  | 
