summaryrefslogtreecommitdiffstats
path: root/examples/demo/graph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/demo/graph.cpp')
-rw-r--r--examples/demo/graph.cpp445
1 files changed, 445 insertions, 0 deletions
diff --git a/examples/demo/graph.cpp b/examples/demo/graph.cpp
new file mode 100644
index 000000000..96e03d6ab
--- /dev/null
+++ b/examples/demo/graph.cpp
@@ -0,0 +1,445 @@
+#include "graph.h"
+#include <qcanvas.h>
+#include <stdlib.h>
+#include <qdatetime.h>
+#include <qhbox.h>
+#include <qpushbutton.h>
+#include <qslider.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+const int bounce_rtti = 1234;
+
+// We use a global variable to save memory - all the brushes and pens in
+// the mesh are shared.
+static TQBrush *tb = 0;
+static TQPen *tp = 0;
+
+class EdgeItem;
+class NodeItem;
+class FigureEditor;
+typedef TQValueList<NodeItem*> NodeItemList;
+typedef TQValueList<EdgeItem*> EdgeItemList;
+
+#define SPEED2ADVANCE(x) (301-x)
+
+class GraphWidgetPrivate
+{
+public:
+ GraphWidgetPrivate() {
+ moving = 0;
+ speed = 275;
+ }
+ ~GraphWidgetPrivate() {
+ delete canvas;
+ }
+ NodeItemList nodeItems;
+ FigureEditor* editor;
+ TQCanvas* canvas;
+ TQCanvasItem* moving;
+ int speed;
+};
+
+class EdgeItem: public TQCanvasLine
+{
+public:
+ EdgeItem( NodeItem*, NodeItem*, TQCanvas* );
+ void setFromPoint( int x, int y ) ;
+ void setToPoint( int x, int y );
+ void moveBy(double dx, double dy);
+
+ NodeItem* from;
+ NodeItem* to;
+};
+
+
+
+class NodeItem: public TQCanvasEllipse
+{
+public:
+ NodeItem( GraphWidgetPrivate* g );
+ ~NodeItem() {}
+
+ void addInEdge( EdgeItem *edge ) { inList.append( edge ); }
+ void addOutEdge( EdgeItem *edge ) { outList.append( edge ); }
+
+ void moveBy(double dx, double dy);
+
+ void calcForce();
+ void advance( int stage );
+
+private:
+ GraphWidgetPrivate* graph;
+ EdgeItemList inList;
+ EdgeItemList outList;
+};
+
+
+
+void EdgeItem::moveBy(double, double)
+{
+ //nothing
+}
+
+EdgeItem::EdgeItem( NodeItem *fromItem, NodeItem *toItem, TQCanvas *canvas )
+ : TQCanvasLine( canvas )
+{
+ from = fromItem;
+ to = toItem;
+ setPen( *tp );
+ setBrush( *tb );
+ from->addOutEdge( this );
+ to->addInEdge( this );
+ setPoints( int(from->x()), int(from->y()), int(to->x()), int(to->y()) );
+ setZ( 127 );
+}
+
+void EdgeItem::setFromPoint( int x, int y )
+{
+ setPoints( x,y, endPoint().x(), endPoint().y() );
+}
+
+void EdgeItem::setToPoint( int x, int y )
+{
+ setPoints( startPoint().x(), startPoint().y(), x, y );
+}
+
+
+void NodeItem::moveBy(double dx, double dy)
+{
+ double nx = x() + dx;
+ double ny = y() + dy;
+ if ( graph->moving != this ) {
+ nx = TQMAX( width()/2, nx );
+ ny = TQMAX( height()/2, ny );
+ nx = TQMIN( canvas()->width() - width()/2, nx );
+ ny = TQMIN( canvas()->height() - height()/2, ny );
+ }
+ TQCanvasEllipse::moveBy( nx-x(), ny-y() );
+ EdgeItemList::Iterator it;
+ for ( it = inList.begin(); it != inList.end(); ++it )
+ (*it)->setToPoint( int(x()), int(y()) );
+ for ( it = outList.begin(); it != outList.end(); ++it )
+ (*it)->setFromPoint( int(x()), int(y()) );
+}
+
+NodeItem::NodeItem( GraphWidgetPrivate* g )
+ : TQCanvasEllipse( 32, 32, g->canvas )
+{
+ graph = g;
+ graph->nodeItems.append( this );
+ setPen( *tp );
+ setBrush( *tb );
+ setZ( 128 );
+}
+
+void NodeItem::advance( int stage ) {
+ switch ( stage ) {
+ case 0:
+ calcForce();
+ break;
+ case 1:
+ TQCanvasItem::advance(stage);
+ break;
+ }
+}
+
+void NodeItem::calcForce() {
+ if ( graph->moving == this ) {
+ setVelocity( 0, 0 );
+ return;
+ }
+ double xvel = 0;
+ double yvel = 0;
+ for ( NodeItemList::Iterator it = graph->nodeItems.begin(); it != graph->nodeItems.end(); ++it ) {
+ NodeItem* n = (*it);
+ if ( n == this )
+ continue;
+ double dx = x() - n->x();
+ double dy = y() - n->y();
+ double l = 2 * ( dx * dx + dy * dy );
+ if ( l > 0 ) {
+ xvel = xvel + dx*260 / l;
+ yvel = yvel + dy*260 / l;
+ }
+ }
+ double w = 1 + outList.count() + inList.count();
+ w *= 10;
+ EdgeItemList::Iterator it2;
+ EdgeItem * e;
+ NodeItem* n;
+ for ( it2 = outList.begin(); it2 != outList.end(); ++it2 ) {
+ e = (*it2);
+ n = e->to;
+ xvel = xvel - ( x() - n->x() ) / w;
+ yvel = yvel - ( y() - n->y() ) / w;
+ }
+ for ( it2 = inList.begin(); it2 != inList.end(); ++it2 ) {
+ e = (*it2);
+ n = e->from;
+ xvel = xvel - ( x() - n->x() ) / w;
+ yvel = yvel - ( y() - n->y() ) / w;
+ }
+ if ( TQABS( xvel ) < .1 && TQABS( yvel ) < .1 )
+ xvel = yvel = 0;
+ setVelocity( xvel, yvel );
+}
+
+
+class FigureEditor : public TQCanvasView {
+public:
+ FigureEditor( GraphWidgetPrivate *g, TQWidget* parent=0, const char* name=0, WFlags f=0);
+
+ TQSize sizeHint() const;
+
+
+protected:
+ void contentsMousePressEvent(TQMouseEvent*);
+ void contentsMouseReleaseEvent(TQMouseEvent*);
+ void contentsMouseMoveEvent(TQMouseEvent*);
+
+
+ void resizeEvent( TQResizeEvent* );
+ void showEvent( TQShowEvent* );
+ void hideEvent( TQHideEvent* e);
+
+private:
+ void initialize();
+ TQPoint moving_start;
+ GraphWidgetPrivate* graph;
+};
+
+
+FigureEditor::FigureEditor(
+ GraphWidgetPrivate* g, TQWidget* parent,
+ const char* name, WFlags f) :
+ TQCanvasView(g->canvas, parent,name,f)
+{
+ graph = g;
+}
+
+void FigureEditor::contentsMousePressEvent(TQMouseEvent* e)
+{
+ TQCanvasItemList l=canvas()->collisions(e->pos());
+ for (TQCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it) {
+ if ((*it)->rtti()==bounce_rtti )
+ continue;
+ graph->moving = *it;
+ moving_start = e->pos();
+ return;
+ }
+ graph->moving = 0;
+}
+
+void FigureEditor::contentsMouseReleaseEvent(TQMouseEvent* )
+{
+ if ( graph->moving )
+ graph->moving = 0;
+}
+
+void FigureEditor::contentsMouseMoveEvent(TQMouseEvent* e)
+{
+ if ( graph->moving ) {
+ graph->moving->moveBy(e->pos().x() - moving_start.x(),
+ e->pos().y() - moving_start.y());
+ moving_start = e->pos();
+ canvas()->update();
+ }
+}
+
+class BouncyText : public TQCanvasText {
+ void initPos();
+ void initSpeed();
+public:
+ int rtti() const;
+ BouncyText(const TQString&, TQFont, TQCanvas*);
+ void advance(int);
+};
+
+BouncyText::BouncyText( const TQString& text, TQFont f, TQCanvas* canvas) :
+ TQCanvasText(text, f, canvas)
+{
+ setAnimated(TRUE);
+ initPos();
+}
+
+
+int BouncyText::rtti() const
+{
+ return bounce_rtti;
+}
+
+void BouncyText::initPos()
+{
+ initSpeed();
+ int trial=1000;
+ do {
+ move(rand()%(canvas()->width()-boundingRect().width()),
+ rand()%(canvas()->height()-boundingRect().height()));
+ advance(0);
+ } while (trial-- && xVelocity()==0.0 && yVelocity()==0.0);
+}
+
+void BouncyText::initSpeed()
+{
+ const double speed = 2.0;
+ double d = (double)(rand()%1024) / 1024.0;
+ double e = (double)(rand()%1024) / 1024.0;
+
+ if ( d < .5 )
+ d = -1 - d;
+ else
+ d = d + 1;
+ if ( e < .5 )
+ e = -1 - e;
+ else
+ e = e + 1;
+
+ setVelocity( d*speed, e * speed );
+}
+
+void BouncyText::advance( int stage )
+{
+ switch ( stage ) {
+ case 0: {
+ double vx = xVelocity();
+ double vy = yVelocity();
+
+ if ( vx == 0.0 && vy == 0.0 ) {
+ // stopped last turn
+ initSpeed();
+ vx = xVelocity();
+ vy = yVelocity();
+ }
+
+ TQRect r = boundingRect();
+ r.moveBy( int(vx), int(vy) );
+
+ if ( r.left() < 0 || r.right() > canvas()->width() )
+ vx = -vx;
+ if ( r.top() < 0 || r.bottom() > canvas()->height() )
+ vy = -vy;
+
+ r = boundingRect();
+ r.moveBy( int(vx), int(vy) );
+ if ( r.left() < 0 || r.right() > canvas()->width() )
+ vx = 0;
+ if ( r.top() < 0 || r.bottom() > canvas()->height() )
+ vy = 0;
+
+ setVelocity( vx, vy );
+ } break;
+ case 1:
+ TQCanvasItem::advance( stage );
+ break;
+ }
+}
+
+GraphWidget::GraphWidget( TQWidget *parent, const char *name)
+ : TQWidget( parent, name )
+{
+ d = new GraphWidgetPrivate;
+ d->canvas = 0;
+ TQVBoxLayout* vb = new TQVBoxLayout( this, 11, 6 );
+ d->editor = new FigureEditor( d, this );
+ vb->addWidget( d->editor );
+ TQHBoxLayout* hb = new TQHBoxLayout( vb );
+ hb->addWidget( new TQLabel("Slow", this ) );
+ TQSlider* slider = new TQSlider( 0, 300, 25, d->speed, Horizontal, this );
+ connect( slider, SIGNAL( valueChanged(int) ), this, SLOT( setSpeed(int) ) );
+ hb->addWidget( slider );
+ hb->addWidget( new TQLabel("Fast", this ) );
+ hb->addSpacing( 10 );
+ TQPushButton* btn = new TQPushButton( "Shuffle Nodes", this );
+ connect( btn, SIGNAL( clicked() ), this, SLOT( shuffle() ) );
+ hb->addWidget( btn );
+}
+
+
+GraphWidget::~GraphWidget()
+{
+ delete d;
+}
+
+void GraphWidget::setSpeed(int s)
+{
+ d->speed = s;
+ if ( isVisible() && d->canvas )
+ d->canvas->setAdvancePeriod( SPEED2ADVANCE( s ) );
+}
+
+void GraphWidget::shuffle()
+{
+
+ for ( NodeItemList::Iterator it = d->nodeItems.begin(); it != d->nodeItems.end(); ++it ) {
+ NodeItem* ni = (*it);
+ ni->move(rand()%(d->canvas->width()-ni->width()),rand()%(d->canvas->height()-ni->height()));
+ }
+}
+
+
+TQSize FigureEditor::sizeHint() const
+{
+ return TQSize( 600, 400 );
+}
+
+void FigureEditor::resizeEvent( TQResizeEvent* e )
+{
+ if ( canvas() )
+ canvas()->resize( contentsRect().width(), contentsRect().height() );
+ TQCanvasView::resizeEvent( e );
+}
+
+void FigureEditor::showEvent( TQShowEvent* )
+{
+ initialize();
+ canvas()->setAdvancePeriod( SPEED2ADVANCE(graph->speed) );
+}
+
+void FigureEditor::hideEvent( TQHideEvent* )
+{
+ initialize();
+ canvas()->setAdvancePeriod( -10 );
+}
+
+void FigureEditor::initialize()
+{
+ if ( canvas() )
+ return;
+ resize( sizeHint() );
+ graph->canvas = new TQCanvas( contentsRect().width(), contentsRect().height() );
+ if ( !tb ) tb = new TQBrush( TQt::red );
+ if ( !tp ) tp = new TQPen( TQt::black );
+ srand( TQTime::currentTime().msec() );
+ int nodecount = 0;
+
+ int rows = 3;
+ int cols = 3;
+
+ TQMemArray<NodeItem*> lastRow(cols);
+ for ( int r = 0; r < rows; r++ ) {
+ NodeItem *prev = 0;
+ for ( int c = 0; c < cols; c++ ) {
+ NodeItem *ni = new NodeItem( graph );
+ ni->setAnimated( TRUE );
+ nodecount++;
+ ni->move(rand()%(graph->canvas->width()-ni->width()),rand()%(graph->canvas->height()-ni->height()));
+
+ if ( r > 0 )
+ (new EdgeItem( lastRow[c], ni, graph->canvas ))->show();
+ if ( prev )
+ (new EdgeItem( prev, ni, graph->canvas ))->show();
+ prev = ni;
+ lastRow[c] = ni;
+ ni->show();
+ }
+ }
+
+ graph->canvas->advance();
+
+ TQCanvasItem* i = new BouncyText( tr( "Drag the nodes around!" ), TQFont("helvetica", 24), graph->canvas);
+ i->show();
+ setCanvas( graph->canvas );
+ setMinimumSize( 600, 400 );
+ setSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding );
+}