hegyi@1289
|
1 |
// This example was started by Guillaume Laurent.
|
hegyi@1289
|
2 |
// It has become a place to dump code that tests parts of the
|
hegyi@1289
|
3 |
// gnomemm canvas code. Little thought has been given to the
|
hegyi@1289
|
4 |
// actual on-screen output.
|
hegyi@1289
|
5 |
|
hegyi@1289
|
6 |
#include <libgnomecanvasmm.h>
|
hegyi@1289
|
7 |
#include <libgnomecanvasmm/polygon.h>
|
hegyi@1289
|
8 |
|
hegyi@1289
|
9 |
#include <fstream>
|
hegyi@1289
|
10 |
#include <iostream>
|
hegyi@1289
|
11 |
|
hegyi@1289
|
12 |
#include <lemon/list_graph.h>
|
hegyi@1289
|
13 |
#include <lemon/graph_reader.h>
|
hegyi@1289
|
14 |
#include <lemon/graph_utils.h>
|
hegyi@1289
|
15 |
#include <lemon/maps.h>
|
hegyi@1289
|
16 |
#include <lemon/error.h>
|
hegyi@1289
|
17 |
#include <lemon/xy.h>
|
hegyi@1289
|
18 |
|
hegyi@1289
|
19 |
using namespace lemon;
|
hegyi@1289
|
20 |
|
hegyi@1289
|
21 |
typedef xy<double> Coordinates;
|
hegyi@1289
|
22 |
typedef ListGraph Graph;
|
hegyi@1289
|
23 |
typedef Graph::NodeMap<Coordinates> CoordinatesMap;
|
hegyi@1289
|
24 |
typedef Graph::Node Node;
|
hegyi@1289
|
25 |
typedef Graph::EdgeIt EdgeIt;
|
hegyi@1289
|
26 |
typedef Graph::NodeIt NodeIt;
|
hegyi@1289
|
27 |
|
hegyi@1289
|
28 |
class GraphDisplayerCanvas : public Gnome::Canvas::CanvasAA
|
hegyi@1289
|
29 |
{
|
hegyi@1289
|
30 |
typedef Gnome::Canvas::CanvasAA Parent;
|
hegyi@1289
|
31 |
|
hegyi@1289
|
32 |
public:
|
hegyi@1289
|
33 |
GraphDisplayerCanvas(Graph &, CoordinatesMap &);
|
hegyi@1289
|
34 |
virtual ~GraphDisplayerCanvas();
|
hegyi@1289
|
35 |
|
hegyi@1289
|
36 |
private:
|
hegyi@1289
|
37 |
|
hegyi@1289
|
38 |
///Event handler function that handles dragging nodes of displayed_graph
|
hegyi@1289
|
39 |
bool event_handler(GdkEvent* e, int b);
|
hegyi@1289
|
40 |
|
hegyi@1289
|
41 |
///Event handler function that handles dragging displayed_graph
|
hegyi@1289
|
42 |
bool tri_mover(GdkEvent* e);
|
hegyi@1289
|
43 |
|
hegyi@1289
|
44 |
///Coordinates of Weight Point of tirangle
|
hegyi@1289
|
45 |
Gnome::Art::Point * wp;
|
hegyi@1289
|
46 |
///Array of nodes of planefigure
|
hegyi@1289
|
47 |
Gnome::Canvas::Ellipse ** nodes;
|
hegyi@1289
|
48 |
///Sides of planefigure
|
hegyi@1289
|
49 |
Gnome::Canvas::Polygon * sides;
|
hegyi@1289
|
50 |
///Group of graphical elements of displayed_graph
|
hegyi@1289
|
51 |
Gnome::Canvas::Group displayed_graph;
|
hegyi@1289
|
52 |
|
hegyi@1289
|
53 |
///Indicates whether the button of mouse is pressed or not
|
hegyi@1289
|
54 |
bool isbutton;
|
hegyi@1289
|
55 |
|
hegyi@1289
|
56 |
///Number Of Elements - the number of nodes
|
hegyi@1289
|
57 |
int noe;
|
hegyi@1289
|
58 |
|
hegyi@1289
|
59 |
///Array of coordinates
|
hegyi@1289
|
60 |
double * coordinates;
|
hegyi@1289
|
61 |
|
hegyi@1289
|
62 |
///At this location was the mousebutton pressed.
|
hegyi@1289
|
63 |
///It helps to calculate the distance of dragging.
|
hegyi@1289
|
64 |
double clicked_x, clicked_y;
|
hegyi@1289
|
65 |
|
hegyi@1289
|
66 |
///Remembers which Gnome::Canvas::Item was pressed.
|
hegyi@1289
|
67 |
///this variable is needed, because
|
hegyi@1289
|
68 |
///1. we cannot query the item at he cursor as fast as it could not cause a Segmentation Fault
|
hegyi@1289
|
69 |
///2. we would like to handle only ony item per movement, therefore quering it is not a working solution
|
hegyi@1289
|
70 |
Gnome::Canvas::Item * active_item;
|
hegyi@1289
|
71 |
|
hegyi@1289
|
72 |
|
hegyi@1289
|
73 |
};
|
hegyi@1289
|
74 |
|
hegyi@1289
|
75 |
///When we click on the weight point we can drag the whole planefigure. This function resolves it.
|
hegyi@1289
|
76 |
bool GraphDisplayerCanvas::tri_mover(GdkEvent* e)
|
hegyi@1289
|
77 |
{
|
hegyi@1289
|
78 |
switch(e->type)
|
hegyi@1289
|
79 |
{
|
hegyi@1289
|
80 |
case GDK_BUTTON_PRESS:
|
hegyi@1289
|
81 |
clicked_x=e->button.x;
|
hegyi@1289
|
82 |
clicked_y=e->button.y;
|
hegyi@1289
|
83 |
isbutton=true;
|
hegyi@1289
|
84 |
break;
|
hegyi@1289
|
85 |
case GDK_BUTTON_RELEASE:
|
hegyi@1289
|
86 |
isbutton=false;
|
hegyi@1289
|
87 |
active_item=NULL;
|
hegyi@1289
|
88 |
break;
|
hegyi@1289
|
89 |
case GDK_MOTION_NOTIFY:
|
hegyi@1289
|
90 |
if(isbutton)
|
hegyi@1289
|
91 |
{
|
hegyi@1289
|
92 |
double dx=e->motion.x-clicked_x;
|
hegyi@1289
|
93 |
double dy=e->motion.y-clicked_y;
|
hegyi@1289
|
94 |
|
hegyi@1289
|
95 |
Gnome::Canvas::Points coos;
|
hegyi@1289
|
96 |
|
hegyi@1289
|
97 |
for(int i=0;i<=noe;i++)
|
hegyi@1289
|
98 |
{
|
hegyi@1289
|
99 |
nodes[i]->move(dx,dy);
|
hegyi@1289
|
100 |
|
hegyi@1289
|
101 |
double x=(coordinates[2*i]+=dx);
|
hegyi@1289
|
102 |
double y=(coordinates[2*i+1]+=dy);
|
hegyi@1289
|
103 |
|
hegyi@1289
|
104 |
if(i!=noe)coos.push_back(Gnome::Art::Point(x,y));
|
hegyi@1289
|
105 |
|
hegyi@1289
|
106 |
}
|
hegyi@1289
|
107 |
|
hegyi@1289
|
108 |
clicked_x=e->motion.x;
|
hegyi@1289
|
109 |
clicked_y=e->motion.y;
|
hegyi@1289
|
110 |
|
hegyi@1289
|
111 |
sides->property_points().set_value(coos);
|
hegyi@1289
|
112 |
}
|
hegyi@1289
|
113 |
default: break;
|
hegyi@1289
|
114 |
}
|
hegyi@1289
|
115 |
return true;
|
hegyi@1289
|
116 |
}
|
hegyi@1289
|
117 |
|
hegyi@1289
|
118 |
///This function moves only one node of displayed_graph,
|
hegyi@1289
|
119 |
///but recalculate the location of weight point,
|
hegyi@1289
|
120 |
///and also redraw the sides of the planefigure.
|
hegyi@1289
|
121 |
bool GraphDisplayerCanvas::event_handler(GdkEvent* e, int b)
|
hegyi@1289
|
122 |
{
|
hegyi@1289
|
123 |
switch(e->type)
|
hegyi@1289
|
124 |
{
|
hegyi@1289
|
125 |
case GDK_BUTTON_PRESS:
|
hegyi@1289
|
126 |
clicked_x=e->button.x;
|
hegyi@1289
|
127 |
clicked_y=e->button.y;
|
hegyi@1289
|
128 |
active_item=(get_item_at(e->button.x, e->button.y));
|
hegyi@1289
|
129 |
isbutton=true;
|
hegyi@1289
|
130 |
break;
|
hegyi@1289
|
131 |
case GDK_BUTTON_RELEASE:
|
hegyi@1289
|
132 |
isbutton=false;
|
hegyi@1289
|
133 |
active_item=NULL;
|
hegyi@1289
|
134 |
break;
|
hegyi@1289
|
135 |
case GDK_MOTION_NOTIFY:
|
hegyi@1289
|
136 |
if(isbutton)
|
hegyi@1289
|
137 |
{
|
hegyi@1289
|
138 |
//double x1, y1, x2, y2;
|
hegyi@1289
|
139 |
//(get_item_at(e->motion.x, e->motion.y))->get_bounds(x1, y1, x2, y2);
|
hegyi@1289
|
140 |
//printf("Item coos: %d %d %d %d\n", (int)x1, (int)y1, (int)x2, (int)y2);
|
hegyi@1289
|
141 |
//printf("Mouse is moved! %d %d\n",(int)e->motion.x,(int)e->motion.y);
|
hegyi@1289
|
142 |
double dx=e->motion.x-clicked_x;
|
hegyi@1289
|
143 |
double dy=e->motion.y-clicked_y;
|
hegyi@1289
|
144 |
active_item->move(dx, dy);
|
hegyi@1289
|
145 |
|
hegyi@1289
|
146 |
coordinates[2*b]+=dx;
|
hegyi@1289
|
147 |
coordinates[2*b+1]+=dy;
|
hegyi@1289
|
148 |
|
hegyi@1289
|
149 |
Gnome::Canvas::Points coos;
|
hegyi@1289
|
150 |
|
hegyi@1289
|
151 |
double x_wp=0;
|
hegyi@1289
|
152 |
double y_wp=0;
|
hegyi@1289
|
153 |
|
hegyi@1289
|
154 |
for(int i=0;i<noe;i++)
|
hegyi@1289
|
155 |
{
|
hegyi@1289
|
156 |
coos.push_back(Gnome::Art::Point(coordinates[2*i], coordinates[2*i+1]));
|
hegyi@1289
|
157 |
|
hegyi@1289
|
158 |
x_wp+=coordinates[2*i];
|
hegyi@1289
|
159 |
y_wp+=coordinates[2*i+1];
|
hegyi@1289
|
160 |
}
|
hegyi@1289
|
161 |
|
hegyi@1289
|
162 |
sides->property_points().set_value(coos);
|
hegyi@1289
|
163 |
|
hegyi@1289
|
164 |
x_wp/=noe;
|
hegyi@1289
|
165 |
y_wp/=noe;
|
hegyi@1289
|
166 |
|
hegyi@1289
|
167 |
dx=x_wp-coordinates[noe*2];
|
hegyi@1289
|
168 |
dy=y_wp-coordinates[noe*2+1];
|
hegyi@1289
|
169 |
nodes[noe]->move(dx, dy);
|
hegyi@1289
|
170 |
|
hegyi@1289
|
171 |
coordinates[noe*2]+=dx;
|
hegyi@1289
|
172 |
coordinates[noe*2+1]+=dy;
|
hegyi@1289
|
173 |
|
hegyi@1289
|
174 |
clicked_x=e->motion.x;
|
hegyi@1289
|
175 |
clicked_y=e->motion.y;
|
hegyi@1289
|
176 |
}
|
hegyi@1289
|
177 |
default: break;
|
hegyi@1289
|
178 |
}
|
hegyi@1289
|
179 |
return true;
|
hegyi@1289
|
180 |
}
|
hegyi@1289
|
181 |
|
hegyi@1289
|
182 |
GraphDisplayerCanvas::GraphDisplayerCanvas(Graph & g, CoordinatesMap & cm):displayed_graph(*(root()), 0, 0),isbutton(false),active_item(NULL)
|
hegyi@1289
|
183 |
{
|
hegyi@1289
|
184 |
nodes=new Gnome::Canvas::Ellipse* [countNodes(g)];
|
hegyi@1289
|
185 |
int sorszam=0;
|
hegyi@1289
|
186 |
|
hegyi@1289
|
187 |
for (NodeIt i(g); i!=INVALID; ++i)
|
hegyi@1289
|
188 |
{
|
hegyi@1289
|
189 |
nodes[sorszam]= new Gnome::Canvas::Ellipse(displayed_graph, cm[i].x-20, cm[i].y-20, cm[i].x+20, cm[i].y+20);
|
hegyi@1289
|
190 |
*(nodes[sorszam]) << Gnome::Canvas::Properties::fill_color("blue");
|
hegyi@1289
|
191 |
*(nodes[sorszam]) << Gnome::Canvas::Properties::outline_color("black");
|
hegyi@1289
|
192 |
(nodes[sorszam])->signal_event().connect(sigc::bind(sigc::mem_fun(*this, &GraphDisplayerCanvas::event_handler),sorszam));
|
hegyi@1289
|
193 |
sorszam++;
|
hegyi@1289
|
194 |
}
|
hegyi@1289
|
195 |
|
hegyi@1289
|
196 |
for (EdgeIt i(g); i!=INVALID; ++i)
|
hegyi@1289
|
197 |
{
|
hegyi@1289
|
198 |
}
|
hegyi@1289
|
199 |
|
hegyi@1289
|
200 |
|
hegyi@1289
|
201 |
}
|
hegyi@1289
|
202 |
|
hegyi@1289
|
203 |
GraphDisplayerCanvas::~GraphDisplayerCanvas()
|
hegyi@1289
|
204 |
{
|
hegyi@1289
|
205 |
}
|
hegyi@1289
|
206 |
|
hegyi@1289
|
207 |
//MainWin:
|
hegyi@1289
|
208 |
|
hegyi@1289
|
209 |
class MainWin : public Gtk::Window
|
hegyi@1289
|
210 |
{
|
hegyi@1289
|
211 |
public:
|
hegyi@1289
|
212 |
MainWin(const std::string& title, Graph &, CoordinatesMap &);
|
hegyi@1289
|
213 |
|
hegyi@1289
|
214 |
protected:
|
hegyi@1289
|
215 |
//Member widgets:
|
hegyi@1289
|
216 |
GraphDisplayerCanvas gd_canvas;
|
hegyi@1289
|
217 |
};
|
hegyi@1289
|
218 |
|
hegyi@1289
|
219 |
MainWin::MainWin(const std::string& title, Graph & graph, CoordinatesMap & cm):gd_canvas(graph, cm)
|
hegyi@1289
|
220 |
{
|
hegyi@1289
|
221 |
set_title (title);
|
hegyi@1289
|
222 |
add(gd_canvas);
|
hegyi@1289
|
223 |
set_default_size(900,600);
|
hegyi@1289
|
224 |
|
hegyi@1289
|
225 |
show_all();
|
hegyi@1289
|
226 |
}
|
hegyi@1289
|
227 |
|
hegyi@1289
|
228 |
|
hegyi@1289
|
229 |
///This class is responsible for being able
|
hegyi@1289
|
230 |
///to read xy datastructure from file. It is
|
hegyi@1289
|
231 |
///based on BaseMap. The set method sets the
|
hegyi@1289
|
232 |
///appropriate value in the final xy NodeMap
|
hegyi@1289
|
233 |
///that was given to the constructor.
|
hegyi@1289
|
234 |
class CoordReaderMap: public MapBase <Node, double>
|
hegyi@1289
|
235 |
{
|
hegyi@1289
|
236 |
CoordinatesMap & cm;
|
hegyi@1289
|
237 |
char xoy;
|
hegyi@1289
|
238 |
|
hegyi@1289
|
239 |
public:
|
hegyi@1289
|
240 |
CoordReaderMap(char xory, CoordinatesMap & coordmap);
|
hegyi@1289
|
241 |
void set(Node node, double coord);
|
hegyi@1289
|
242 |
};
|
hegyi@1289
|
243 |
|
hegyi@1289
|
244 |
///The constructor expects for an xy NodeMap,
|
hegyi@1289
|
245 |
///and we have to tell it, for which value
|
hegyi@1289
|
246 |
///of the xy vector is responsible the actual
|
hegyi@1289
|
247 |
///copy.
|
hegyi@1289
|
248 |
CoordReaderMap::CoordReaderMap(char xory, CoordinatesMap & coordmap): cm(coordmap)
|
hegyi@1289
|
249 |
{
|
hegyi@1289
|
250 |
switch(xory)
|
hegyi@1289
|
251 |
{
|
hegyi@1289
|
252 |
case 'x':
|
hegyi@1289
|
253 |
case 'y':
|
hegyi@1289
|
254 |
xoy=xory;
|
hegyi@1289
|
255 |
break;
|
hegyi@1289
|
256 |
default:
|
hegyi@1289
|
257 |
throw UninitializedParameter() ;
|
hegyi@1289
|
258 |
}
|
hegyi@1289
|
259 |
}
|
hegyi@1289
|
260 |
|
hegyi@1289
|
261 |
///set method sets the appropriate value in the
|
hegyi@1289
|
262 |
///xy type NodeMap that is under construction
|
hegyi@1289
|
263 |
void CoordReaderMap::set(Node node, double coord)
|
hegyi@1289
|
264 |
{
|
hegyi@1289
|
265 |
switch(xoy)
|
hegyi@1289
|
266 |
{
|
hegyi@1289
|
267 |
case 'x':
|
hegyi@1289
|
268 |
cm[node].x=coord;
|
hegyi@1289
|
269 |
break;
|
hegyi@1289
|
270 |
case 'y':
|
hegyi@1289
|
271 |
cm[node].y=coord;
|
hegyi@1289
|
272 |
break;
|
hegyi@1289
|
273 |
default:
|
hegyi@1289
|
274 |
throw UninitializedParameter() ;
|
hegyi@1289
|
275 |
}
|
hegyi@1289
|
276 |
}
|
hegyi@1289
|
277 |
|
hegyi@1289
|
278 |
//main():
|
hegyi@1289
|
279 |
|
hegyi@1289
|
280 |
int main(int argc, char *argv[])
|
hegyi@1289
|
281 |
{
|
hegyi@1290
|
282 |
if(argc<2)
|
hegyi@1290
|
283 |
{
|
hegyi@1290
|
284 |
std::cerr << "USAGE: gd <input filename.lgf>" << endl;
|
hegyi@1290
|
285 |
return 0;
|
hegyi@1290
|
286 |
}
|
hegyi@1289
|
287 |
|
hegyi@1289
|
288 |
Coordinates coosvector;
|
hegyi@1289
|
289 |
|
hegyi@1289
|
290 |
Graph g;
|
hegyi@1289
|
291 |
|
hegyi@1289
|
292 |
CoordinatesMap cm(g);
|
hegyi@1289
|
293 |
|
hegyi@1289
|
294 |
//we create one object to read x coordinates
|
hegyi@1289
|
295 |
//and one to read y coordinate of nodes and write them to cm NodeMap.
|
hegyi@1289
|
296 |
CoordReaderMap xreader('x',cm);
|
hegyi@1289
|
297 |
CoordReaderMap yreader('y',cm);
|
hegyi@1289
|
298 |
|
hegyi@1290
|
299 |
std::ifstream is(argv[1]);
|
hegyi@1289
|
300 |
|
hegyi@1289
|
301 |
GraphReader<Graph> reader(is, g);
|
hegyi@1289
|
302 |
reader.addNodeMap("coordinates_x", xreader);
|
hegyi@1289
|
303 |
reader.addNodeMap("coordinates_y", yreader);
|
hegyi@1289
|
304 |
reader.run();
|
hegyi@1289
|
305 |
|
hegyi@1289
|
306 |
for (NodeIt i(g); i!=INVALID; ++i)
|
hegyi@1289
|
307 |
std::cout << " " << g.id(i) << " " << cm[i];
|
hegyi@1289
|
308 |
std::cout << std::endl;
|
hegyi@1289
|
309 |
|
hegyi@1289
|
310 |
Gnome::Canvas::init();
|
hegyi@1289
|
311 |
Gtk::Main app(argc, argv);
|
hegyi@1289
|
312 |
|
hegyi@1289
|
313 |
MainWin mainwin("Displayed Graph", g, cm);
|
hegyi@1289
|
314 |
app.run(mainwin);
|
hegyi@1289
|
315 |
|
hegyi@1289
|
316 |
return 0;
|
hegyi@1289
|
317 |
}
|