Esempio n. 1
0
/*!
 * Toggle a boolean property including change management
 */
ObjectChange *
object_toggle_prop (DiaObject *obj, const char *pname, gboolean val)
{
  Property *prop = make_new_prop (pname, PROP_TYPE_BOOL, 0);
  GPtrArray *plist = prop_list_from_single (prop);
  
  ((BoolProperty *)prop)->bool_data = val;
  return object_apply_props (obj, plist);
}
Esempio n. 2
0
/*!
 * \brief Modification of the objects 'pattern' property
 *
 * @param object object to modify
 * @param pattern the pattern to set
 * @return an object change or NULL
 *
 * If the object does not have a pattern property nothing
 * happens. If there is a pattern property and the passed
 * in pattern is identical an empty change is returned.
 *
 * \memberof _DiaObject
 * \ingroup StdProps
 */
ObjectChange *
dia_object_set_pattern (DiaObject  *object,
			DiaPattern *pattern)
{
  ObjectChange *change;
  GPtrArray *props;
  PatternProperty *pp;
  Property *prop = object_prop_by_name_type (object, "pattern", PROP_TYPE_PATTERN);
  
  if (!prop)
    return NULL;
  pp = (PatternProperty *)prop;
  if (pp->pattern == pattern)
    return change_list_create ();
  if (pp->pattern)
    g_object_unref (pp->pattern);
  pp->pattern = g_object_ref (pattern);
  props = prop_list_from_single (prop);
  change = object_apply_props (object, props);
  prop_list_free (props);
  return change;
}
Esempio n. 3
0
/*!
 * \brief Modification of the objects 'pixbuf' property
 *
 * @param object object to modify
 * @param pixbuf the pixbuf to set
 * @return an object change or NULL
 *
 * If the object does not have a pixbuf property nothing
 * happens. If there is a pixbuf property and the passed
 * in pixbuf is identical an empty change is returned.
 *
 * \memberof _DiaObject
 * \ingroup StdProps
 */
ObjectChange *
dia_object_set_pixbuf (DiaObject *object,
		       GdkPixbuf *pixbuf)
{
  ObjectChange *change;
  GPtrArray *props;
  PixbufProperty *pp;
  Property *prop = object_prop_by_name_type (object, "pixbuf", PROP_TYPE_PIXBUF);
  
  if (!prop)
    return NULL;
  pp = (PixbufProperty *)prop;
  if (pp->pixbuf == pixbuf)
    return change_list_create ();
  if (pp->pixbuf)
    g_object_unref (pp->pixbuf);
  pp->pixbuf = g_object_ref (pixbuf);
  props = prop_list_from_single (prop);
  change = object_apply_props (object, props);
  prop_list_free (props);
  return change;
}
Esempio n. 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;
}
Esempio n. 5
0
static ObjectChange *
_obj_set_bends (DiaObject *obj, std::vector<double>& coords)
{
  Property *prop = NULL;
  
  if ((prop = object_prop_by_name(obj, "poly_points")) != NULL) {
    PointarrayProperty *ptp = (PointarrayProperty *)prop;
    int num = ptp->pointarray_data->len;
    Point last  = g_array_index(ptp->pointarray_data, Point, num-1);
    // we keep the first and last point (the connected ones) and overwrite the rest
    num = coords.size()/2+2;

    g_array_set_size(ptp->pointarray_data, num);
    for (int i = 1; i < num-1; ++i) {
      Point *pt = &g_array_index(ptp->pointarray_data, Point, i);
      pt->x = coords[(i-1)*2];
      pt->y = coords[(i-1)*2+1];
    }
    g_array_index(ptp->pointarray_data, Point, num-1) = last;
  } else if ((prop = object_prop_by_name(obj, "orth_points")) != NULL) {
    PointarrayProperty *ptp = (PointarrayProperty *)prop;
    int num = ptp->pointarray_data->len;
    Point last  = g_array_index(ptp->pointarray_data, Point, num-1);
    // we keep the first and last point (the connected ones) and overwrite the rest
    num = coords.size()/2+2;

    // there must be at least 3 points with an orthconn, so we may have to create one
    // TODO: also maintain the orthogonality?
    if (num == 2) {
      Point first  = g_array_index(ptp->pointarray_data, Point, 0);
      Point pt = { (first.x + last.x) / 2, (first.y + last.y) / 2 };
      ++num;
      g_array_set_size(ptp->pointarray_data, num);
      g_array_index(ptp->pointarray_data, Point, num-2) = pt;
    } else {
      g_array_set_size(ptp->pointarray_data, num);
      for (int i = 1; i < num-1; ++i) {
	Point *pt = &g_array_index(ptp->pointarray_data, Point, i);
	pt->x = coords[(i-1)*2];
	pt->y = coords[(i-1)*2+1];
      }
    }
    g_array_index(ptp->pointarray_data, Point, num-1) = last;
  } else if ((prop = object_prop_by_name(obj, "bez_points")) != NULL) {
    BezPointarrayProperty *ptp = (BezPointarrayProperty *)prop;
    int num = ptp->bezpointarray_data->len;
    BezPoint last = g_array_index(ptp->bezpointarray_data, BezPoint, num-1);

    // we keep the first and last point (the connected ones) and overwrite the rest
    num = coords.size()/2+1;
    if (num == 1) {
      // still want to have two points - a straight line
      g_array_set_size(ptp->bezpointarray_data, 2);
      last.p1 = last.p3;
      last.p2 = g_array_index(ptp->bezpointarray_data, BezPoint, 0).p1;
      g_array_index(ptp->bezpointarray_data, BezPoint, 1) = last;
    } else {
      // the bends are used for control points ...
      Point p1;

      p1.x = coords[0];
      p1.y = coords[1];
      g_array_set_size(ptp->bezpointarray_data, num);
      for (int i = 1; i < num-1; ++i) {
	BezPoint *bp = &g_array_index(ptp->bezpointarray_data, BezPoint, i);

	// TODO: better conversion from polyline to bezierline?
	bp->type = BezPoint::BEZ_CURVE_TO;
	bp->p1 = p1;
	bp->p2 = p1;
	// ... and an extra point on every segment center
	bp->p3.x = (p1.x + coords[i*2]) / 2;
	bp->p3.y = (p1.y + coords[i*2+1]) / 2;
	// next control point
	p1.x = coords[i*2];
	p1.y = coords[i*2+1];
      }
      last.type = BezPoint::BEZ_CURVE_TO;
      last.p1 = p1;
      last.p2 = p1;
      g_array_index(ptp->bezpointarray_data, BezPoint, num-1) = last;
    }
  }

  if (prop) {
    GPtrArray *props = prop_list_from_single (prop);
    return object_apply_props (obj, props);
  }
  return NULL;
}