ELVE  1
ELVE Logic Visualization Explorer
/home/travis/build/stdgregwar/elve/Core/GraphWidget.cpp
00001 #include "GraphWidget.h"
00002 
00003 #include <QTimerEvent>
00004 #include <QDebug>
00005 #include <cmath>
00006 #include <QWheelEvent>
00007 #include <QOpenGLWidget>
00008 #include <QJsonObject>
00009 #include <QJsonArray>
00010 #include <QPaintEvent>
00011 #include <QTimeLine>
00012 #include <QGridLayout>
00013 
00014 #include <unordered_map>
00015 #include <random>
00016 #include <chrono>
00017 
00018 #include "Point.h"
00019 
00020 #define SS 40960000
00021 
00022 namespace Elve {
00023 
00024 using namespace std;
00025 
00026 constexpr int PLAYICONSIZE = 48;
00027 
00028 std::array<QColor,10> GraphWidget::mSelectionColors = {
00029     Qt::blue,
00030     Qt::red,
00031     Qt::yellow,
00032     Qt::green,
00033     QColor(0, 102, 0), //Dark green
00034     QColor(255, 153, 0), //Orange
00035     QColor(255, 0, 102), //Purple
00036     QColor(0, 0, 255), //Dark blue
00037     QColor(255, 102, 255), //Pink
00038     QColor(128, 0, 0) //Bordeaux
00039 };
00040 
00041 GraphWidget::GraphWidget(QWidget* parent, GraphWidgetListener* listener) : QGraphicsView(parent),
00042     mScene(new QGraphicsScene(-SS,-SS,SS*2,SS*2,this)),
00043     mDrag(false),
00044     mScale(1),
00045     mTargetScale(1),
00046     mBehaviour(new Behaviour(this)),
00047     //mEdgesPath(new QGraphicsPathItem()),
00048     mListener(listener),
00049     mTimerId(-1),
00050     mSim(true)
00051 {
00052     mPlayPauseIcon = new QGraphicsPixmapItem();
00053     mPlayPauseIcon->setPixmap(QIcon(":resources/play.svg").pixmap(PLAYICONSIZE,PLAYICONSIZE));
00054     mPlayPauseIcon->setFlag(QGraphicsItem::ItemIgnoresTransformations);
00055     mPlayPauseIcon->setPos(20,50);
00056     mPlayPauseIcon->setZValue(2);
00057     mScene->addItem(mPlayPauseIcon);
00058 
00059     mSelectionBox = new QComboBox(this);
00060     mSelectionBox->setGeometry(20,20,100,20);
00061     for(int i = 0; i < mSelectionColors.size(); i++) {
00062         mSelectionBox->addItem("Mask " + QString::number(i));
00063     }
00064 
00065     connect(mSelectionBox,SIGNAL(activated(int)),this,SLOT(setCurrentMask(int)));
00066     connect(this,SIGNAL(maskChanged(int)),mSelectionBox,SLOT(setCurrentIndex(int)));
00067 
00068     setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
00069     setDragMode(QGraphicsView::ScrollHandDrag);
00070     setGeometry(0,0,1280,720);
00071     setScene(mScene);
00072     setBackgroundBrush(QBrush(QColor(59,58,58), Qt::SolidPattern));
00073 
00074 }
00075 
00076 void GraphWidget::start() {
00077     mTimerId = startTimer(1000/60);
00078     show();
00079 }
00080 
00081 void GraphWidget::stop() {
00082     if(mTimerId != -1) {
00083         killTimer(mTimerId);
00084         mTimerId = -1;
00085     }
00086     hide();
00087 }
00088 
00089 void GraphWidget::toggleSim(bool sim) {
00090     mSim = !sim;
00091     mPlayPauseIcon->setPixmap(
00092                 QIcon(mSim ? ":resources/play.svg" : ":resources/pause.svg")
00093                 .pixmap(PLAYICONSIZE,PLAYICONSIZE));
00094 }
00095 
00096 void GraphWidget::setCurrentMask(int i) {
00097     mGraph->setMask(i);
00098     updateSelectionColor();
00099 }
00100 
00101 void GraphWidget::fit() {
00102     //fitInView(mScene->itemsBoundingRect(),Qt::KeepAspectRatio);
00103     fitInView(mGraph->layout()->system().sizeHint(),Qt::KeepAspectRatio);
00104 }
00105 
00106 void GraphWidget::init()
00107 {
00108 }
00109 
00110 void GraphWidget::showEvent(QShowEvent *event)
00111 {
00112     QGraphicsView::showEvent(event);
00113     init();
00114 }
00115 
00116 void GraphWidget::clear() {
00117     mEdges.clear();
00118     mNodes.clear();
00119 }
00120 
00121 void GraphWidget::setGraph(SharedEGraph graph, unsigned quickTicks) {
00122     unsetGraph();
00123 
00124     mListener->graphChanged(mGraph,graph);
00125     mGraph = graph;
00126     mGraph->setView(this);
00127     if(graph->layout() && graph->look()) {
00128         //graph->applyLayout();
00129         reflect(graph->layout()->system(),graph->graph(),graph->look());
00130         quickSim(quickTicks);
00131 
00132         mScene->setSceneRect(graph->layout()->system().sizeHint());
00133     }
00134     updateSelectionColor();
00135 }
00136 
00137 QGraphicsScene* GraphWidget::scene() {
00138     return mScene;
00139 }
00140 
00141 void GraphWidget::quickSim(unsigned ticks)
00142 {
00143     if(mGraph && mGraph->layout())
00144         mGraph->layout()->quickSim(ticks);
00145 }
00146 
00147 void GraphWidget::drawBackground(QPainter *painter, const QRectF &rect){
00148     QGraphicsView::drawBackground(painter,rect);
00149     if(mGraph->layout()) {
00150         painter->setPen(QPen(Qt::gray));
00151         //mGraph->layout()->system().debug(painter);
00152         painter->drawRect(mGraph->layout()->system().sizeHint());
00153     }
00154     //painter->fillRect(rect,Qt::CrossPattern);
00155 }
00156 
00157 void GraphWidget::drawForeground(QPainter *painter, const QRectF &rect) {
00158     //painter->drawText(QPointF{20,20},QString("selection : %1").arg(QString::number(mGraph->mask())));
00159     QImage img = QIcon(":resources/lock.svg").pixmap(QSize(64,64)).toImage();
00160     for(const PointsByID::value_type& p : mGraph->layout()->system().pinnedPoints()) {
00161         const QVector2D& pos = p.second->pos();
00162         painter->drawImage(QPointF(pos.x(),pos.y()),img);
00163     }
00164 }
00165 
00166 void GraphWidget::paintEvent(QPaintEvent* ev) {
00167     mPlayPauseIcon->setPos(mapToScene(20,50));
00168     QGraphicsView::paintEvent(ev);
00169 }
00170 
00171 void GraphWidget::wheelEvent(QWheelEvent *event)
00172 {
00173     //setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
00174 
00175     const QPoint degrees = event->angleDelta()/ 8;
00176     const int steps = degrees.y() / 15;
00177     const float scalebase = sqrt(2);
00178     float s = pow(scalebase,steps);
00179     mTargetScale*=s;
00180     event->accept();
00181     //QGraphicsView::wheelEvent(event);
00182 }
00183 
00184 void GraphWidget::borderSelect() {
00185     setBehaviour(new BorderSelect(this));
00186 }
00187 
00188 void GraphWidget::mousePressEvent(QMouseEvent *event)
00189 {
00190     if(!mBehaviour || !mBehaviour->mousePressEvent(event)) {
00191         if(event->button() == Qt::RightButton) {
00192             QList<QGraphicsItem*> items = mScene->items(mapToScene(event->pos()));
00193             NodeIDSet names;
00194             for(QGraphicsItem* i : items) {
00195                 NodeLook* n = dynamic_cast<NodeLook*>(i);
00196                 if(n) {
00197                     names.insert(n->node().id());
00198                 }
00199             }
00200             SelectionMode mode = CLEAR;
00201             if(event->modifiers() & Qt::ShiftModifier) mode = ADD;
00202             if(event->modifiers() & Qt::ControlModifier) mode = SUB;
00203             select(names,mode);
00204         }
00205         QGraphicsView::mousePressEvent(event);
00206     }
00207 }
00208 
00209 void GraphWidget::mouseReleaseEvent(QMouseEvent *event)
00210 {
00211     if(!mBehaviour || !mBehaviour->mouseReleaseEvent(event)) {
00212         QGraphicsView::mouseReleaseEvent(event);
00213     }
00214 }
00215 
00216 void GraphWidget::mouseMoveEvent(QMouseEvent *event)
00217 {
00218     if(!mBehaviour || !mBehaviour->mouseMoveEvent(event)) {
00219         QGraphicsView::mouseMoveEvent(event);
00220     }
00221 }
00222 
00223 void GraphWidget::mouseDoubleClickEvent(QMouseEvent* event) { //TEMP ungroup feature
00224 }
00225 
00226 void GraphWidget::keyPressEvent(QKeyEvent *event) {
00227     QGraphicsView::keyPressEvent(event);
00228     if(event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) {
00229         mGraph->setMask(event->key()-Qt::Key_0);
00230         emit maskChanged(event->key()-Qt::Key_0);
00231         updateSelectionColor();
00232         mListener->selectionChanged(mGraph);
00233     }
00234 }
00235 
00236 void GraphWidget::quickSim() {
00237     quickSim(500);
00238 }
00239 
00240 void GraphWidget::group() {
00241     qDebug() << "grouping!";
00242     //group(mGraph->currentSelection());
00243     mListener->runCommand(QString("group -m %1").arg(mGraph->mask()));
00244 }
00245 
00246 void GraphWidget::ungroup() {
00247     //ungroup(mGraph->currentSelection());
00248     mListener->runCommand(QString("ungroup -m %1").arg(mGraph->mask()));
00249 }
00250 
00251 void GraphWidget::toggleSelection() {
00252     Selection& s = mGraph->currentSelection();
00253     QString cmd = QString("select %1").arg(QString::number(mGraph->mask()));
00254     if(s.size() == 0) {
00255         cmd += " -a";
00256     } else {
00257         //s.clear();
00258         cmd += " -c";
00259 
00260     }
00261     mListener->runCommand(cmd);
00262     //updateSelectionColor();
00263 }
00264 
00265 void GraphWidget::ungroup(const NodeIDSet& names) {
00266     setGraph(mGraph->ungroup(names),0);
00267 }
00268 
00269 void GraphWidget::group(const Selection &names, const NodeName &groupName) {
00270     if(names.empty()) return;
00271     NodeIDSet inputs;
00272     NodeIDSet nonio;
00273     NodeIDSet outputs;
00274     for(const NodeID& id : names) {
00275         qDebug() << "id" << id;
00276         const Node& nd = mGraph->graph()->nodes().at(id);
00277         switch(nd.type()) {
00278         case INPUT:
00279             inputs.insert(id);
00280             break;
00281         case OUTPUT:
00282             outputs.insert(id);
00283             break;
00284         default:
00285             nonio.insert(id);
00286             break;
00287         }
00288     }
00289     SharedEGraph eg = mGraph->group(nonio,groupName)
00290             ->group(inputs,groupName)
00291             ->group(outputs,groupName);
00292     setGraph(eg,0);
00293 }
00294 
00295 void GraphWidget::tick(float dt, bool update)
00296 {
00297 
00298     if(mGraph->layout()) {
00299         mGraph->layout()->tick(dt,update);
00300         /*QPainterPath p;
00301         std::for_each(mEdges.begin(),mEdges.end(),[&p](EdgeLook*& e){
00302             e->addToPath(p);
00303         });
00304         mEdgesPath->setPath(p);*/
00305     }
00306 }
00307 
00308 void GraphWidget::timerEvent(QTimerEvent *e)
00309 {
00310     if(mSim) tick(0.25);
00311 
00312 
00313     updateEdges();
00314 
00315     qreal oldScale= mScale;
00316     mScale = 0.8*mScale+0.2*mTargetScale;
00317     qreal factor = mScale/oldScale;
00318     if(abs(1-factor)>1e-3) {
00319         scale(factor,factor);
00320     }
00321 }
00322 
00323 void GraphWidget::setBehaviour(Behaviour* b) {
00324     if(mBehaviour) {
00325         mBehaviour->onEnd();
00326         delete mBehaviour;
00327     }
00328     b->onStart();
00329     mBehaviour = b;
00330 }
00331 
00332 void GraphWidget::setLayout(const SharedLayout& l) {
00333     mGraph->setLayout(l);
00334     setSceneRect(l->system().sizeHint());
00335     //reflect(mGraph->layout()->system(),mGraph->graph());
00336 }
00337 
00338 void GraphWidget::clearScene() {
00339     clearEdgesPaths();
00340     mScene->removeItem(mPlayPauseIcon);
00341     mScene->clear();
00342     mScene->addItem(mPlayPauseIcon);
00343     for_each(mEdges.begin(),mEdges.end(),[](EdgeLook* e){delete e;});
00344     mEdges.clear();
00345     mNodes.clear();
00346 }
00347 
00348 void GraphWidget::reflect(System &sys, SharedGraph g, SharedLook lf) {
00349     clearScene();
00350 
00351     qDebug() << "Reflecting" << lf->lookName();
00352 
00353     setSceneRect(sys.sizeHint());
00354 
00355     unordered_map<NodeID,NodeLook*> looks;
00356 
00357     for(auto& nbi : g->nodes()) {
00358         const Node& n = nbi.second;
00359         NodeLook* ni = lf->node(n);
00360         looks[n.id()] = ni;
00361         mNodes.push_back(ni);
00362         Point* p = sys.point(n.id());
00363         p->clearMovables();
00364         p->addMovable(ni);
00365         mScene->addItem(ni);
00366     }
00367 
00368     for(auto& nbi : g->nodes()) {
00369         const Node& n = nbi.second;
00370         for(const Node::Connexion& c : n.fanIn()) {
00371             const NodeLook& al = *looks.at(c.node->id());
00372             const NodeLook& ll = *looks.at(n.id());
00373             EdgeLook* ei = lf->edge(al,c.from,ll,c.to);
00374             //Point* ep = sys.point(c.node->id());
00375             mEdges.push_back(ei);
00376         }
00377     }
00378     updateSelectionColor();
00379     qDebug() << "Reflected";
00380 }
00381 
00382 /*
00383  * BORDER SELECT BEHAVIOUR
00384  */
00385 
00386 GraphWidget::BorderSelect::BorderSelect(GraphWidget* parent) : Behaviour(parent) {
00387 
00388 }
00389 
00390 void GraphWidget::BorderSelect::onStart() {
00391     QPen dashPen = QPen(QColor(200,200,200));
00392     dashPen.setStyle(Qt::DashLine);
00393     mRectangle = gw.mScene->addRect({0,0,0,0},
00394                                     dashPen);
00395     mCross = gw.mScene->addPath(QPainterPath(),dashPen);
00396 }
00397 
00398 bool GraphWidget::BorderSelect::mousePressEvent(QMouseEvent *event) {
00399     gw.mScene->removeItem(mCross);
00400     //delete mCross;
00401     mCross = nullptr;
00402     mRectangle->setPos(gw.mapToScene(event->pos()));
00403     return true;
00404 }
00405 
00406 
00407 bool GraphWidget::BorderSelect::mouseReleaseEvent(QMouseEvent *event) {
00408     QList<QGraphicsItem*> items = gw.mScene->items(mRectangle->sceneBoundingRect());
00409     NodeIDSet names;
00410     for(QGraphicsItem* i : items) {
00411         NodeLook* n = dynamic_cast<NodeLook*>(i);
00412         if(n) {
00413             names.insert(n->node().id());
00414         }
00415     }
00416     SelectionMode mode = CLEAR;
00417     if(event->modifiers() & Qt::ShiftModifier) mode = ADD;
00418     if(event->modifiers() & Qt::ControlModifier) mode = SUB;
00419     gw.select(names,mode);
00420     //gw.group(names);
00421     gw.setBehaviour(new Behaviour(&gw));
00422     gw.mScene->removeItem(mRectangle);
00423     return true;
00424 }
00425 
00426 void GraphWidget::select(const NodeIDSet& names, SelectionMode mode) {
00427     if(names.empty()) return;
00428     QString cmd = QString("select");
00429     switch(mode) {
00430     case CLEAR:
00431         cmd += " -c";
00432         break;
00433     case ADD:
00434         cmd += " --add";
00435         break;
00436     case SUB:
00437         cmd += " --sub";
00438         break;
00439     default:
00440         break;
00441     }
00442 
00443     cmd += QString(" %1").arg(QString::number(mGraph->mask()));
00444     for(const NodeID& id : names) {
00445         cmd += " " + QString::number(id);
00446     }
00447     mListener->runCommand(cmd);
00448 }
00449 
00450 void GraphWidget::updateSelectionColor() {
00451     Selection& s = mGraph->currentSelection();
00452     for(NodeLook* i : mNodes) {
00453         if(s.count(i->node().id())) {
00454             i->color(mSelectionColors[mGraph->mask()]);
00455         } else {
00456             i->color(QColor());
00457         }
00458     }
00459 }
00460 
00461 void GraphWidget::flushPen(QPen& pen, QPainterPath& path, const QPen &newPen) {
00462     //Flush in pathitem
00463     if(path.length() > 0.f) {
00464         QGraphicsPathItem* pitem = new QGraphicsPathItem(path);
00465         mScene->addItem(pitem);
00466         pitem->setPen(pen);
00467         mEdgesPaths.push_back(pitem);
00468         path = QPainterPath(); //clear path
00469     }
00470     pen = newPen;
00471 }
00472 
00473 void GraphWidget::clearEdgesPaths() {
00474     for(QGraphicsPathItem* p : mEdgesPaths) {
00475         mScene->removeItem(p);
00476         delete p;
00477     }
00478     mEdgesPaths.clear();
00479 }
00480 
00481 void GraphWidget::updateEdges() {
00482     clearEdgesPaths();
00483 
00484     QPen pen;
00485     QPainterPath path;
00486     for(EdgeLook* e : mEdges) {
00487         if(pen != e->pen()) {
00488             flushPen(pen,path,e->pen());
00489         }
00490         e->addToPath(path);
00491     }
00492     flushPen(pen,path,QPen());
00493 }
00494 
00495 bool GraphWidget::BorderSelect::mouseMoveEvent(QMouseEvent *event) {
00496     float inf = 800000; //TODO cross
00497     QPointF pos = gw.mapToScene(event->pos());
00498     if(mCross) {
00499 
00500     } else {
00501         QPointF origin = mRectangle->pos();
00502         mRectangle->setRect(0,0,
00503                             (pos.x()-origin.x()),(pos.y()-origin.y()));
00504     }
00505     return true;
00506 }
00507 
00508 const SharedEGraph& GraphWidget::graph() const
00509 {
00510     return mGraph;
00511 }
00512 
00513 void GraphWidget::BorderSelect::onEnd() {
00514     if(mCross) {
00515         gw.mScene->removeItem(mCross);
00516         //delete mCross;
00517     }
00518     //gw.mScene->removeItem(mRectangle);
00519     //delete mRectangle;
00520 }
00521 
00522 void GraphWidget::unsetGraph() {
00523     if(mGraph) {
00524         mGraph->setView(nullptr);
00525         if(mGraph->layout()) {
00526             mGraph->layout()->system().clearMovables();
00527         }
00528     }
00529 }
00530 
00531 GraphWidget::~GraphWidget() {
00532     unsetGraph();
00533 }
00534 
00535 }
 All Classes Functions