Exemple #1
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");

  }
}
Exemple #2
0
static void
create_object_button_release(CreateObjectTool *tool, GdkEventButton *event,
			     DDisplay *ddisp)
{
  GList *list = NULL;
  DiaObject *obj = tool->obj;
  gboolean reset;

  GList *parent_candidates;

  g_return_if_fail (obj != NULL);
  if (!obj) /* not sure if this isn't enough */
    return; /* could be a legal invariant */

  if (tool->moving) {
    gdk_pointer_ungrab (event->time);

    object_add_updates(tool->obj, ddisp->diagram);
    tool->obj->ops->move_handle(tool->obj, tool->handle, &tool->last_to,
				NULL, HANDLE_MOVE_CREATE_FINAL, 0);
    object_add_updates(tool->obj, ddisp->diagram);

  }

  parent_candidates = 
    layer_find_objects_containing_rectangle(obj->parent_layer, 
					    &obj->bounding_box);

  /* whole object must be within another object to parent it */
  for (; parent_candidates != NULL; parent_candidates = g_list_next(parent_candidates)) {
    DiaObject *parent_obj = (DiaObject *) parent_candidates->data;
    if (obj != parent_obj 
	&& object_within_parent(obj, parent_obj)) {
      Change *change = undo_parenting(ddisp->diagram, parent_obj, obj, TRUE);
      (change->apply)(change, ddisp->diagram);
      break;
    /*
    obj->parent = parent_obj;
    parent_obj->children = g_list_append(parent_obj->children, obj);
    */
    }
  }
  g_list_free(parent_candidates);

  list = g_list_prepend(list, tool->obj);

  undo_insert_objects(ddisp->diagram, list, 1); 

  if (tool->moving) {
    if (tool->handle->connect_type != HANDLE_NONCONNECTABLE) {
      object_connect_display(ddisp, tool->obj, tool->handle, TRUE);
      diagram_update_connections_selection(ddisp->diagram);
      diagram_flush(ddisp->diagram);
    }
    tool->moving = FALSE;
    tool->handle = NULL;
    tool->obj = NULL;    
  }
  
  {
    /* 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);
  }
  
  highlight_reset_all(ddisp->diagram);
  reset = prefs.reset_tools_after_create != tool->invert_persistence;
  /* kind of backward: first starting editing to see if it is possible at all, than GUI reflection */
  if (textedit_activate_object(ddisp, obj, NULL) && reset) {
    gtk_action_activate (menus_get_action ("ToolsTextedit"));
    reset = FALSE; /* don't switch off textedit below */
  }
  diagram_update_extents(ddisp->diagram);
  diagram_modified(ddisp->diagram);

  undo_set_transactionpoint(ddisp->diagram->undo);
  
  if (reset)
      tool_reset();
  ddisplay_set_all_cursor(default_cursor);
  ddisplay_do_update_menu_sensitivity(ddisp);
}
Exemple #3
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;
}
Exemple #4
0
/*!
 * \brief Calback function invoking layout algorithms from Dia's menu
 * \ingroup LayoutPlugin
 */
