source: trunk/examples/demo/graph.cpp@ 203

Last change on this file since 203 was 160, checked in by dmik, 19 years ago

Imported table and iconview modules and a bunch of dependent examples from the official release 3.3.1 from Trolltech.

  • Property svn:keywords set to Id
File size: 10.3 KB
Line 
1#include "graph.h"
2#include <qcanvas.h>
3#include <stdlib.h>
4#include <qdatetime.h>
5#include <qhbox.h>
6#include <qpushbutton.h>
7#include <qslider.h>
8#include <qlabel.h>
9#include <qlayout.h>
10
11const int bounce_rtti = 1234;
12
13// We use a global variable to save memory - all the brushes and pens in
14// the mesh are shared.
15static QBrush *tb = 0;
16static QPen *tp = 0;
17
18class EdgeItem;
19class NodeItem;
20class FigureEditor;
21typedef QValueList<NodeItem*> NodeItemList;
22typedef QValueList<EdgeItem*> EdgeItemList;
23
24#define SPEED2ADVANCE(x) (301-x)
25
26class GraphWidgetPrivate
27{
28public:
29 GraphWidgetPrivate() {
30 moving = 0;
31 speed = 275;
32 }
33 ~GraphWidgetPrivate() {
34 delete canvas;
35 }
36 NodeItemList nodeItems;
37 FigureEditor* editor;
38 QCanvas* canvas;
39 QCanvasItem* moving;
40 int speed;
41};
42
43class EdgeItem: public QCanvasLine
44{
45public:
46 EdgeItem( NodeItem*, NodeItem*, QCanvas* );
47 void setFromPoint( int x, int y ) ;
48 void setToPoint( int x, int y );
49 void moveBy(double dx, double dy);
50
51 NodeItem* from;
52 NodeItem* to;
53};
54
55
56
57class NodeItem: public QCanvasEllipse
58{
59public:
60 NodeItem( GraphWidgetPrivate* g );
61 ~NodeItem() {}
62
63 void addInEdge( EdgeItem *edge ) { inList.append( edge ); }
64 void addOutEdge( EdgeItem *edge ) { outList.append( edge ); }
65
66 void moveBy(double dx, double dy);
67
68 void calcForce();
69 void advance( int stage );
70
71private:
72 GraphWidgetPrivate* graph;
73 EdgeItemList inList;
74 EdgeItemList outList;
75};
76
77
78
79void EdgeItem::moveBy(double, double)
80{
81 //nothing
82}
83
84EdgeItem::EdgeItem( NodeItem *fromItem, NodeItem *toItem, QCanvas *canvas )
85 : QCanvasLine( canvas )
86{
87 from = fromItem;
88 to = toItem;
89 setPen( *tp );
90 setBrush( *tb );
91 from->addOutEdge( this );
92 to->addInEdge( this );
93 setPoints( int(from->x()), int(from->y()), int(to->x()), int(to->y()) );
94 setZ( 127 );
95}
96
97void EdgeItem::setFromPoint( int x, int y )
98{
99 setPoints( x,y, endPoint().x(), endPoint().y() );
100}
101
102void EdgeItem::setToPoint( int x, int y )
103{
104 setPoints( startPoint().x(), startPoint().y(), x, y );
105}
106
107
108void NodeItem::moveBy(double dx, double dy)
109{
110 double nx = x() + dx;
111 double ny = y() + dy;
112 if ( graph->moving != this ) {
113 nx = QMAX( width()/2, nx );
114 ny = QMAX( height()/2, ny );
115 nx = QMIN( canvas()->width() - width()/2, nx );
116 ny = QMIN( canvas()->height() - height()/2, ny );
117 }
118 QCanvasEllipse::moveBy( nx-x(), ny-y() );
119 EdgeItemList::Iterator it;
120 for ( it = inList.begin(); it != inList.end(); ++it )
121 (*it)->setToPoint( int(x()), int(y()) );
122 for ( it = outList.begin(); it != outList.end(); ++it )
123 (*it)->setFromPoint( int(x()), int(y()) );
124}
125
126NodeItem::NodeItem( GraphWidgetPrivate* g )
127 : QCanvasEllipse( 32, 32, g->canvas )
128{
129 graph = g;
130 graph->nodeItems.append( this );
131 setPen( *tp );
132 setBrush( *tb );
133 setZ( 128 );
134}
135
136void NodeItem::advance( int stage ) {
137 switch ( stage ) {
138 case 0:
139 calcForce();
140 break;
141 case 1:
142 QCanvasItem::advance(stage);
143 break;
144 }
145}
146
147void NodeItem::calcForce() {
148 if ( graph->moving == this ) {
149 setVelocity( 0, 0 );
150 return;
151 }
152 double xvel = 0;
153 double yvel = 0;
154 for ( NodeItemList::Iterator it = graph->nodeItems.begin(); it != graph->nodeItems.end(); ++it ) {
155 NodeItem* n = (*it);
156 if ( n == this )
157 continue;
158 double dx = x() - n->x();
159 double dy = y() - n->y();
160 double l = 2 * ( dx * dx + dy * dy );
161 if ( l > 0 ) {
162 xvel = xvel + dx*260 / l;
163 yvel = yvel + dy*260 / l;
164 }
165 }
166 double w = 1 + outList.count() + inList.count();
167 w *= 10;
168 EdgeItemList::Iterator it2;
169 EdgeItem * e;
170 NodeItem* n;
171 for ( it2 = outList.begin(); it2 != outList.end(); ++it2 ) {
172 e = (*it2);
173 n = e->to;
174 xvel = xvel - ( x() - n->x() ) / w;
175 yvel = yvel - ( y() - n->y() ) / w;
176 }
177 for ( it2 = inList.begin(); it2 != inList.end(); ++it2 ) {
178 e = (*it2);
179 n = e->from;
180 xvel = xvel - ( x() - n->x() ) / w;
181 yvel = yvel - ( y() - n->y() ) / w;
182 }
183 if ( QABS( xvel ) < .1 && QABS( yvel ) < .1 )
184 xvel = yvel = 0;
185 setVelocity( xvel, yvel );
186}
187
188
189class FigureEditor : public QCanvasView {
190public:
191 FigureEditor( GraphWidgetPrivate *g, QWidget* parent=0, const char* name=0, WFlags f=0);
192
193 QSize sizeHint() const;
194
195
196protected:
197 void contentsMousePressEvent(QMouseEvent*);
198 void contentsMouseReleaseEvent(QMouseEvent*);
199 void contentsMouseMoveEvent(QMouseEvent*);
200
201
202 void resizeEvent( QResizeEvent* );
203 void showEvent( QShowEvent* );
204 void hideEvent( QHideEvent* e);
205
206private:
207 void initialize();
208 QPoint moving_start;
209 GraphWidgetPrivate* graph;
210};
211
212
213FigureEditor::FigureEditor(
214 GraphWidgetPrivate* g, QWidget* parent,
215 const char* name, WFlags f) :
216 QCanvasView(g->canvas, parent,name,f)
217{
218 graph = g;
219}
220
221void FigureEditor::contentsMousePressEvent(QMouseEvent* e)
222{
223 QCanvasItemList l=canvas()->collisions(e->pos());
224 for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) {
225 if ((*it)->rtti()==bounce_rtti )
226 continue;
227 graph->moving = *it;
228 moving_start = e->pos();
229 return;
230 }
231 graph->moving = 0;
232}
233
234void FigureEditor::contentsMouseReleaseEvent(QMouseEvent* )
235{
236 if ( graph->moving )
237 graph->moving = 0;
238}
239
240void FigureEditor::contentsMouseMoveEvent(QMouseEvent* e)
241{
242 if ( graph->moving ) {
243 graph->moving->moveBy(e->pos().x() - moving_start.x(),
244 e->pos().y() - moving_start.y());
245 moving_start = e->pos();
246 canvas()->update();
247 }
248}
249
250class BouncyText : public QCanvasText {
251 void initPos();
252 void initSpeed();
253public:
254 int rtti() const;
255 BouncyText(const QString&, QFont, QCanvas*);
256 void advance(int);
257};
258
259BouncyText::BouncyText( const QString& text, QFont f, QCanvas* canvas) :
260 QCanvasText(text, f, canvas)
261{
262 setAnimated(TRUE);
263 initPos();
264}
265
266
267int BouncyText::rtti() const
268{
269 return bounce_rtti;
270}
271
272void BouncyText::initPos()
273{
274 initSpeed();
275 int trial=1000;
276 do {
277 move(rand()%(canvas()->width()-boundingRect().width()),
278 rand()%(canvas()->height()-boundingRect().height()));
279 advance(0);
280 } while (trial-- && xVelocity()==0.0 && yVelocity()==0.0);
281}
282
283void BouncyText::initSpeed()
284{
285 const double speed = 2.0;
286 double d = (double)(rand()%1024) / 1024.0;
287 double e = (double)(rand()%1024) / 1024.0;
288
289 if ( d < .5 )
290 d = -1 - d;
291 else
292 d = d + 1;
293 if ( e < .5 )
294 e = -1 - e;
295 else
296 e = e + 1;
297
298 setVelocity( d*speed, e * speed );
299}
300
301void BouncyText::advance( int stage )
302{
303 switch ( stage ) {
304 case 0: {
305 double vx = xVelocity();
306 double vy = yVelocity();
307
308 if ( vx == 0.0 && vy == 0.0 ) {
309 // stopped last turn
310 initSpeed();
311 vx = xVelocity();
312 vy = yVelocity();
313 }
314
315 QRect r = boundingRect();
316 r.moveBy( int(vx), int(vy) );
317
318 if ( r.left() < 0 || r.right() > canvas()->width() )
319 vx = -vx;
320 if ( r.top() < 0 || r.bottom() > canvas()->height() )
321 vy = -vy;
322
323 r = boundingRect();
324 r.moveBy( int(vx), int(vy) );
325 if ( r.left() < 0 || r.right() > canvas()->width() )
326 vx = 0;
327 if ( r.top() < 0 || r.bottom() > canvas()->height() )
328 vy = 0;
329
330 setVelocity( vx, vy );
331 } break;
332 case 1:
333 QCanvasItem::advance( stage );
334 break;
335 }
336}
337
338GraphWidget::GraphWidget( QWidget *parent, const char *name)
339 : QWidget( parent, name )
340{
341 d = new GraphWidgetPrivate;
342 d->canvas = 0;
343 QVBoxLayout* vb = new QVBoxLayout( this, 11, 6 );
344 d->editor = new FigureEditor( d, this );
345 vb->addWidget( d->editor );
346 QHBoxLayout* hb = new QHBoxLayout( vb );
347 hb->addWidget( new QLabel("Slow", this ) );
348 QSlider* slider = new QSlider( 0, 300, 25, d->speed, Horizontal, this );
349 connect( slider, SIGNAL( valueChanged(int) ), this, SLOT( setSpeed(int) ) );
350 hb->addWidget( slider );
351 hb->addWidget( new QLabel("Fast", this ) );
352 hb->addSpacing( 10 );
353 QPushButton* btn = new QPushButton( "Shuffle Nodes", this );
354 connect( btn, SIGNAL( clicked() ), this, SLOT( shuffle() ) );
355 hb->addWidget( btn );
356}
357
358
359GraphWidget::~GraphWidget()
360{
361 delete d;
362}
363
364void GraphWidget::setSpeed(int s)
365{
366 d->speed = s;
367 if ( isVisible() && d->canvas )
368 d->canvas->setAdvancePeriod( SPEED2ADVANCE( s ) );
369}
370
371void GraphWidget::shuffle()
372{
373
374 for ( NodeItemList::Iterator it = d->nodeItems.begin(); it != d->nodeItems.end(); ++it ) {
375 NodeItem* ni = (*it);
376 ni->move(rand()%(d->canvas->width()-ni->width()),rand()%(d->canvas->height()-ni->height()));
377 }
378}
379
380
381QSize FigureEditor::sizeHint() const
382{
383 return QSize( 600, 400 );
384}
385
386void FigureEditor::resizeEvent( QResizeEvent* e )
387{
388 if ( canvas() )
389 canvas()->resize( contentsRect().width(), contentsRect().height() );
390 QCanvasView::resizeEvent( e );
391}
392
393void FigureEditor::showEvent( QShowEvent* )
394{
395 initialize();
396 canvas()->setAdvancePeriod( SPEED2ADVANCE(graph->speed) );
397}
398
399void FigureEditor::hideEvent( QHideEvent* )
400{
401 initialize();
402 canvas()->setAdvancePeriod( -10 );
403}
404
405void FigureEditor::initialize()
406{
407 if ( canvas() )
408 return;
409 resize( sizeHint() );
410 graph->canvas = new QCanvas( contentsRect().width(), contentsRect().height() );
411 if ( !tb ) tb = new QBrush( Qt::red );
412 if ( !tp ) tp = new QPen( Qt::black );
413 srand( QTime::currentTime().msec() );
414 int nodecount = 0;
415
416 int rows = 3;
417 int cols = 3;
418
419 QMemArray<NodeItem*> lastRow(cols);
420 for ( int r = 0; r < rows; r++ ) {
421 NodeItem *prev = 0;
422 for ( int c = 0; c < cols; c++ ) {
423 NodeItem *ni = new NodeItem( graph );
424 ni->setAnimated( TRUE );
425 nodecount++;
426 ni->move(rand()%(graph->canvas->width()-ni->width()),rand()%(graph->canvas->height()-ni->height()));
427
428 if ( r > 0 )
429 (new EdgeItem( lastRow[c], ni, graph->canvas ))->show();
430 if ( prev )
431 (new EdgeItem( prev, ni, graph->canvas ))->show();
432 prev = ni;
433 lastRow[c] = ni;
434 ni->show();
435 }
436 }
437
438 graph->canvas->advance();
439
440 QCanvasItem* i = new BouncyText( tr( "Drag the nodes around!" ), QFont("helvetica", 24), graph->canvas);
441 i->show();
442 setCanvas( graph->canvas );
443 setMinimumSize( 600, 400 );
444 setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
445}
Note: See TracBrowser for help on using the repository browser.