Esempio n. 1
0
/*!
 * \brief Move the list in the given direction.
 *
 * @param objects The objects to move
 * @param dia The diagram owning the objects
 * @param dir The direction to move to
 * @param step The step-width to move
 */
void
object_list_nudge(GList *objects, Diagram *dia, Direction dir, real step)
{
    Point *orig_pos;
    Point *dest_pos;
    guint nobjs, i;
    real inc_x, inc_y;
    GList *list;
    DiaObject *obj;

    if (!objects)
        return;
    g_return_if_fail (step > 0);

    nobjs = g_list_length (objects);
    g_return_if_fail (nobjs > 0);

    dest_pos = g_new(Point, nobjs);
    orig_pos = g_new(Point, nobjs);

    inc_x = DIR_RIGHT == dir ? step : (DIR_LEFT == dir ? -step : 0);
    inc_y = DIR_DOWN == dir ? step : (DIR_UP == dir ? -step : 0);

    /* remeber original positions and calculate destination */
    i = 0;
    list = objects;
    while (list != NULL) {
        obj = (DiaObject *) list->data;

        orig_pos[i] = obj->position;
        dest_pos[i].x = orig_pos[i].x + inc_x;
        dest_pos[i].y = orig_pos[i].y + inc_y;

        obj->ops->move(obj, &dest_pos[i]);
        ++i;
        list = g_list_next(list);
    }
    /* if anything is connected not anymore */
    diagram_unconnect_selected(dia);
    undo_move_objects(dia, orig_pos, dest_pos, g_list_copy(objects));
}
Esempio n. 2
0
static void
modify_button_release(ModifyTool *tool, GdkEventButton *event,
		      DDisplay *ddisp)
{
  Point *dest_pos, to;
  GList *list;
  int i;
  ObjectChange *objchange;

  tool->break_connections = FALSE;
  ddisplay_set_all_cursor(default_cursor);

  /* remove position from status bar */
  {
    GtkStatusbar *statusbar = GTK_STATUSBAR (ddisp->modified_status);
    guint context_id = gtk_statusbar_get_context_id (statusbar, "ObjectPos");
    gtk_statusbar_pop (statusbar, context_id);
  }
  switch (tool->state) {
  case STATE_MOVE_OBJECT:
    /* Return to normal state */
    gdk_pointer_ungrab (event->time);

    ddisplay_untransform_coords(ddisp, event->x, event->y, &to.x, &to.y);
    if (!modify_move_already(tool, ddisp, &to)) {
      tool->orig_pos = NULL;
      tool->state = STATE_NONE;
      return;
    }

    diagram_update_connections_selection(ddisp->diagram);

    if (tool->orig_pos != NULL) {
      /* consider the non-selected children affected */
      list = parent_list_affected(ddisp->diagram->data->selected);
      dest_pos = g_new(Point, g_list_length(list));
      i=0;
      while (list != NULL) {
	DiaObject *obj = (DiaObject *)  list->data;
	dest_pos[i] = obj->position;
	list = g_list_next(list); i++;
      }

      undo_move_objects(ddisp->diagram, tool->orig_pos, dest_pos,
			parent_list_affected(ddisp->diagram->data->selected));
    }

    ddisplay_connect_selected(ddisp); /* pushes UNDO info */
    diagram_update_extents(ddisp->diagram);
    diagram_modified(ddisp->diagram);
    diagram_flush(ddisp->diagram);

    undo_set_transactionpoint(ddisp->diagram->undo);

    tool->orig_pos = NULL;
    tool->state = STATE_NONE;
    break;
  case STATE_MOVE_HANDLE:
    gdk_pointer_ungrab (event->time);
    tool->state = STATE_NONE;

    if (tool->orig_pos != NULL) {
      undo_move_handle(ddisp->diagram, tool->handle, tool->object,
		       *tool->orig_pos, tool->last_to, gdk_event_to_dia_ModifierKeys(event->state));
    }

    /* Final move: */
    object_add_updates(tool->object, ddisp->diagram);
    objchange = tool->object->ops->move_handle(tool->object, tool->handle,
					       &tool->last_to, NULL,
					       HANDLE_MOVE_USER_FINAL,gdk_event_to_dia_ModifierKeys(event->state));
    if (objchange != NULL) {
      undo_object_change(ddisp->diagram, tool->object, objchange);
    }

    object_add_updates(tool->object, ddisp->diagram);

    /* Connect if possible: */
    if (tool->handle->connect_type != HANDLE_NONCONNECTABLE) {
      object_connect_display(ddisp, tool->object, tool->handle, TRUE); /* pushes UNDO info */
      diagram_update_connections_selection(ddisp->diagram);
    }

    highlight_reset_all(ddisp->diagram);
    diagram_flush(ddisp->diagram);

    diagram_modified(ddisp->diagram);
    diagram_update_extents(ddisp->diagram);

    undo_set_transactionpoint(ddisp->diagram->undo);

    if (tool->orig_pos != NULL) {
      g_free(tool->orig_pos);
      tool->orig_pos = NULL;
    }

    break;
  case STATE_BOX_SELECT:

    gdk_pointer_ungrab (event->time);
    /* Remove last box: */
    dia_interactive_renderer_set_selection (ddisp->renderer,
                                            FALSE, 0, 0, 0, 0);

    {
      GList *list, *list_to_free;

      list = list_to_free = find_selected_objects(ddisp, tool);

      if (selection_style == SELECT_REPLACE &&
          !(event->state & GDK_SHIFT_MASK)) {
        /* Not Multi-select => Remove all selected */
        diagram_remove_all_selected(ddisp->diagram, TRUE);
      }

      if (selection_style == SELECT_INTERSECTION) {
        GList *intersection = NULL;

        while (list != NULL) {
          DiaObject *obj = (DiaObject *)list->data;

          if (diagram_is_selected(ddisp->diagram, obj)) {
            intersection = g_list_append(intersection, obj);
          }

          list = g_list_next(list);
        }
        list = intersection;
        diagram_remove_all_selected(ddisp->diagram, TRUE);
        while (list != NULL) {
          DiaObject *obj = (DiaObject *)list->data;

          diagram_select(ddisp->diagram, obj);

          list = g_list_next(list);
        }
        g_list_free(intersection);
      } else {
        while (list != NULL) {
          DiaObject *obj = (DiaObject *)list->data;

          if (selection_style == SELECT_REMOVE) {
            if (diagram_is_selected(ddisp->diagram, obj))
              diagram_unselect_object(ddisp->diagram, obj);
          } else if (selection_style == SELECT_INVERT) {
            if (diagram_is_selected(ddisp->diagram, obj))
              diagram_unselect_object(ddisp->diagram, obj);
            else
              diagram_select(ddisp->diagram, obj);
          } else {
            if (!diagram_is_selected(ddisp->diagram, obj))
              diagram_select(ddisp->diagram, obj);
          }

          list = g_list_next(list);
        }
      }

      g_list_free(list_to_free);

    }

    ddisplay_do_update_menu_sensitivity(ddisp);
    ddisplay_flush(ddisp);

    tool->state = STATE_NONE;
    break;
  case STATE_NONE:
    break;
  default:
    message_error("Internal error: Strange state in modify_tool\n");

  }
}
Esempio n. 3
0
/*!
 * \brief Align objects by moving then horizontally
 *
 * For each node in objects align them horizontally. The connections (edges) will follow.
 *
 * @param objects  selection of objects to be considered
 * @param dia      the diagram owning the objects (and holding undo information)
 * @param align    the alignment algorithm
 */