static ObjectChange *
layout_callback (DiagramData *data,
                 const gchar *filename,
                 guint flags, /* further additions */
                 void *user_data,
		 GraphCreateFunc func)
{
  ObjectChange *changes = NULL;
  GList *nodes = NULL, *edges = NULL, *list;
  const char *algorithm = (const char*)user_data;

  /* from the selection create two lists */
  list = data_get_sorted_selected (data);
  while (list) {
    DiaObject *o = (DiaObject *)list->data;
    if (!maybe_edge (o))
      nodes = g_list_append (nodes, o);
    //FIXME: neither 1 nor num_handles-1 is guaranteed to be the second connection
    // it entirely depends on the objects implementation
    else if (   o->num_handles > 1 && o->handles[0]->connected_to 
             && (o->handles[1]->connected_to || o->handles[o->num_handles-1]->connected_to))
      edges = g_list_append (edges, o);
    list = g_list_next(list);
  }
  if (g_list_length (edges) < 1 || g_list_length (nodes) < 2) {
    message_warning (_("Please select edges and nodes to layout."));
  } else {
    IGraph *g = func ? func () : NULL;

    if (!g)
      message_error (_("Graph creation failed"));
    else {
      std::vector<double> coords;

      /* transfer nodes and edges */
      for (list = nodes; list != NULL; list = g_list_next(list)) {
        DiaObject *o = (DiaObject *)list->data;
        const Rectangle *bbox = dia_object_get_bounding_box (o);
        g->AddNode (bbox->left, bbox->top, bbox->right, bbox->bottom);
      }
      for (list = edges; list != NULL; list = g_list_next(list)) {
        DiaObject *o = (DiaObject *)list->data;
	DiaObject *src = o->handles[0]->connected_to->object;
	// see above: there is no guarantee ...
	DiaObject *dst = o->handles[1]->connected_to ?
	  o->handles[1]->connected_to->object : o->handles[o->num_handles-1]->connected_to->object;

	if (_obj_get_bends (o, coords))
          g->AddEdge (g_list_index (nodes, src), g_list_index (nodes, dst), &coords[0], coords.size());
	else
          g->AddEdge (g_list_index (nodes, src), g_list_index (nodes, dst), NULL, 0);
      }
      IGraph::eResult res;
      if ((res = g->Layout (algorithm)) != IGraph::SUCCESS) {
	const char *sErr;
	switch (res) {
	case IGraph::NO_MODULE : sErr = _("No such module."); break;
	case IGraph::OUT_OF_MEMORY : sErr = _("Out of memory."); break;
	case IGraph::NO_TREE: sErr = _("Not a tree."); break;
	case IGraph::NO_FOREST: sErr = _("Not a forest."); break;
	case IGraph::FAILED_ALGORITHM: sErr = _("Failed algorithm."); break;
	case IGraph::FAILED_PRECONDITION: sErr = _("Failed precondition."); break;
	case IGraph::CRASHED : sErr = _("OGDF crashed."); break;
	default : sErr = _("Unknown reason"); break;
	}
        message_warning (_("Layout '%s' failed.\n%s"), (const char*)user_data, sErr);
      } else {
        changes = change_list_create ();
	/* transfer back information */
	int n;
	for (n = 0, list = nodes; list != NULL; list = g_list_next (list), ++n) {
	  Point pt;
	  if (g->GetNodePosition (n, &pt.x, &pt.y)) {
	    DiaObject *o = (DiaObject *)list->data;
	    GPtrArray *props = g_ptr_array_new ();
	    
	    //FIXME: can't use "obj_pos", it is not read in usual update_data impementations
	    // "elem_corner" will only work for Element derived classes, but that covers most
	    // of the cases here ...
	    prop_list_add_point (props, "elem_corner", &pt);
	    change_list_add (changes, object_apply_props (o, props));
	  }
	}
	// first update to reuse the connected points
	diagram_update_connections_selection(DIA_DIAGRAM (data));
	/* use edge bends, if any */
	int e;
	for (e = 0, list = edges; list != NULL; list = g_list_next (list), ++e) {
          DiaObject *o = (DiaObject *)list->data;
	  // number of bends / 2 is the number of points
	  int n = g->GetEdgeBends (e, NULL, 0);
	  if (n >= 0) { // with 0 it is just a reset of the exisiting line
	    try {
	      coords.resize (n);
	    } catch (std::bad_alloc& ex) {
	      g_warning ("%s", ex.what());
	      continue;
	    }
	    g->GetEdgeBends (e, &coords[0], n);
	    change_list_add (changes, _obj_set_bends (o, coords));
	  }
	}
	/* update view */
	diagram_update_connections_selection(DIA_DIAGRAM (data));
      }
      g->Release ();
    }
  }
  g_list_free (nodes);
  g_list_free (edges);

  return changes;
}