From baed5ee4bd2dd04e49df650b07278a8ceb900cab Mon Sep 17 00:00:00 2001
From: Přemysl Janouch 
Date: Mon, 14 Feb 2011 10:14:28 +0100
Subject: Allow rotation of symbols.
Bind this action to the right mouse button.
Due to limitations of json-glib, we can't store rotation as an enum.
---
 liblogdiag/ld-canvas.c         | 140 +++++++++++++++++++++++++++++++++++++----
 liblogdiag/ld-canvas.h         |   2 -
 liblogdiag/ld-diagram-symbol.c |  45 ++++++++++++-
 liblogdiag/ld-diagram-symbol.h |  10 +++
 4 files changed, 181 insertions(+), 16 deletions(-)
(limited to 'liblogdiag')
diff --git a/liblogdiag/ld-canvas.c b/liblogdiag/ld-canvas.c
index 9342973..a180167 100644
--- a/liblogdiag/ld-canvas.c
+++ b/liblogdiag/ld-canvas.c
@@ -240,6 +240,7 @@ static void queue_object_draw (LdCanvas *self, LdDiagramObject *object);
 
 /* Symbol terminals. */
 static void check_terminals (LdCanvas *self, const LdPoint *point);
+static void rotate_terminal (LdPoint *terminal, gint symbol_rotation);
 static void hide_terminals (LdCanvas *self);
 static void queue_terminal_draw (LdCanvas *self, LdPoint *terminal);
 
