/*! * 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); }
/*! * \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; }
/*! * \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; }
/*! * \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; }
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; }