forked from SpineML/SpineCreator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SC_component_gvitems.cpp
238 lines (207 loc) · 7.94 KB
/
SC_component_gvitems.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/***************************************************************************
** **
** This file is part of SpineCreator, an easy to use GUI for **
** describing spiking neural network models. **
** Copyright (C) 2013-2014 Alex Cope, Paul Richmond, Seb James **
** **
** This program is free software: you can redistribute it and/or modify **
** it under the terms of the GNU General Public License as published by **
** the Free Software Foundation, either version 3 of the License, or **
** (at your option) any later version. **
** **
** This program is distributed in the hope that it will be useful, **
** but WITHOUT ANY WARRANTY; without even the implied warranty of **
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
** GNU General Public License for more details. **
** **
** You should have received a copy of the GNU General Public License **
** along with this program. If not, see http://www.gnu.org/licenses/. **
** **
****************************************************************************
** Author: Paul Richmond **
** Website/Contact: http://bimpa.group.shef.ac.uk/ **
****************************************************************************/
#include "SC_component_gvitems.h"
// Debugging define here, as we don't include globalHeader.h
#define DBG() qDebug() << __FUNCTION__ << ": "
/* GVLayout */
GVLayout::GVLayout()
{
this->gvc = gvContext();
#ifdef USE_LIBGRAPH_NOT_LIBCGRAPH
this->gvgraph = agopen((char*)"g", AGDIGRAPH);
#else
this->gvgraph = agopen((char*)"g", Agdirected, NULL);
#endif
agsafeset(this->gvgraph, (char*)"splines", (char*)"true", (char*)"");
agsafeset(this->gvgraph, (char*)"overlap", (char*)"false", (char*)"");
agsafeset(this->gvgraph, (char*)"rankdir", (char*)"LR", (char*)"");
agsafeset(this->gvgraph, (char*)"nodesep", (char*)"2.0", (char*)"");
agsafeset(this->gvgraph, (char*)"labelloc", (char*)"t", (char*)"");
}
GVLayout::~GVLayout()
{
agclose(this->gvgraph);
gvFreeContext (this->gvc);
}
void GVLayout::updateLayout()
{
gvLayout (this->gvc, this->gvgraph, "dot");
//update all graphviz items in the layout
for (int i=0; i<this->items.size(); i++)
{
GVItem *gv_item = this->items[i];
gv_item->updateLayout();
}
// For debugging, this shows the content of the graph (ok for libgraph and libcgraph):
//gvRender (this->gvc, this->gvgraph, "dot", stdout);
// The original comment for gvFreeLayout() was:
// free after update to avoid crashes when node are removed!
// When gvc is used with cgraph, this actually causes a crash in Graphviz
// 2.26.3 and 2.30.1, due to bug (in Graphviz) 2.32+ are immune.
// The crash occurs on a subsequent call to gvLayout().
// See http://www.graphviz.org/mantisbt/view.php?id=2467
gvFreeLayout (this->gvc, this->gvgraph);
}
Agraph_t *GVLayout::getGVGraph()
{
return this->gvgraph;
}
void GVLayout::addGVItem(GVItem *item)
{
items.push_back(item);
}
void GVLayout::removeGVItem(GVItem *item)
{
items.erase(std::remove(items.begin(), items.end(), item), items.end());
}
GVItem::GVItem(GVLayout *l)
{
this->layout = l;
this->layout->addGVItem(this);
}
/* GVNode */
GVNode::GVNode(GVLayout *l, QString name)
: GVItem(l)
{
#ifdef USE_LIBGRAPH_NOT_LIBCGRAPH
this->gv_node = agnode(this->layout->getGVGraph(), name.toUtf8().data());
#else
this->gv_node = agnode(this->layout->getGVGraph(), name.toUtf8().data(), TRUE);
#endif
agsafeset(this->gv_node, (char*)"fixedsize", (char*)"true", (char*)"");
agsafeset(this->gv_node, (char*)"shape", (char*)"rectangle", (char*)"");
}
GVNode::~GVNode()
{
agdelete(this->layout->getGVGraph(), this->gv_node);
}
Agnode_t * GVNode::getGVNode()
{
return this->gv_node;
}
void GVNode::setGVNodeSize(qreal width_inches, qreal height_inches)
{
//update GV node size
char w[16];
char h[16];
sprintf(w,"%f", width_inches);
sprintf(h,"%f", height_inches);
agsafeset(this->gv_node, (char*)"width", w, (char*)"");
agsafeset(this->gv_node, (char*)"height", h, (char*)"");
//DBG() << "setGVNodeSize (" << w << ", " << h << ") in inches for node " << ND_id(this->gv_node);
}
// used in nineml_graphicsitems.cpp:122 or thereabouts. This method
// is a bit bizarre; I would apply the offset in the client code to
// make this a pure position accessor.
QPointF GVNode::getGVNodePosition(QPointF offset)
{
QPointF position;
#ifdef USE_LIBGRAPH_NOT_LIBCGRAPH
position = QPointF((gv_node->u.coord.x), (layout->getGVGraph()->u.bb.UR.y - gv_node->u.coord.y));
#else
position = QPointF(ND_coord(this->gv_node).x,
(GD_bb(this->layout->getGVGraph()).UR.y - ND_coord(this->gv_node).y));
#endif
//DBG() << "getGVNodePosition: actual position: " << position
// << " for node ID " << ND_id(this->gv_node);
position -= offset;
return position;
}
#ifdef USE_LIBGRAPH_NOT_LIBCGRAPH
void GVNode::renameGVNode(QString name)
{
QString temp(gv_node->name);
agstrfree(gv_node->name);
gv_node->name = agstrdup(name.toUtf8().data());
}
#endif
/* GVEdge */
GVEdge::GVEdge(GVLayout *l, Agnode_t *src, Agnode_t *dst)
: GVItem(l)
{
//get src regime
#ifdef USE_LIBGRAPH_NOT_LIBCGRAPH
this->gv_edge = agedge(this->layout->getGVGraph(), src, dst);
#else
this->gv_edge = agedge(this->layout->getGVGraph(), src, dst, NULL, 1);
#endif
}
GVEdge::~GVEdge()
{
agdelete(this->layout->getGVGraph(), this->gv_edge);
}
void GVEdge::setGVEdgeLabelSize(int width_pixels, int height_pixels)
{
//update GV l width
char label[256];
sprintf(label,"<table width=\"%d\" height=\"%d\"><tr><td>Label</td></tr></table>", width_pixels, height_pixels);
#ifdef USE_LIBGRAPH_NOT_LIBCGRAPH
char* html = agstrdup_html(label);
agsafeset(this->gv_edge, (char*)"label", html, (char*)"html");
agstrfree(html);
#else
char* html = agstrdup_html(this->layout->getGVGraph(), label);
agsafeset(this->gv_edge, (char*)"label", html, (char*)"html");
agstrfree(this->layout->getGVGraph(), html);
#endif
//DBG() << "(" << width_pixels<< ", " << height_pixels << ") for label '" << agget (this->gv_edge, (char*)"label") << "'";
}
QPointF GVEdge::getGVEdgeLabelPosition(QPointF offset)
{
QPointF position(0,0);
#ifdef USE_LIBGRAPH_NOT_LIBCGRAPH
position = QPointF(this->gv_edge->u.label->pos.x,
this->layout->getGVGraph()->u.bb.UR.y - this->gv_edge->u.label->pos.y);
#else
qreal a = 0;
qreal b = 0;
textlabel_t* edgelabel = ED_label(this->gv_edge);
if (edgelabel != NULL) {
a = edgelabel->pos.x;
} else {
DBG() << "Warning: edge label doesn't exist in this->gv_edge...";
}
//char* l = agget (this->gv_edge, (char*)"label");
b = (GD_bb(this->layout->getGVGraph()).UR.y - ED_label(this->gv_edge)->pos.y);
position = QPointF(a,b);
#endif
position -= offset;
return position;
}
int GVEdge::getGVEdgeSplinesCount()
{
return ED_spl(this->gv_edge)->list->size;
}
QPointF GVEdge::getGVEdgeSplinesPoint(int i)
{
QPointF spline = QPointF(ED_spl(this->gv_edge)->list->list[i].x,
GD_bb(this->layout->getGVGraph()).UR.y - ED_spl(this->gv_edge)->list->list[i].y);
return spline;
}
QPointF GVEdge::getGVEdgeSplinesEndPoint()
{
QPointF spline = QPointF(ED_spl(this->gv_edge)->list->ep.x,
GD_bb(this->layout->getGVGraph()).UR.y - ED_spl(this->gv_edge)->list->ep.y);
return spline;
}