[dia] Align Connected: aligning at connected points



commit f705f2d7fb6e65b1b053a72714bc0450d020fcfc
Author: Hans Breuer <hans breuer org>
Date:   Sun Aug 15 20:38:33 2010 +0200

    Align Connected: aligning at connected points
    
    Aligning objects usually works on the objects bounding boxes.
    To get straight lines connecting multiple objects in the same
    direction it might be useful to align the connected points
    instead. This will (slightly) move the objects - while staying
    connected - to have the connection points on a straight line.
    
    Currently implemented are horizontal and vertical alignment
    based on the information given by the used connection points.
    (Following commits will fix some of this info.)
    
    move the objects

 app/commands.c      |   20 +++++++++
 app/commands.h      |    1 +
 app/menus.c         |    1 +
 app/object_ops.c    |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 app/object_ops.h    |    1 +
 data/display-ui.xml |    1 +
 data/popup-ui.xml   |    1 +
 7 files changed, 139 insertions(+), 2 deletions(-)
---
diff --git a/app/commands.c b/app/commands.c
index 17b20e9..04e5e34 100644
--- a/app/commands.c
+++ b/app/commands.c
@@ -1241,6 +1241,26 @@ objects_align_v_callback (GtkAction *action)
   undo_set_transactionpoint(dia->undo);
 }
 
+void
+objects_align_connected_callback (GtkAction *action)
+{
+  Diagram *dia;
+  GList *objects;
+
+  dia = ddisplay_active_diagram();
+  if (!dia) return;
+  objects = dia->data->selected;
+
+  object_add_updates_list(objects, dia);
+  object_list_align_connected(objects, dia, 0);
+  diagram_update_connections_selection(dia);
+  object_add_updates_list(objects, dia);
+  diagram_modified(dia);
+  diagram_flush(dia);
+
+  undo_set_transactionpoint(dia->undo);
+}
+
 /*! Open a file and show it in a new display */
 void
 dia_file_open (const gchar *filename,
diff --git a/app/commands.h b/app/commands.h
index a770e1a..c72dded 100644
--- a/app/commands.h
+++ b/app/commands.h
@@ -87,6 +87,7 @@ void objects_group_callback             (GtkAction *action);
 void objects_ungroup_callback           (GtkAction *action);
 void objects_align_h_callback           (GtkAction *action);
 void objects_align_v_callback           (GtkAction *action);
+void objects_align_connected_callback   (GtkAction *action);
 
 void dialogs_properties_callback (GtkAction *action);
 void dialogs_layers_callback     (GtkAction *action);
diff --git a/app/menus.c b/app/menus.c
index f89de77..21fc418 100644
--- a/app/menus.c
+++ b/app/menus.c
@@ -191,6 +191,7 @@ static const GtkActionEntry display_entries[] =
       { "ObjectsAlignSpreadoutvertically", NULL, N_("Spread Out Vertically"), "<alt><shift>V", NULL, G_CALLBACK (objects_align_v_callback) },
       { "ObjectsAlignAdjacent", NULL, N_("Adjacent"), "<alt><shift>A", NULL, G_CALLBACK (objects_align_h_callback) },
       { "ObjectsAlignStacked", NULL, N_("Stacked"), "<alt><shift>S", NULL, G_CALLBACK (objects_align_v_callback) },
+      { "ObjectsAlignConnected", NULL, N_("Connected"), "<alt><shift>O", NULL, G_CALLBACK (objects_align_connected_callback) },
 
       { "ObjectsProperties", GTK_STOCK_PROPERTIES, NULL, "<alt>Return", NULL, G_CALLBACK (dialogs_properties_callback) },
 
diff --git a/app/object_ops.c b/app/object_ops.c
index 0096408..47fb76f 100644
--- a/app/object_ops.c
+++ b/app/object_ops.c
@@ -168,7 +168,8 @@ object_list_corner(GList *list)
 }
 
 static int
