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),
00034 QColor(255, 153, 0),
00035 QColor(255, 0, 102),
00036 QColor(0, 0, 255),
00037 QColor(255, 102, 255),
00038 QColor(128, 0, 0)
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
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
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
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
00152 painter->drawRect(mGraph->layout()->system().sizeHint());
00153 }
00154
00155 }
00156
00157 void GraphWidget::drawForeground(QPainter *painter, const QRectF &rect) {
00158
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
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
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) {
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
00243 mListener->runCommand(QString("group -m %1").arg(mGraph->mask()));
00244 }
00245
00246 void GraphWidget::ungroup() {
00247
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
00258 cmd += " -c";
00259
00260 }
00261 mListener->runCommand(cmd);
00262
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
00301
00302
00303
00304
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
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
00375 mEdges.push_back(ei);
00376 }
00377 }
00378 updateSelectionColor();
00379 qDebug() << "Reflected";
00380 }
00381
00382
00383
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
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
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
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();
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;
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
00517 }
00518
00519
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 }