@@ -251,6 +252,8 @@ static gboolean get_symbol_clip_area (LdCanvas *self,
 
 static gboolean get_symbol_area (LdCanvas *self,
 	LdDiagramSymbol *symbol, LdRectangle *rect);
+static void rotate_symbol_area (LdRectangle *area, gint rotation);
+static void rotate_symbol (LdCanvas *self, LdDiagramSymbol *symbol);
 static LdSymbol *resolve_symbol (LdCanvas *self,
 	LdDiagramSymbol *diagram_symbol);
 
@@ -1162,12 +1165,12 @@ check_terminals (LdCanvas *self, const LdPoint *point)
 	objects = (GList *) ld_diagram_get_objects (self->priv->diagram);
 	for (iter = objects; iter; iter = g_list_next (iter))
 	{
-		LdDiagramObject *diagram_object;
 		gdouble object_x, object_y;
 		LdDiagramSymbol *diagram_symbol;
 		LdSymbol *symbol;
 		const LdPointArray *terminals;
 		guint i;
+		gint rotation;
 
 		if (!LD_IS_DIAGRAM_SYMBOL (iter->data))
 			continue;
@@ -1177,17 +1180,17 @@ check_terminals (LdCanvas *self, const LdPoint *point)
 		if (!symbol)
 			continue;
 
-		diagram_object = LD_DIAGRAM_OBJECT (iter->data);
-		g_object_get (diagram_object, "x", &object_x, "y", &object_y, NULL);
+		g_object_get (diagram_symbol, "x", &object_x, "y", &object_y,
+			"rotation", &rotation, NULL);
 
 		terminals = ld_symbol_get_terminals (symbol);
-
 		for (i = 0; i < terminals->length; i++)
 		{
 			LdPoint cur_term, widget_coords;
 			gdouble distance;
 
 			cur_term = terminals->points[i];
+			rotate_terminal (&cur_term, rotation);
 			cur_term.x += object_x;
 			cur_term.y += object_y;
 
@@ -1213,6 +1216,30 @@ check_terminals (LdCanvas *self, const LdPoint *point)
 	}
 }
 
+static void
+rotate_terminal (LdPoint *terminal, gint symbol_rotation)
+{
+	gdouble temp;
+
+	switch (symbol_rotation)
+	{
+	case LD_DIAGRAM_SYMBOL_ROTATION_90:
+		temp = terminal->y;
+		terminal->y = terminal->x;
+		terminal->x = -temp;
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_180:
+		terminal->y = -terminal->y;
+		terminal->x = -terminal->x;
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_270:
+		temp = terminal->x;
+		terminal->x = terminal->y;
+		terminal->y = -temp;
+		break;
+	}
+}
+
 static void
 hide_terminals (LdCanvas *self)
 {
@@ -1276,8 +1303,10 @@ get_symbol_area (LdCanvas *self, LdDiagramSymbol *symbol, LdRectangle *rect)
 	LdRectangle area;
 	gdouble x1, x2;
 	gdouble y1, y2;
+	gint rotation;
 
-	g_object_get (symbol, "x", &object_x, "y", &object_y, NULL);
+	g_object_get (symbol, "x", &object_x, "y", &object_y,
+		"rotation", &rotation, NULL);
 
 	library_symbol = resolve_symbol (self, symbol);
 	if (library_symbol)
@@ -1285,7 +1314,8 @@ get_symbol_area (LdCanvas *self, LdDiagramSymbol *symbol, LdRectangle *rect)
 	else
 		return FALSE;
 
-	/* TODO: Rotate the rectangle for other orientations. */
+	rotate_symbol_area (&area, rotation);
+
 	ld_canvas_diagram_to_widget_coords (self,
 		object_x + area.x,
 		object_y + area.y,
@@ -1307,6 +1337,68 @@ get_symbol_area (LdCanvas *self, LdDiagramSymbol *symbol, LdRectangle *rect)
 	return TRUE;
 }
 
+static void
+rotate_symbol_area (LdRectangle *area, gint rotation)
+{
+	gdouble temp;
+
+	switch (rotation)
+	{
+	case LD_DIAGRAM_SYMBOL_ROTATION_90:
+		temp = area->y;
+		area->y = area->x;
+		area->x = -(temp + area->height);
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_180:
+		area->y = -(area->y + area->height);
+		area->x = -(area->x + area->width);
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_270:
+		temp = area->x;
+		area->x = area->y;
+		area->y = -(temp + area->width);
+		break;
+	}
+
+	switch (rotation)
+	{
+	case LD_DIAGRAM_SYMBOL_ROTATION_90:
+	case LD_DIAGRAM_SYMBOL_ROTATION_270:
+		temp = area->width;
+		area->width = area->height;
+		area->height = temp;
+		break;
+	}
+}
+
+static void
+rotate_symbol (LdCanvas *self, LdDiagramSymbol *symbol)
+{
+	gint rotation;
+
+	g_object_get (symbol, "rotation", &rotation, NULL);
+	queue_object_draw (self, LD_DIAGRAM_OBJECT (symbol));
+
+	switch (rotation)
+	{
+	case LD_DIAGRAM_SYMBOL_ROTATION_0:
+		rotation = LD_DIAGRAM_SYMBOL_ROTATION_90;
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_90:
+		rotation = LD_DIAGRAM_SYMBOL_ROTATION_180;
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_180:
+		rotation = LD_DIAGRAM_SYMBOL_ROTATION_270;
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_270:
+		rotation = LD_DIAGRAM_SYMBOL_ROTATION_0;
+		break;
+	}
+
+	g_object_set (symbol, "rotation", rotation, NULL);
+	queue_object_draw (self, LD_DIAGRAM_OBJECT (symbol));
+}
+
 static LdSymbol *
 resolve_symbol (LdCanvas *self, LdDiagramSymbol *diagram_symbol)
 {
@@ -1846,11 +1938,6 @@ on_button_press (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
 	AddObjectData *data;
 	LdDiagramObject *object;
 
-	if (event->button != 1)
-		return FALSE;
-	if (!gtk_widget_has_focus (widget))
-		gtk_widget_grab_focus (widget);
-
 	point.x = event->x;
 	point.y = event->y;
 
@@ -1858,6 +1945,19 @@ on_button_press (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
 	if (!self->priv->diagram)
 		return FALSE;
 
+	if (event->button == 3 && self->priv->operation == OPER_0)
+	{
+		object = get_object_at_point (self, &point);
+		if (object && LD_IS_DIAGRAM_SYMBOL (object))
+			rotate_symbol (self, LD_DIAGRAM_SYMBOL (object));
+		return FALSE;
+	}
+
+	if (event->button != 1)
+		return FALSE;
+	if (!gtk_widget_has_focus (widget))
+		gtk_widget_grab_focus (widget);
+
 	self->priv->drag_operation = OPER_0;
 	switch (self->priv->operation)
 	{
@@ -2151,6 +2251,7 @@ draw_symbol (LdDiagramSymbol *diagram_symbol, DrawData *data)
 	LdSymbol *symbol;
 	LdRectangle clip_rect;
 	gdouble x, y;
+	gint rotation;
 
 	symbol = resolve_symbol (data->self, diagram_symbol);
 
@@ -2175,12 +2276,25 @@ draw_symbol (LdDiagramSymbol *diagram_symbol, DrawData *data)
 		clip_rect.width, clip_rect.height);
 	cairo_clip (data->cr);
 
-	/* TODO: Rotate the space for other orientations. */
-	g_object_get (diagram_symbol, "x", &x, "y", &y, NULL);
+	g_object_get (diagram_symbol, "x", &x, "y", &y,
+		"rotation", &rotation, NULL);
 	ld_canvas_diagram_to_widget_coords (data->self, x, y, &x, &y);
 	cairo_translate (data->cr, x, y);
 	cairo_scale (data->cr, data->scale, data->scale);
 
+	switch (rotation)
+	{
+	case LD_DIAGRAM_SYMBOL_ROTATION_90:
+		cairo_rotate (data->cr, G_PI * 0.5);
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_180:
+		cairo_rotate (data->cr, G_PI);
+		break;
+	case LD_DIAGRAM_SYMBOL_ROTATION_270:
+		cairo_rotate (data->cr, G_PI * 1.5);
+		break;
+	}
+
 	ld_symbol_draw (symbol, data->cr);
 	cairo_restore (data->cr);
 }
diff --git a/liblogdiag/ld-canvas.h b/liblogdiag/ld-canvas.h
index 9e2d105..3091a34 100644
--- a/liblogdiag/ld-canvas.h
+++ b/liblogdiag/ld-canvas.h
@@ -87,8 +87,6 @@ void ld_canvas_zoom_out (LdCanvas *self);
 
 void ld_canvas_add_object_begin (LdCanvas *self, LdDiagramObject *object);
 
-/* TODO: The rest of the interface. */
-
 
 G_END_DECLS
 
diff --git a/liblogdiag/ld-diagram-symbol.c b/liblogdiag/ld-diagram-symbol.c
index 8307ef4..01c0172 100644
--- a/liblogdiag/ld-diagram-symbol.c
+++ b/liblogdiag/ld-diagram-symbol.c
@@ -23,7 +23,8 @@
 enum
 {
 	PROP_0,
-	PROP_CLASS
+	PROP_CLASS,
+	PROP_ROTATION
 };
 
 static void ld_diagram_symbol_get_property (GObject *object, guint property_id,
@@ -53,6 +54,16 @@ ld_diagram_symbol_class_init (LdDiagramSymbolClass *klass)
 		"The class of this symbol.",
 		"", G_PARAM_READWRITE);
 	g_object_class_install_property (object_class, PROP_CLASS, pspec);
+
+/**
+ * LdDiagramSymbol:rotation:
+ *
+ * Rotation of this symbol.
+ */
+	pspec = g_param_spec_int ("rotation", "Rotation",
+		"Rotation of this symbol.",
+		0, 3, 0, G_PARAM_READWRITE);
+	g_object_class_install_property (object_class, PROP_ROTATION, pspec);
 }
 
 static void
@@ -70,6 +81,7 @@ ld_diagram_symbol_get_property (GObject *object, guint property_id,
 	switch (property_id)
 	{
 	case PROP_CLASS:
+	case PROP_ROTATION:
 		ld_diagram_object_get_data_for_param (self, value, pspec);
 		break;
 	default:
@@ -87,6 +99,7 @@ ld_diagram_symbol_set_property (GObject *object, guint property_id,
 	switch (property_id)
 	{
 	case PROP_CLASS:
+	case PROP_ROTATION:
 		ld_diagram_object_set_data_for_param (self, value, pspec);
 		break;
 	default:
@@ -139,3 +152,33 @@ ld_diagram_symbol_set_class (LdDiagramSymbol *self, const gchar *klass)
 	g_return_if_fail (LD_IS_DIAGRAM_SYMBOL (self));
 	g_object_set (self, "class", klass, NULL);
 }
+
+/**
+ * ld_diagram_symbol_get_rotation:
+ * @self: an #LdDiagramSymbol object.
+ *
+ * Return value: rotation of the symbol.
+ */
+gint
+ld_diagram_symbol_get_rotation (LdDiagramSymbol *self)
+{
+	gint rotation;
+
+	g_return_val_if_fail (LD_IS_DIAGRAM_SYMBOL (self), 0);
+	g_object_get (self, "rotation", &rotation, NULL);
+	return rotation;
+}
+
+/**
+ * ld_diagram_symbol_set_rotation:
+ * @self: an #LdDiagramSymbol object.
+ * @rotation: the rotation.
+ *
+ * Set rotation of the symbol.
+ */
+void
+ld_diagram_symbol_set_rotation (LdDiagramSymbol *self, gint rotation)
+{
+	g_return_if_fail (LD_IS_DIAGRAM_SYMBOL (self));
+	g_object_set (self, "rotation", rotation, NULL);
+}
diff --git a/liblogdiag/ld-diagram-symbol.h b/liblogdiag/ld-diagram-symbol.h
index d96c0f0..d7dfce2 100644
--- a/liblogdiag/ld-diagram-symbol.h
+++ b/liblogdiag/ld-diagram-symbol.h
@@ -50,11 +50,21 @@ struct _LdDiagramSymbolClass
 };
 
 
+enum
+{
+	LD_DIAGRAM_SYMBOL_ROTATION_0,
+	LD_DIAGRAM_SYMBOL_ROTATION_90,
+	LD_DIAGRAM_SYMBOL_ROTATION_180,
+	LD_DIAGRAM_SYMBOL_ROTATION_270
+};
+
 GType ld_diagram_symbol_get_type (void) G_GNUC_CONST;
 
 LdDiagramSymbol *ld_diagram_symbol_new (JsonObject *storage);
 gchar *ld_diagram_symbol_get_class (LdDiagramSymbol *self);
 void ld_diagram_symbol_set_class (LdDiagramSymbol *self, const gchar *klass);
+gint ld_diagram_symbol_get_rotation (LdDiagramSymbol *self);
+void ld_diagram_symbol_set_rotation (LdDiagramSymbol *self, gint rotation);
 
 
 G_END_DECLS
-- 
cgit v1.2.3-70-g09d2