-object_list_sort_vertical(const void *o1, const void *o2) {
+object_list_sort_vertical(const void *o1, const void *o2)
+{
     DiaObject *obj1 = *(DiaObject **)o1;
     DiaObject *obj2 = *(DiaObject **)o2;
 
@@ -318,7 +319,8 @@ object_list_align_v(GList *objects, Diagram *dia, int align)
 
 
 static int
-object_list_sort_horizontal(const void *o1, const void *o2) {
+object_list_sort_horizontal(const void *o1, const void *o2) 
+{
   DiaObject *obj1 = *(DiaObject **)o1;
   DiaObject *obj2 = *(DiaObject **)o2;
 
@@ -464,6 +466,116 @@ object_list_align_h(GList *objects, Diagram *dia, int align)
     g_list_free(objects);
 }
 
+/*! Align objects at their connected points */
+void
+object_list_align_connected (GList *objects, Diagram *dia, int align)
+{
+  GList *list;
+  GList *connected;
+  Point *orig_pos;
+  Point *dest_pos;
+  DiaObject *obj, *o2;
+  int i, nobjs;
+  GList *to_be_moved = NULL;
+  GList *movelist = NULL;
+  GList *connections = NULL;
+
+  /* find all elements to be moved directly */
+  list = objects;
+  while (list != NULL) {
+    obj = list->data;
+    for (i = 0; i < obj->num_connections; ++i) {
+      ConnectionPoint *cp = obj->connections[i];
+      connected = cp->connected;
+      /* first of all remember the objects connected to anything */
+      if (connected && !g_list_find (to_be_moved, obj))
+        to_be_moved = g_list_append (to_be_moved, obj);
+      /* also list all the connection objects - our todo list */
+      while (connected != NULL) {
+        o2 = connected->data;
+        if (!g_list_find (connections, o2))
+          connections = g_list_append (connections, o2);
+        connected = g_list_next (connected);
+      }
+    }
+    list = g_list_next (list);
+  }
+  dia_log_message ("Moves %d - Connections %d\n", g_list_length (to_be_moved), g_list_length (connections));
+  /* for every connection check:
+   * - "matching" directions of both object connection points (this also gives
+   *    the direction of the move of the second object)
+   * - 
+   * - move every object only once
+   */
+  nobjs = g_list_length (to_be_moved);
+  orig_pos = g_new (Point, nobjs);
+  dest_pos = g_new (Point, nobjs);
+
+  list = connections;
+  while (list != NULL) {
+    DiaObject *con = list->data;
+    Handle *h1 = NULL, *h2 = NULL;
+
+    g_assert (con->num_handles >= 2);
+    for (i = 0; i < con->num_handles; ++i) {
+      if (con->handles[i]->id == HANDLE_MOVE_STARTPOINT)
+        h1 = con->handles[i];
+      else if (con->handles[i]->id == HANDLE_MOVE_ENDPOINT)
+        h2 = con->handles[i];
+    }
+    /* should this be an assert? */
+    if (h1 && h2 && h1->connected_to && h2->connected_to) {
+      ConnectionPoint *cps = h1->connected_to;
+      ConnectionPoint *cpe = h2->connected_to;
+
+      obj = cps->object;
+      o2 = cpe->object;
+      if (g_list_find(to_be_moved, o2) && !g_list_find (movelist, o2)) {
+        Point delta = {0, 0};
+        /* if we haven't moved it yet, check if we want to */
+        if (   (cps->directions == DIR_NORTH && cpe->directions == DIR_SOUTH)
+            || (cps->directions == DIR_SOUTH && cpe->directions == DIR_NORTH)) {
+          /* horizontal move */
+          delta.x = cps->pos.x - cpe->pos.x;
+        } else if (   (cps->directions == DIR_EAST && cpe->directions == DIR_WEST)
+                   || (cps->directions == DIR_WEST && cpe->directions == DIR_EAST)) {
+          /* vertical move */
+          delta.y = cps->pos.y - cpe->pos.y;
+        } else {
+          /* would need more context */
+          char dirs[] = "NESW";
+          int j;
+          for (j = 0; j < 4; ++j) if (cps->directions & (1<<j)) g_print ("%c", dirs[j]);
+          g_print ("(%s) -> ", obj->type->name);
+          for (j = 0; j < 4; ++j) if (cpe->directions & (1<<j)) g_print ("%c", dirs[j]);
+          g_print ("(%s)\n", o2->type->name);
+        }
+        if (delta.x != 0.0 || delta.y != 0) {
+          Point pos = o2->position;
+
+          point_add (&pos, &delta);
+
+          i = g_list_length (movelist);
+          orig_pos[i] = o2->position;
+          dest_pos[i] = pos;
+
+          dia_log_message ("Move '%s' by %g,%g\n", o2->type->name, delta.x, delta.y);
+          o2->ops->move (o2, &pos);
+          diagram_update_connections_object (dia, o2, FALSE);
+          movelist = g_list_append (movelist, o2);
+        }
+      }
+    }
+    
+    list = g_list_next (list);
+  }
+
+  /* eating all the passed in parameters */
+  undo_move_objects (dia, orig_pos, dest_pos, movelist);
+  g_list_free (to_be_moved);
+  g_list_free (connections);
+}
+
 /** Move the list in the given direction.
  *
  * @param objects The objects to move
diff --git a/app/object_ops.h b/app/object_ops.h
index d89fe23..93c7d6b 100644
--- a/app/object_ops.h
+++ b/app/object_ops.h
@@ -46,6 +46,7 @@ void object_connect_display(DDisplay *ddisp, DiaObject *obj,
 Point object_list_corner(GList *list);
 void object_list_align_h(GList *objects, Diagram *dia, int align);
 void object_list_align_v(GList *objects, Diagram *dia, int align);
+void object_list_align_connected (GList *objects, Diagram *dia, int align);
 
 typedef enum {
   DIR_UP = 1,
diff --git a/data/display-ui.xml b/data/display-ui.xml
index 79439e6..2cd44aa 100644
--- a/data/display-ui.xml
+++ b/data/display-ui.xml
@@ -107,6 +107,7 @@
 				<menuitem name="ObjectsAlignSpreadoutvertically" action="ObjectsAlignSpreadoutvertically" />
 				<menuitem name="ObjectsAlignAdjacent" action="ObjectsAlignAdjacent" />
 				<menuitem name="ObjectsAlignStacked" action="ObjectsAlignStacked" />
+				<menuitem name="ObjectsAlignConnected" action="ObjectsAlignConnected" />
 			</menu>
 			<separator name="ObjectsSep4" />
 			<menuitem name="ObjectsProperties" action="ObjectsProperties" />
diff --git a/data/popup-ui.xml b/data/popup-ui.xml
index 7e478f5..263e08d 100644
--- a/data/popup-ui.xml
+++ b/data/popup-ui.xml
@@ -104,6 +104,7 @@
 				<menuitem name="ObjectsAlignSpreadoutvertically" action="ObjectsAlignSpreadoutvertically" />
 				<menuitem name="ObjectsAlignAdjacent" action="ObjectsAlignAdjacent" />
 				<menuitem name="ObjectsAlignStacked" action="ObjectsAlignStacked" />
+				<menuitem name="ObjectsAlignConnected" action="ObjectsAlignConnected" />
 			</menu>
 			<separator name="ObjectsSep4" />
 			<menuitem name="ObjectsProperties" action="ObjectsProperties" />



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]