void
object_list_align_h(GList *objects, Diagram *dia, int align)
{
    GList *list;
    Point *orig_pos;
    Point *dest_pos;
    real x_pos = 0;
    DiaObject *obj;
    Point pos;
    real left, right, freespc = 0;
    int nobjs;
    int i;
    GList *unconnected = NULL;

    filter_connected (objects, 1, NULL, &unconnected);
    objects = unconnected;
    if (objects==NULL)
        return;

    obj = (DiaObject *) objects->data; /*  First object */

    left = obj->bounding_box.left;
    right = obj->bounding_box.right;
    freespc = right - left;

    nobjs = 1;
    list = objects->next;
    while (list != NULL) {
        obj = (DiaObject *) list->data;

        if (obj->bounding_box.left < left)
            left = obj->bounding_box.left;
        if (obj->bounding_box.right > right)
            right = obj->bounding_box.right;

        freespc += obj->bounding_box.right - obj->bounding_box.left;
        nobjs++;

        list = g_list_next(list);
    }

    /*
     * These alignments can alter the order of elements, so we need
     * to sort them out by position.
     */
    if (align == DIA_ALIGN_EQUAL || align == DIA_ALIGN_ADJACENT) {
        DiaObject **object_array = (DiaObject **)g_malloc(sizeof(DiaObject*)*nobjs);
        int i = 0;

        list = objects;
        while (list != NULL) {
            obj = (DiaObject *) list->data;
            object_array[i] = obj;
            i++;
            list = g_list_next(list);
        }
        qsort(object_array, nobjs, sizeof(DiaObject*), object_list_sort_horizontal);
        list = NULL;
        for (i = 0; i < nobjs; i++) {
            list = g_list_append(list, object_array[i]);
        }
        g_assert (objects == unconnected);
        g_list_free (unconnected);
        objects = unconnected = list;
        g_free(object_array);
    }

    switch (align) {
    case DIA_ALIGN_LEFT:
        x_pos = left;
        break;
    case DIA_ALIGN_CENTER:
        x_pos = (left + right)/2.0;
        break;
    case DIA_ALIGN_RIGHT:
        x_pos = right;
        break;
    case DIA_ALIGN_POSITION:
        x_pos = (left + right)/2.0;
        break;
    case DIA_ALIGN_EQUAL:
        freespc = (right - left - freespc)/(double)(nobjs - 1);
        x_pos = left;
        break;
    case DIA_ALIGN_ADJACENT:
        x_pos = left;
        break;
    default:
        message_warning("Wrong argument to object_list_align_h()\n");
    }

    dest_pos = g_new(Point, nobjs);
    orig_pos = g_new(Point, nobjs);

    i = 0;
    list = objects;
    while (list != NULL) {
        obj = (DiaObject *) list->data;

        switch (align) {
        case DIA_ALIGN_LEFT:
            pos.x = x_pos + obj->position.x - obj->bounding_box.left;
            break;
        case DIA_ALIGN_CENTER:
            pos.x = x_pos + obj->position.x - (obj->bounding_box.left + obj->bounding_box.right)/2.0;
            break;
        case DIA_ALIGN_RIGHT:
            pos.x = x_pos - (obj->bounding_box.right - obj->position.x);
            break;
        case DIA_ALIGN_POSITION:
            pos.x = x_pos;
            break;
        case DIA_ALIGN_EQUAL:
            pos.x = x_pos + obj->position.x - obj->bounding_box.left;
            x_pos += obj->bounding_box.right - obj->bounding_box.left + freespc;
            break;
        case DIA_ALIGN_ADJACENT:
            pos.x = x_pos + obj->position.x - obj->bounding_box.left;
            x_pos += obj->bounding_box.right - obj->bounding_box.left;
            break;
        }

        pos.y = obj->position.y;

        orig_pos[i] = obj->position;
        dest_pos[i] = pos;

        obj->ops->move(obj, &pos);

        i++;
        list = g_list_next(list);
    }

    undo_move_objects(dia, orig_pos, dest_pos, g_list_copy(objects));
    g_list_free (unconnected);
}
Esempio n. 4
0
/*!
 * \brief Align objects at their connected points
 *
 * The result of the algorithm depends on the order of objects
 * in the list. The list is typically coming from the selection.
 * That order depends on the kind of selection performed.
 *  - selection by rubberband gives objects in reverse order of
 *    the the original layer order as of this writing
 *  - Select/Transitive lets the order follow the connection order,
 *    but still reversed due data_select() prepending
 *  - Step-wise manual selection would also be in reverse order
 * So it appears to be a good idea to reverse the processing order
 * In this function to minimize surpise.
 *
 * The result also currently depends on the direction of the connections.
 * When aligning two objects the one connected with HANDLE_MOVE_ENDPOINT
 * will be moved. This might be contradictory to the selection order.
 *
 * @param objects  selection of objects to be considered
 * @param dia      the diagram owning the objects (and holding undo information)
 * @param align    unused
 */
