Ejemplo n.º 1
0
static void
modify_motion (ModifyTool     *tool,
               GdkEventMotion *event,
               DDisplay       *ddisp)
{
  Point to;
  Point now, delta, full_delta;
  gboolean auto_scroll, vertical = FALSE;
  ConnectionPoint *connectionpoint = NULL;
  ObjectChange *objchange = NULL;

  ddisplay_untransform_coords(ddisp, event->x, event->y, &to.x, &to.y);

  if (tool->state==STATE_NONE) {
    DiaObject *obj = NULL;
    Handle *handle = NULL;

    diagram_find_closest_handle (ddisp->diagram, &handle, &obj, &to);
    if  (handle && handle->type != HANDLE_NON_MOVABLE
      && handle->id >= HANDLE_RESIZE_NW && handle->id <= HANDLE_RESIZE_SE
      && handle_is_clicked(ddisp, handle, &to)
      && g_list_length (ddisp->diagram->data->selected) == 1)
      ddisplay_set_all_cursor (get_direction_cursor (CURSOR_DIRECTION_0 + handle->id));
    else
      ddisplay_set_all_cursor_name (NULL, "default");
    return; /* Fast path... */
  }
  auto_scroll = ddisplay_autoscroll(ddisp, event->x, event->y);

  if (!modify_move_already(tool, ddisp, &to)) return;

  switch (tool->state) {
  case STATE_MOVE_OBJECT:

    if (tool->orig_pos == NULL) {
      GList *list, *pla;
      int i;
      DiaObject *obj;

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

    if (tool->break_connections)
      diagram_unconnect_selected(ddisp->diagram); /* Pushes UNDO info */

    if (gdk_event_to_dia_ModifierKeys (event->state) & MODIFIER_CONTROL) {
      full_delta = to;
      point_sub(&full_delta, &tool->start_at);
      vertical = (fabs(full_delta.x) < fabs(full_delta.y));
    }

    point_add(&to, &tool->move_compensate);
    snap_to_grid(ddisp, &to.x, &to.y);

    now = tool->object->position;

    delta = to;
    point_sub(&delta, &now);

    if (gdk_event_to_dia_ModifierKeys (event->state) & MODIFIER_CONTROL) {
      /* Up-down or left-right */
      if (vertical) {
       delta.x = tool->start_at.x + tool->move_compensate.x - now.x;
      } else {
       delta.y = tool->start_at.y + tool->move_compensate.y - now.y;
      }
    }

    object_add_updates_list(ddisp->diagram->data->selected, ddisp->diagram);
    objchange = object_list_move_delta(ddisp->diagram->data->selected, &delta);
    if (objchange != NULL) {
      undo_object_change(ddisp->diagram, tool->object, objchange);
    }
    object_add_updates_list(ddisp->diagram->data->selected, ddisp->diagram);

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

    /* Put current mouse position in status bar */
    {
      gchar *postext;
      GtkStatusbar *statusbar = GTK_STATUSBAR (ddisp->modified_status);
      guint context_id = gtk_statusbar_get_context_id (statusbar, "ObjectPos");
      gtk_statusbar_pop (statusbar, context_id);
      postext = g_strdup_printf("%.3f, %.3f - %.3f, %.3f",
			        tool->object->bounding_box.left,
			        tool->object->bounding_box.top,
			        tool->object->bounding_box.right,
			        tool->object->bounding_box.bottom);

      gtk_statusbar_pop (statusbar, context_id);
      gtk_statusbar_push (statusbar, context_id, postext);

      g_free(postext);
    }

    diagram_update_connections_selection(ddisp->diagram);
    diagram_flush(ddisp->diagram);
    break;
  case STATE_MOVE_HANDLE:
    full_delta = to;
    point_sub(&full_delta, &tool->start_at);
    /* make sure resizing is restricted to its parent */

    /* if resize was blocked by parent, that means the resizing was
      outward, thus it won't bother the children so we don't have to
      check the children */
    if (!parent_handle_move_out_check(tool->object, &to))
      parent_handle_move_in_check(tool->object, &to, &tool->start_at);

    if (gdk_event_to_dia_ModifierKeys (event->state) & MODIFIER_CONTROL)
      vertical = (fabs(full_delta.x) < fabs(full_delta.y));

    highlight_reset_all(ddisp->diagram);
    if ((tool->handle->connect_type != HANDLE_NONCONNECTABLE)) {
      /* Move to ConnectionPoint if near: */
      connectionpoint = object_find_connectpoint_display (ddisp,
                                                          &to,
                                                          tool->object, TRUE);
      if (connectionpoint != NULL) {
        DiaHighlightType type;
        to = connectionpoint->pos;
        if (connectionpoint->flags & CP_FLAGS_MAIN) {
          type = DIA_HIGHLIGHT_CONNECTIONPOINT_MAIN;
        } else {
          type = DIA_HIGHLIGHT_CONNECTIONPOINT;
        }
        highlight_object(connectionpoint->object, type, ddisp->diagram);
        ddisplay_set_all_cursor_name (NULL, "crosshair");
      }
    }
    if (connectionpoint == NULL) {
      /* No connectionopoint near, then snap to grid (if enabled) */
      snap_to_grid(ddisp, &to.x, &to.y);
      ddisplay_set_all_cursor_name (NULL, "move");
    }

    if (tool->break_connections) {
      /* break connections to the handle currently selected. */
      if (tool->handle->connected_to!=NULL) {
        Change *change = undo_unconnect (ddisp->diagram,
                                         tool->object,
                                         tool->handle);

        (change->apply)(change, ddisp->diagram);
      }
    }

    if (gdk_event_to_dia_ModifierKeys (event->state) & MODIFIER_CONTROL) {
      /* Up-down or left-right */
      if (vertical) {
       to.x = tool->start_at.x;
      } else {
       to.y = tool->start_at.y;
      }
    }

    if (tool->orig_pos == NULL) {
      tool->orig_pos = g_new(Point, 1);
      *tool->orig_pos = tool->handle->pos;
    }

    /* Put current mouse position in status bar */
    {
      gchar *postext;
      GtkStatusbar *statusbar = GTK_STATUSBAR (ddisp->modified_status);
      guint context_id = gtk_statusbar_get_context_id (statusbar, "ObjectPos");

      if (tool->object) { /* play safe */
        real w = tool->object->bounding_box.right - tool->object->bounding_box.left;
        real h = tool->object->bounding_box.bottom - tool->object->bounding_box.top;
        postext = g_strdup_printf("%.3f, %.3f (%.3fx%.3f)", to.x, to.y, w, h);
      } else {
        postext = g_strdup_printf("%.3f, %.3f", to.x, to.y);
      }

      gtk_statusbar_pop (statusbar, context_id);
      gtk_statusbar_push (statusbar, context_id, postext);

      g_free(postext);
    }

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

    /* Handle undo */
    if (tool->object)
      objchange = tool->object->ops->move_handle(tool->object, tool->handle,
					         &to, connectionpoint,
					         HANDLE_MOVE_USER, 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);

    diagram_update_connections_selection(ddisp->diagram);
    diagram_flush(ddisp->diagram);
    break;
  case STATE_BOX_SELECT:
    tool->end_box = to;

    ddisplay_transform_coords (ddisp,
                               MIN (tool->start_box.x, tool->end_box.x),
                               MIN (tool->start_box.y, tool->end_box.y),
                               &tool->x1, &tool->y1);
    ddisplay_transform_coords (ddisp,
                               MAX (tool->start_box.x, tool->end_box.x),
                               MAX (tool->start_box.y, tool->end_box.y),
                               &tool->x2, &tool->y2);

    dia_interactive_renderer_set_selection (ddisp->renderer,
                                            TRUE,
                                            tool->x1,
                                            tool->y1,
                                            tool->x2 - tool->x1,
                                            tool->y2 - tool->y1);
    ddisplay_flush (ddisp);

    break;
  case STATE_NONE:
    break;
  default:
    message_error("Internal error: Strange state in modify_tool\n");
  }

  tool->last_to = to;
  tool->auto_scrolled = auto_scroll;
}
Ejemplo n.º 2
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);
}