void
object_list_align_connected (GList *objects, Diagram *dia, int align)
{
    GList *list;
    Point *orig_pos;
    Point *dest_pos;
    DiaObject *obj, *o2;
    int i, nobjs;
    GList *connected = NULL;
    GList *to_be_moved = NULL;
    GList *movelist = NULL;

    /* find all elements to be moved directly */
    filter_connected (objects, 2, &connected, &to_be_moved);
    dia_log_message ("Moves %d - Connections %d\n", g_list_length (to_be_moved), g_list_length (connected));
    /* 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 = g_list_reverse (connected);
    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;
            /* swap alignment direction if we are working backwards by the selection order */
            if (g_list_index (to_be_moved, obj) < g_list_index (to_be_moved, o2)) {
                DiaObject *otmp = o2;
                ConnectionPoint *cptmp = cpe;
                o2 = obj;
                obj = otmp;
                cpe = cps;
                cps = cptmp;
            }
            if (   !g_list_find (movelist, o2)
                    && g_list_find(to_be_moved, o2) && g_list_find(to_be_moved, obj)) {
                Point delta = {0, 0};
                /* If we haven't moved it yet, check if we want to */
                int hweight = 0;
                int vweight = 0;
                if (cps->directions == DIR_NORTH || cps->directions == DIR_SOUTH)
                    ++vweight;
                else if (cps->directions == DIR_EAST || cps->directions == DIR_WEST)
                    ++hweight;
                if (cpe->directions == DIR_NORTH || cpe->directions == DIR_SOUTH)
                    ++vweight;
                else if (cpe->directions == DIR_EAST || cpe->directions == DIR_WEST)
                    ++hweight;

                /* One clear directions is required to move at all */
                if (vweight > hweight) {
                    /* horizontal move */
                    delta.x = cps->pos.x - cpe->pos.x;
                } else if (hweight > vweight) {
                    /* 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);
#if 0
                    o2->ops->move (o2, &pos);
#else
                    {
                        GList *move_list = g_list_append (NULL, o2);
                        object_list_move_delta (move_list, &delta);
                        g_list_free (move_list);
                    }
#endif
                    diagram_update_connections_object (dia, o2, TRUE);
                    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 (connected);
}
Esempio n. 5
0
/*!
 * \brief Align objects by moving them vertically
 *
 * For each node in objects align them vertically. The connections (edges) will follow.
 *
 * @param objects  selection of objects to be considered
 * @param dia      the diagram owning the objects (and holding undo information)
 * @param align    the alignment algorithm
 */
void
object_list_align_v(GList *objects, Diagram *dia, int align)
{
    GList *list;
    Point *orig_pos;
    Point *dest_pos;
    real y_pos = 0;
    DiaObject *obj;
    Point pos;
    real top, bottom, freespc;
    int nobjs;
    int i;
    GList *unconnected = NULL;

    filter_connected (objects, 1, NULL, &unconnected);
    objects = unconnected;
    if (objects==NULL)
        return;

    obj = (DiaObject *) objects->data; /*  First object */

    top = obj->bounding_box.top;
    bottom = obj->bounding_box.bottom;
    freespc = bottom - top;

    nobjs = 1;
    list = objects->next;
    while (list != NULL) {
        obj = (DiaObject *) list->data;

        if (obj->bounding_box.top < top)
            top = obj->bounding_box.top;
        if (obj->bounding_box.bottom > bottom)
            bottom = obj->bounding_box.bottom;

        freespc += obj->bounding_box.bottom - obj->bounding_box.top;
        nobjs++;

        list = g_list_next(list);
    }

    /*
     * These alignments can alter the order of elements, so we need
     * to sort them out by position.
     */
    if (align == DIA_ALIGN_EQUAL || align == DIA_ALIGN_ADJACENT) {
        DiaObject **object_array = (DiaObject **)g_malloc(sizeof(DiaObject*)*nobjs);
        int i = 0;

        list = objects;
        while (list != NULL) {
            obj = (DiaObject *) list->data;
            object_array[i] = obj;
            i++;
            list = g_list_next(list);
        }
        qsort(object_array, nobjs, sizeof(DiaObject*), object_list_sort_vertical);
        list = NULL;
        for (i = 0; i < nobjs; i++) {
            list = g_list_append(list, object_array[i]);
        }
        g_assert (objects == unconnected);
        g_list_free (unconnected);
        objects = unconnected = list;
        g_free(object_array);
    }

    switch (align) {
    case DIA_ALIGN_TOP: /* TOP */
        y_pos = top;
        break;
    case DIA_ALIGN_CENTER: /* CENTER */
        y_pos = (top + bottom)/2.0;
        break;
    case DIA_ALIGN_BOTTOM: /* BOTTOM */
        y_pos = bottom;
        break;
    case DIA_ALIGN_POSITION: /* OBJECT POSITION */
        y_pos = (top + bottom)/2.0;
        break;
    case DIA_ALIGN_EQUAL: /* EQUAL DISTANCE */
        freespc = (bottom - top - freespc)/(double)(nobjs - 1);
        y_pos = top;
        break;
    case DIA_ALIGN_ADJACENT: /* ADJACENT */
        y_pos = top;
        break;
    default:
        message_warning("Wrong argument to object_list_align_v()\n");
    }

    dest_pos = g_new(Point, nobjs);
    orig_pos = g_new(Point, nobjs);

    i = 0;
    list = objects;
    while (list != NULL) {
        obj = (DiaObject *) list->data;

        pos.x = obj->position.x;

        switch (align) {
        case DIA_ALIGN_TOP: /* TOP */
            pos.y = y_pos + obj->position.y - obj->bounding_box.top;
            break;
        case DIA_ALIGN_CENTER: /* CENTER */
            pos.y = y_pos + obj->position.y - (obj->bounding_box.top + obj->bounding_box.bottom)/2.0;
            break;
        case DIA_ALIGN_BOTTOM: /* BOTTOM */
            pos.y = y_pos - (obj->bounding_box.bottom - obj->position.y);
            break;
        case DIA_ALIGN_POSITION: /* OBJECT POSITION */
            pos.y = y_pos;
            break;
        case DIA_ALIGN_EQUAL: /* EQUAL DISTANCE */
            pos.y = y_pos + obj->position.y - obj->bounding_box.top;
            y_pos += obj->bounding_box.bottom - obj->bounding_box.top + freespc;
            break;
        case DIA_ALIGN_ADJACENT: /* ADJACENT */
            pos.y = y_pos + obj->position.y - obj->bounding_box.top;
            y_pos += obj->bounding_box.bottom - obj->bounding_box.top;
            break;
        }

        pos.x = obj->position.x;

        orig_pos[i] = obj->position;
        dest_pos[i] = pos;

        obj->ops->move(obj, &pos);

        i++;
        list = g_list_next(list);
    }

    undo_move_objects(dia, orig_pos, dest_pos, g_list_copy(objects));
    g_list_free (unconnected);
}