Developer Documentation
graphicsScene.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 //== INCLUDES =================================================================
46 #include "graphicsScene.hh"
47 #include "graphicsView.hh"
48 #include "sceneElement.hh"
49 #include "sceneTools.hh"
50 #include "elementArea.hh"
51 
52 #include "elementInput.hh"
53 #include "elementOutput.hh"
54 #include "elementFunction.hh"
55 #include "connection.hh"
56 #include "connectionPoint.hh"
57 #include "wayfind.hh"
58 
59 #include "baseWidget.hh"
60 
61 #include <QApplication>
62 #include <QPaintEngine>
63 #include <QMimeData>
64 
65 #include <QXmlResultItems>
66 
67 #include "../parser/context.hh"
68 #include "../parser/output.hh"
69 #include "../parser/function.hh"
70 
71 #define SELECTION_RED 0x00
72 #define SELECTION_GREEN 0x00
73 #define SELECTION_BLUE 0x7f
74 #define SELECTION_ALPHA 0x7f
75 
76 //== NAMESPACES ===============================================================
77 namespace VSI {
78 
79 //=============================================================================
80 //
81 // CLASS VSI::GraphicsScene - IMPLEMENTATION
82 //
83 //=============================================================================
84 
87  QGraphicsScene (),
88  ctx_ (_ctx),
89  function_ (_function),
90  dndElement_ (0),
91  elementArea_ (0),
92  selectionActive_ (false),
93  blockChanges_ (false),
94  activeConnection_ (0),
95  currentZ_ (0)
96 {
97  // tools area
98  tools_ = new SceneTools (this);
99  addItem (tools_);
100  tools_->setZValue (10);
101 
102  // selecion item
103  selection_ = new QGraphicsRectItem ();
104  addItem (selection_);
105  selection_->setZValue (1);
106  selection_->hide ();
107 
108  selection_->setBrush(QBrush(QColor(SELECTION_RED,
109  SELECTION_GREEN,
110  SELECTION_BLUE,
111  SELECTION_ALPHA / 2)));
112 
113  selection_->setPen(QColor(SELECTION_RED,
114  SELECTION_GREEN,
115  SELECTION_BLUE,
116  SELECTION_ALPHA));
117 
118  elementArea_ = new ElementArea (this);
119  addItem (elementArea_);
120  elementArea_->setZValue (0.0);
121 
122  // add start and end
123  if (!function_)
124  {
125  SceneElement *end = new SceneElement (this, ctx_->element ("end"));
126  addElement (end);
127  SceneElement *start = new SceneElement (this, ctx_->element ("start"));
128  addElement (start);
129  }
130  else
131  {
132  SceneElement *end = new SceneElement (this, function_->function ()->end ());
133  addElement (end);
134  SceneElement *start = new SceneElement (this, function_->function ()->start ());
135  addElement (start);
136  }
137 
138  // initalize wayfinding
139  wayFind_ = new WayFind (this);
140 
141  view_ = new GraphicsView ();
142  view_->setScene (this);
143  view_->setRenderHint (QPainter::Antialiasing, true);
144 
147 
148  connect (this, SIGNAL(sceneRectChanged( const QRectF& )), this, SLOT(sceneResized(const QRectF&)));
149  dontMoveStart_ = false;
150 }
151 
152 //------------------------------------------------------------------------------
153 
156 {
157  delete wayFind_;
158 
161  view_->deleteLater ();
162 }
163 
164 //------------------------------------------------------------------------------
165 
166 // draw background
167 void GraphicsScene::drawBackground(QPainter *_painter, const QRectF &_rect)
168 {
169  QGraphicsScene::drawBackground (_painter, _rect);
170 }
171 
172 //------------------------------------------------------------------------------
173 
174 // drag enter
175 void GraphicsScene::dragEnterEvent (QGraphicsSceneDragDropEvent *_event)
176 {
177  // create scene element if mimedata is valid
178  if (validMimeData (_event->mimeData ()) && !dndElement_ && ctx_->element (mimeDataElementName (_event->mimeData ())))
179  {
180  dndElement_ = new SceneElement (this, ctx_->element (mimeDataElementName (_event->mimeData ())));
181  dndElement_->setOpacity (0.5);
182  addElement (dndElement_);
183 
184  QPoint off = mimeDataPoint (_event->mimeData ());
185 
186  QPointF p = elementArea_->mapFromScene (_event->scenePos ().x (), _event->scenePos ().y ());
187  dndElement_->setPos (p.x () - (dndElement_->size ().width () / 2) - off.x(),
188  p.y () - (dndElement_->size ().height () / 2) - off.y());
189 
190  }
191  else
192  _event->ignore ();
193 
194 }
195 
196 //------------------------------------------------------------------------------
197 
198 // drag leave
199 void GraphicsScene::dragLeaveEvent (QGraphicsSceneDragDropEvent *_event)
200 {
201  // destroy created scene element
202  if (validMimeData (_event->mimeData ()) && dndElement_)
203  {
204  tools_->mouseRelease (_event->scenePos (), dndElement_);
205  removeElement (dndElement_);
206  delete dndElement_;
207  dndElement_ = NULL;
208  }
209  else
210  _event->ignore ();
211 }
212 
213 //------------------------------------------------------------------------------
214 
215 // drag move
216 void GraphicsScene::dragMoveEvent (QGraphicsSceneDragDropEvent *_event)
217 {
218  // update position of dragged element
219  if (validMimeData (_event->mimeData ()) && dndElement_)
220  {
221  QPoint off = mimeDataPoint (_event->mimeData ());
222  QPointF p = elementArea_->mapFromScene (_event->scenePos ().x (), _event->scenePos ().y ());
223  dndElement_->setPos (p.x () - (dndElement_->size ().width () / 2) - off.x (),
224  p.y () - (dndElement_->size ().height () / 2) - off.y ());
225 
226  tools_->mouseMove (_event->scenePos ());
227  }
228  else
229  _event->ignore ();
230 }
231 
232 //------------------------------------------------------------------------------
233 
234 // drop
235 void GraphicsScene::dropEvent (QGraphicsSceneDragDropEvent *_event)
236 {
237  // leave dropped element in scene
238  if (validMimeData (_event->mimeData ()) && dndElement_)
239  {
240  tools_->mouseRelease (_event->scenePos (), dndElement_);
241  dndElement_->setOpacity (1.0);
242  dndElement_ = NULL;
243  contentChange ();
244  }
245  else
246  _event->ignore ();
247 }
248 
249 //------------------------------------------------------------------------------
250 
253 {
254  currentZ_ += 0.01;
255  return currentZ_;
256 }
257 
258 //------------------------------------------------------------------------------
259 
261 void GraphicsScene::moveElements (qreal _dx, qreal _dy, bool _selected)
262 {
263  elementArea_->moveBy (_dx, _dy);
264  if (_selected)
265  return;
266 
267  contentChange ();
268  foreach (QGraphicsItem *e, elementArea_->elements ())
269  if (e->isSelected ())
270  {
271  QPointF p = elementArea_->mapFromScene (0, 0) -
272  elementArea_->mapFromScene (_dx, _dy);
273  e->moveBy (p.x (), p.y ());
274  }
275 }
276 
277 //------------------------------------------------------------------------------
278 
280 void GraphicsScene::scaleElements (qreal _delta)
281 {
282  QRectF rect = sceneRect();
283  scaleElements (_delta, QPointF (rect.x () + (rect.width () / 2.0),
284  rect.y () + (rect.height () / 2.0)));
285 }
286 
287 //------------------------------------------------------------------------------
288 
290 void GraphicsScene::scaleElements (qreal _delta, QPointF _center)
291 {
292  QPointF p(elementArea_->mapFromScene (_center.x (), _center.y ()));
293  elementArea_->setTransform(QTransform().translate(p.x (), p.y ()).scale(_delta, _delta).translate(-p.x (), -p.y ()), true);
294 }
295 
296 //------------------------------------------------------------------------------
297 
300 {
301  contentChange ();
302  addItem (_element);
303  elementArea_->addElement (_element);
304 }
305 
306 //------------------------------------------------------------------------------
307 
310 {
311  contentChange ();
312  bool rv = elementArea_->removeElement (_element);
313  if (rv)
314  removeItem (_element);
315 
316  return rv;
317 }
318 
319 //------------------------------------------------------------------------------
320 
322 void GraphicsScene::mouseMove (QPointF _pos)
323 {
324  tools_->mouseMove (_pos);
325 }
326 
327 //------------------------------------------------------------------------------
328 
330 void GraphicsScene::mouseRelease (QPointF _pos, QGraphicsItem *_item)
331 {
332  tools_->mouseRelease (_pos, _item);
333 }
334 
335 //------------------------------------------------------------------------------
336 
338 {
339  if (elementArea_)
340  return elementArea_->mapToScene (elementArea_->childrenBoundingRect ()).boundingRect ();
341  else
342  return QRectF ();
343 }
344 
345 //------------------------------------------------------------------------------
346 
348 const QList<SceneElement *>& GraphicsScene::elements () const
349 {
350  return elementArea_->elements ();
351 }
352 
353 //------------------------------------------------------------------------------
354 
355 // start selection rectangle if pressing on empty area of scene
356 void GraphicsScene::mousePressEvent (QGraphicsSceneMouseEvent *_event)
357 {
358  QPainterPath p;
359 
360  foreach (QGraphicsItem *e, selectedItems ())
361  p += e->mapToScene (e->shape ());
362 
363  QGraphicsScene::mousePressEvent (_event);
364  selectionStart_ = _event->scenePos ();
365 
366  if (itemAt (selectionStart_,QTransform()) != elementArea_ && !_event->isAccepted ())
367  {
368  if (_event->modifiers () & (Qt::ControlModifier | Qt::ShiftModifier))
369  setSelectionArea (p);
370 
371  selectionActive_ = true;
372  selection_->setRect (QRectF (selectionStart_, QSizeF (0, 0)));
373  selection_->show ();
374  _event->accept ();
375  }
376 
377  dontMoveStart_ = true;
378 }
379 
380 //------------------------------------------------------------------------------
381 
382 // update selection rectangle
383 void GraphicsScene::mouseMoveEvent (QGraphicsSceneMouseEvent *_event)
384 {
385  if (selectionActive_)
386  {
387  selection_->setRect (QRectF (selectionStart_, _event->scenePos ()).normalized ());
388  _event->accept ();
389  }
390  else if (activeConnection_)
391  {
392  activeConnection_->mouseMoveEvent (_event);
393  }
394  else
395  QGraphicsScene::mouseMoveEvent (_event);
396 }
397 
398 //------------------------------------------------------------------------------
399 
400 // select all elements in selection rectangle
401 void GraphicsScene::mouseReleaseEvent (QGraphicsSceneMouseEvent *_event)
402 {
403  if (selectionActive_)
404  {
405  selection_->hide ();
406  QPainterPath p;
407 
408  p.addRect (QRectF (selectionStart_, _event->scenePos ()).normalized ());
409 
410  if (_event->modifiers () == Qt::ControlModifier)
411  {
412  p += selectionArea ();
413  setSelectionArea (p);
414  }
415  else if (_event->modifiers () == Qt::ShiftModifier)
416  {
417  foreach (QGraphicsItem *e, items (QRectF (selectionStart_, _event->scenePos ()).normalized ()))
418  if (e->isSelected ())
419  e->setSelected (false);
420  }
421  else
422  setSelectionArea (p);
423 
424  selectionActive_ = false;
425 
426  _event->accept ();
427  }
428  if (activeConnection_)
429  {
430  activeConnection_->mouseReleaseEvent (_event);
431  }
432 
433  QGraphicsScene::mouseReleaseEvent (_event);
434 }
435 
436 //------------------------------------------------------------------------------
437 
438 // returns all scene elements. Also all elements of sub-functions
439 QList<SceneElement *> GraphicsScene::getAllElements()
440 {
441  QList<SceneElement *> rv;
442 
443  foreach (SceneElement *e, elementArea_->elements ())
444  {
445  rv.append (e);
446  foreach (ElementFunction *ef, e->functions ())
447  {
448  rv.append (ef->scene ()->getAllElements ());
449  }
450  }
451 
452  return rv;
453 }
454 
455 //------------------------------------------------------------------------------
456 
458 QString GraphicsScene::generateCode (QString &errors, bool _codeOnly)
459 {
460  QString rv = "";
461 
462  // only code block for functions
463  if (!_codeOnly)
464  {
465  // collect all elements and functions
466  QSet<Element *> set;
467  QList<ElementFunction *> functions;
468 
469  foreach (SceneElement *e, getAllElements ())
470  {
471  set.insert (e->element ());
472  foreach (ElementFunction *ef, e->functions ())
473  functions.append (ef);
474  }
475 
476  // add precode block for each element only once
477  foreach (Element *e, set)
478  if (!e->precode ().isEmpty ())
479  {
480  rv += "// - ";
481  rv += e->shortDescription ();
482  rv += " -\n";
483  rv += e->precode ();
484  rv += "\n";
485  }
486 
487  // add functiond
488  if (!functions.isEmpty ())
489  {
490  rv += "// ------- FUNCTIONS -----------\n\n";
491  }
492 
493  foreach (ElementFunction *ef, functions)
494  {
495  rv += "// - ";
496  rv += ef->element ()->element ()->shortDescription ();
497  rv += " - ";
498  rv += ef->function ()->shortDescription ();
499  rv += " -\n";
500  rv += "function func_" + ef->element ()->variableId () + "_" + ef->function ()->name ();
501 
502  QString param;
503  foreach (Output *o, ef->function ()->start ()->outputs ())
504  {
505  param += o->name () + ", ";
506  }
507 
508  if (!param.isEmpty ())
509  param.remove (param.length () - 2, 2);
510 
511  rv += " (" + param + ")\n{\n";
512 
513  QString code = ef->scene ()->generateCode (errors, true);
514 
515  rv += code + "}\n\n";
516  }
517 
518  if (!functions.isEmpty ())
519  {
520  rv += "// ------- END FUNCTIONS -------\n\n";
521  }
522  }
523 
524 
525  QList<SceneElement *> elements = elementArea_->elements ();
526 
527  SceneElement *start = 0;
528  SceneElement *end = 0;
529 
530  // reset code block of all elements and find start element
531  foreach (SceneElement *e, elements)
532  {
533  e->resetCodeGeneration ();
534 
535  if ((!function_ && e->element ()->name () == "start") ||
536  (function_ && function_->function ()->start () == e->element ()))
537  start = e;
538  if ((!function_ && e->element ()->name () == "end") ||
539  (function_ && function_->function ()->end () == e->element ()))
540  end = e;
541  }
542 
543  if (!start)
544  {
545  // should never happen
546  errors += "No start element!";
547  return "";
548  }
549 
550  elements.removeAll (start);
551  elements.removeAll (end);
552 
553  // Ignore empty scenes
554  if (elements.isEmpty() && end->inputs().isEmpty ())
555  end = NULL;
556 
557  rv += "// --- CODE BEGIN ---\n\n";
558 
559  updateConnections (start, true);
560 
561  SceneElement *found = (SceneElement*)1;
562 
563  // iterate over all elements
564  while ((!elements.empty () || end) && found)
565  {
566  found = NULL;
567 
568  // pick element where all inputs are set
569  foreach (SceneElement *e, elements)
570  {
571  bool set = true;
572  foreach (ElementInput *i, e->inputs ())
573  if (!i->valid ())
574  set = false;
575 
576  if (e->dataIn () && !e->dataIn ()->valid ())
577  set = false;
578 
579  if (set)
580  found = e;
581  }
582 
583  if (!found)
584  {
585  bool set = true;
586  foreach (ElementInput *i, end->inputs ())
587  if (!i->valid ())
588  set = false;
589 
590  if (end->dataIn () && !end->dataIn ()->valid ())
591  set = false;
592 
593  // Ignore end elements without inputs
594  if (set)
595  {
596  if (!end->inputs ().isEmpty ())
597  found = end;
598  end = NULL;
599  }
600  }
601 
602  if (found)
603  {
604  elements.removeAll (found);
605 
606  rv += "// - ";
607  rv += found->element ()->shortDescription ();
608  rv += " -\n";
609  rv += updateConnections (found, false);
610 
611  QString dName = "ask_user_output_" + found->variableId();
612  QString dInputs = "";
613 
614  // replace all inputs that are not connected with user defined value or prepare for asking during execution
615  foreach (ElementInput *i, found->inputs ()){
616  if (i->isSet ())
617  {
618  found->replaceCodeBlock ("is_set", i->inOut ()->name (), "true");
619  found->replaceCodeBlock ("input", i->inOut ()->name (), i->value ());
620  }
621  else if (!i->connections ().isEmpty ())
622  {
623  found->replaceCodeBlock ("is_set", i->inOut ()->name (), "true");
624  }
625  else if (i->connections ().isEmpty ())
626  {
627  if (i->state () & Input::Optional && !i->isForceAskSet ())
628  {
629  found->replaceCodeBlock ("input", i->inOut ()->name (), "\"\"");
630  found->replaceCodeBlock ("is_set", i->inOut ()->name (), "false");
631  }
632  else
633  {
634  found->replaceCodeBlock ("is_set", i->inOut ()->name (), "true");
635  found->replaceCodeBlock ("input", i->inOut ()->name (), dName + "." + i->inOut ()->name ());
636  dInputs += i->inOut ()->name () + ",";
637  }
638  }
639 
640  // Replace the is_connected block for inputs as well.
641  if (i->connections ().isEmpty ())
642  found->replaceCodeBlock ("is_connected", i->inOut ()->name (), "false");
643  else
644  found->replaceCodeBlock ("is_connected", i->inOut ()->name (), "true");
645  }
646 
647  foreach (ElementFunction *ef, found->functions ())
648  found->replaceCodeBlock ("function", ef->function ()->name (), "func_" + found->variableId () + "_" + ef->function ()->name ());
649 
650  if (!dInputs.isEmpty ())
651  {
652  // remove last ,
653  dInputs.remove (dInputs.length () - 1, 1);
654  rv += "// Ask user for missing input values\n";
655  rv += "var " + dName + " = visualscripting.askForInputs (\"" + found->element ()->name ();
656  rv += "\", \"" + dInputs + "\");\n";
657  }
658 
659  rv += found->code ();
660  rv += "\n";
661  }
662  }
663 
664  rv += "// --- CODE END ---\n";
665 
666  if (end)
667  elements.append (end);
668 
669  if (!elements.isEmpty ())
670  {
671  // find all elements that have real missing inputs
672  foreach (SceneElement *e, elements)
673  {
674  foreach (ElementOutput *o, e->outputs ())
675  {
676  foreach (Connection *c, o->connections ())
677  if (c->input ())
678  {
679  c->input ()->setValid (true);
680  }
681  }
682 
683  if (e->dataOut ())
684  foreach (Connection *c, e->dataOut ()->connections ())
685  if (c->input ())
686  {
687  c->input ()->setValid (true);
688  break;
689  }
690  }
691 
692  QList<SceneElement *> fixE;
693  foreach (SceneElement *e, elements)
694  {
695  bool set = true;
696  foreach (ElementInput *i, e->inputs ())
697  if (!i->valid ())
698  set = false;
699 
700  if (e->dataIn () && !e->dataIn ()->valid ())
701  set = false;
702 
703  if (!set)
704  fixE.append (e);
705  }
706 
707  errors += "<dl><dt>";
708 
709  if (!function_)
710  errors += "<b>Function: </b>Main";
711  else
712  errors += "<b>Function: </b>" + function_->function ()->shortDescription();
713 
714  errors += "</dt><dd>";
715 
716  foreach (SceneElement *e, fixE)
717  {
718  errors += "<b>Element: </b>" + e->element ()->shortDescription () + " <i>(";
719  foreach (ElementInput *i, e->inputs ())
720  if (!i->valid ())
721  errors += i->inOut ()->shortDescription () + ", ";
722 
723  if (e->dataIn () && !e->dataIn ()->valid ())
724  errors += e->dataIn ()->inOut ()->shortDescription ();
725 
726  if (errors.endsWith (", "))
727  errors.remove (errors.length () - 2, 2);
728  errors += ")</i><br>";
729  }
730 
731  if (errors.endsWith ("<br>"))
732  errors.remove (errors.length () - 4, 4);
733 
734  errors += "<dd></dl>";
735 
736  return "";
737  }
738 
739  // indent code
740  if (!_codeOnly)
741  {
742  QStringList code = rv.split ('\n');
743  QString indent = "";
744  rv.clear ();
745 
746  foreach (QString s, code)
747  {
748  if (s.contains ('}') && !indent.isEmpty ())
749  indent.remove (indent.length () - 2, 2);
750  rv += indent + s + "\n";
751  if (s.contains ('{'))
752  indent += " ";
753  }
754  }
755 
756  return rv;
757 }
758 
759 //------------------------------------------------------------------------------
760 
761 // Mark all inputs that are connected to the outputs of _from as valid
762 QString GraphicsScene::updateConnections (SceneElement *_from, bool _isStart)
763 {
764  QString rv;
765  foreach (ElementOutput *o, _from->outputs ())
766  {
767  QString oName;
768 
769  if (!_isStart)
770  {
771  oName = "output_" + _from->variableId() + "_" + o->inOut ()->name ();
772  rv += "var " + oName + "\n";
773 
774  _from->replaceCodeBlock ("output", o->inOut ()->name (), oName);
775 
776  if (o->connections ().isEmpty ())
777  _from->replaceCodeBlock ("is_connected", o->inOut ()->name (), "false");
778  else
779  _from->replaceCodeBlock ("is_connected", o->inOut ()->name (), "true");
780  }
781  else
782  oName = o->inOut ()->name ();
783 
784  foreach (Connection *c, o->connections ())
785  if (c->input ())
786  {
787  c->input ()->setValid (true);
788  c->input ()->element ()->replaceCodeBlock ("input", c->input ()->inOut ()->name (), oName);
789  }
790  }
791 
792  if (_from->dataOut ())
793  foreach (Connection *c, _from->dataOut ()->connections ())
794  if (c->input ())
795  {
796  c->input ()->setValid (true);
797  break;
798  }
799  return rv;
800 }
801 
802 //------------------------------------------------------------------------------
803 
804 // Checks for supported mimetype
805 bool GraphicsScene::validMimeData(const QMimeData *_m)
806 {
807  return _m->hasFormat ("application/x-openflipper.vsi");
808 }
809 
810 //------------------------------------------------------------------------------
811 
812 // gets the element name from the mimetype data
813 QString GraphicsScene::mimeDataElementName(const QMimeData *_m)
814 {
815  if (!validMimeData (_m))
816  return "";
817  QStringList sl = QString (_m->data ("application/x-openflipper.vsi")).split (";");
818 
819  if (sl.length() != 3)
820  return "";
821 
822  return sl[2];
823 }
824 
825 //------------------------------------------------------------------------------
826 
827 // gets the mouse hotspot from the mimetype data
828 QPoint GraphicsScene::mimeDataPoint(const QMimeData *_m)
829 {
830  if (! validMimeData (_m))
831  return QPoint (0, 0);
832 
833  QStringList sl = QString (_m->data ("application/x-openflipper.vsi")).split (";");
834 
835  if (sl.length() != 3)
836  return QPoint (0, 0);
837 
838  bool ok1, ok2;
839  int x = sl[0].toInt (&ok1);
840  int y = sl[1].toInt (&ok2);
841 
842  if (!ok1 || !ok2)
843  return QPoint (0, 0);
844 
845  return QPoint (x, y);
846 }
847 
848 //------------------------------------------------------------------------------
849 
851 void GraphicsScene::saveToXml (QDomDocument &_doc, QDomElement &_root)
852 {
853  QTransform t = elementArea_->transform ();
854  QDomElement s = _doc.createElement("transform");
855  _root.appendChild(s);
856  QDomText txt = _doc.createTextNode(
857  QString::number (t.m11 ()) + "|" + QString::number (t.m12 ()) + "|" + QString::number (t.m13 ()) + "|" +
858  QString::number (t.m21 ()) + "|" + QString::number (t.m22 ()) + "|" + QString::number (t.m23 ()) + "|" +
859  QString::number (t.m31 ()) + "|" + QString::number (t.m32 ()) + "|" + QString::number (t.m33 ())
860  );
861  s.appendChild(txt);
862 
863  s = _doc.createElement("x");
864  _root.appendChild(s);
865  txt = _doc.createTextNode (QString::number(elementArea_->pos ().x ()));
866  s.appendChild(txt);
867 
868  s = _doc.createElement("y");
869  _root.appendChild(s);
870  txt = _doc.createTextNode (QString::number(elementArea_->pos ().y ()));
871  s.appendChild(txt);
872 
873  QDomElement el = _doc.createElement("elements");
874  _root.appendChild(el);
875 
876  foreach (SceneElement *e, elements ())
877  e->saveToXml (_doc, el);
878 }
879 
880 //------------------------------------------------------------------------------
881 
883 void VSI::GraphicsScene::loadFromXml (QXmlQuery &_xml)
884 {
885  clearScene (true);
886 
887  QStringList sl = Context::getXmlString (_xml, "transform/string(text ())").split ("|");
888 
889  qreal m[9];
890 
891  if (sl.length () == 9)
892  {
893  bool ok;
894  for (unsigned int i = 0; i < 9; i++)
895  {
896  m[i] = sl[i].toDouble (&ok);
897  if (!ok)
898  break;
899  }
900  if (ok)
901  elementArea_->setTransform (QTransform (m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]), false);
902  }
903 
904  bool ok1, ok2;
905  double x, y;
906  QString val;
907 
908  val = Context::getXmlString (_xml, "x/string(text())");
909  x = val.toDouble (&ok1);
910 
911  val = Context::getXmlString (_xml, "y/string(text())");
912  y = val.toDouble (&ok2);
913 
914  if (ok1 && ok2)
915  elementArea_->setPos (x, y);
916 
917  _xml.setQuery ("elements/element");
918 
919  QXmlResultItems el;
920 
921  if (_xml.isValid ())
922  {
923  _xml.evaluateTo (&el);
924  QXmlItem item (el.next ());
925  while (!item.isNull ())
926  {
927  QXmlQuery q (_xml);
928  q.setFocus (item);
929  loadElement (q);
930  item = el.next ();
931  }
932  }
933 
934  _xml.setQuery ("elements/element/inputs/input/connection");
935 
936  if (_xml.isValid ())
937  {
938  _xml.evaluateTo (&el);
939  QXmlItem item (el.next ());
940  while (!item.isNull ())
941  {
942  QXmlQuery q (_xml);
943  q.setFocus (item);
944  loadConnection (q);
945  item = el.next ();
946  }
947  }
948 
949  QTimer::singleShot(0, this, SLOT (updateConnections()));
950 }
951 
952 //------------------------------------------------------------------------------
953 
954 // load element from xml
955 void GraphicsScene::loadElement(QXmlQuery & _xml)
956 {
957  QString name = Context::getXmlString (_xml, "string(@name)");
958  if (name.isEmpty () || !ctx_->element (name))
959  return;
960 
961  SceneElement *e = new SceneElement (this, ctx_->element (name));
962  addElement (e);
963 
964  e->loadFromXml (_xml);
965 }
966 
967 //------------------------------------------------------------------------------
968 
969 // load connection from xml
970 void GraphicsScene::loadConnection(QXmlQuery & _xml)
971 {
972  bool ok;
973  int inId, outId;
974 
975  QString inEl = Context::getXmlString (_xml, "../../../string(@name)");
976  QString inElId = Context::getXmlString (_xml, "../../../id/string(text ())");
977  QString inIn = Context::getXmlString (_xml, "../string(@name)");
978 
979  inId = inElId.toInt (&ok);
980  if (!ok)
981  return;
982 
983  QString outEl = Context::getXmlString (_xml, "string(@element)");
984  QString outElId = Context::getXmlString (_xml, "string(@element_id)");
985  QString outOut = Context::getXmlString (_xml, "string(@output)");
986 
987  outId = outElId.toInt (&ok);
988  if (!ok)
989  return;
990 
991  SceneElement *in = NULL, *out = NULL;
992 
993  foreach (SceneElement *e, elements ())
994  {
995  if (e->element ()->name () == inEl && e->id () == inId)
996  in = e;
997  else if (e->element ()->name () == outEl && e->id () == outId)
998  out = e;
999  }
1000 
1001  if (!in || !out)
1002  return;
1003 
1004  ConnectionPoint *p1 = NULL, *p2 = NULL;
1005 
1006  if (in->dataIn () && in->dataIn ()->inOut ()->name () == inIn &&
1007  out->dataOut () && out->dataOut ()->inOut ()->name () == outOut)
1008  {
1009  p1 = in->dataIn ()->connectionPointItem ();
1010  p2 = out->dataOut ()->connectionPointItem ();
1011  }
1012  else
1013  {
1014  foreach (ElementInput *i, in->inputs())
1015  if (i->inOut ()->name () == inIn)
1016  {
1017  p1 = i->connectionPointItem ();
1018  break;
1019  }
1020 
1021  foreach (ElementOutput *o, out->outputs())
1022  if (o->inOut ()->name () == outOut)
1023  {
1024  p2 = o->connectionPointItem ();
1025  break;
1026  }
1027  }
1028 
1029  if (p1 && p2)
1030  new Connection (p1, p2, this);
1031 }
1032 
1033 //------------------------------------------------------------------------------
1034 
1036 void GraphicsScene::clearScene (bool _start)
1037 {
1038  elementArea_->resetTransform ();
1039  elementArea_->setPos (0, 0);
1040  foreach (SceneElement *e, elements())
1041  {
1042  bool rv = elementArea_->removeElement (e, true);
1043  if (rv)
1044  {
1045  removeItem (e);
1046  delete e;
1047  }
1048  }
1049  if (!_start)
1050  {
1051  if (!function_)
1052  {
1053  SceneElement *start = new SceneElement (this, ctx_->element ("start"));
1054  addElement (start);
1055 
1056  start->setPos(5, (height () - start->size ().height ()) / 2);
1057 
1058  SceneElement *end = new SceneElement (this, ctx_->element ("end"));
1059  addElement (end);
1060 
1061  end->setPos(width () - end->size ().width () - 5, (height () - end->size ().height ()) / 2);
1062  }
1063  else
1064  {
1065  SceneElement *start = new SceneElement (this, function_->function ()->start ());
1066  addElement (start);
1067 
1068  start->setPos(5, (height () - start->size ().height ()) / 2);
1069 
1070  SceneElement *end = new SceneElement (this, function_->function ()->end ());
1071  addElement (end);
1072 
1073  end->setPos(width () - end->size ().width () - 5, (height () - end->size ().height ()) / 2);
1074  }
1075  }
1076  dontMoveStart_ = false;
1077 }
1078 
1079 //------------------------------------------------------------------------------
1080 
1081 // update all connections in the scene
1082 void GraphicsScene::updateConnections()
1083 {
1084  foreach (SceneElement *e, elements ())
1085  {
1086  foreach (ElementInput *i, e->inputs ())
1087  foreach (Connection *c, i->connections ())
1088  c->updatePositions ();
1089 
1090  foreach (ElementOutput *o, e->outputs ())
1091  foreach (Connection *c, o->connections ())
1092  c->updatePositions ();
1093 
1094  if (e->dataIn ())
1095  foreach (Connection *c, e->dataIn ()->connections ())
1096  c->updatePositions ();
1097 
1098  if (e->dataOut ())
1099  foreach (Connection *c, e->dataOut ()->connections ())
1100  c->updatePositions ();
1101  }
1102 }
1103 
1104 //------------------------------------------------------------------------------
1105 
1108 {
1109  if (blockChanges_)
1110  return;
1111 
1112  emit contentChanged ();
1113  dontMoveStart_ = true;
1114 }
1115 
1116 //------------------------------------------------------------------------------
1117 
1118 void VSI::GraphicsScene::sceneResized(const QRectF & /*_rect*/)
1119 {
1120  if (dontMoveStart_)
1121  return;
1122 
1123  blockChanges_ = true;
1124 
1125  QList<SceneElement *> elements = elementArea_->elements ();
1126 
1127  SceneElement *start = 0;
1128  SceneElement *end = 0;
1129 
1130  // reset code block of all elements and find start element
1131  foreach (SceneElement *e, elements)
1132  {
1133  e->resetCodeGeneration ();
1134 
1135  if ((!function_ && e->element ()->name () == "start") ||
1136  (function_ && function_->function ()->start () == e->element ()))
1137  start = e;
1138  if ((!function_ && e->element ()->name () == "end") ||
1139  (function_ && function_->function ()->end () == e->element ()))
1140  end = e;
1141  }
1142 
1143  if (start)
1144  start->setPos(5, (height () - start->size ().height ()) / 2);
1145  if (end)
1146  end->setPos(width () - end->size ().width () - 5, (height () - end->size ().height ()) / 2);
1147 
1148  blockChanges_ = false;
1149 }
1150 
1151 //=============================================================================
1152 }
1153 //=============================================================================
1154 
1155 
1156 
1157 
1158 
1159 
1160 
1161 
1162 
1163 
void scaleElements(qreal _delta)
Scale all elements with scaling center in the center of the scene.
InOut * inOut() const
InOut context object.
const QList< SceneElement * > & elements() const
Scene elements.
void loadFromXml(QXmlQuery &_xml)
Load from xml.
bool valid()
Returns state of valid flag (needed during code generation)
unsigned int state()
VSI::Input state passthrough.
void contentChange()
handle content changes
void addElement(SceneElement *_element)
Add a child element.
Definition: elementArea.cc:86
const QVector< Output * > & outputs() const
Outputs.
Definition: element.hh:97
void addScene(GraphicsScene *_scene)
add a new scene
Definition: baseWidget.cc:496
QString value() const
Returns value set by user.
Definition: elementInput.hh:90
SceneElement * element()
The scene element of this function element.
QString generateCode(QString &errors, bool _codeOnly=false)
Generate textual script code (_codeOnly = only pure code block)
const QString & name() const
Name.
Definition: inout.hh:70
QString variableId()
Unique variable name for code generation.
ElementInput * dataIn()
Scene input.
static QString getXmlString(QXmlQuery &_xml, QString _expr, QString _default="")
Gets the string of a xml query.
Definition: context.cc:534
void updatePositions()
called to update position on element movement
Definition: connection.cc:232
int id()
Unique id for identification.
bool removeElement(SceneElement *_element)
Remove the element from the scene.
ConnectionPoint * connectionPointItem() const
Connection point widget.
Definition: elementInOut.hh:89
QString name() const
Name.
Definition: function.hh:81
QString code()
Code block.
QRectF elementsBoundingRect()
Bounding rectangle of all scene elements.
QVector< ElementOutput * > outputs()
Outputs.
Definition: sceneElement.hh:94
QString precode() const
Precode segment.
Definition: element.hh:112
void loadFromXml(QXmlQuery &_xml)
Load from xml.
bool isSet()
Return "set" flag.
void moveElements(qreal _dx, qreal _dy, bool _selected=false)
Moves all elements.
SceneElement * element()
Scene element.
ElementOutput * dataOut()
Scene output.
static BaseWidget * getBaseWidget()
Returns singleton.
Definition: baseWidget.cc:465
void contentChanged()
Informs about content changes.
Element * end() const
End element of this function (can be NULL)
Definition: function.hh:93
void mouseMove(QPointF _pos)
Redirect mouse movement to tools area.
void mouseRelease(QPointF _pos, QGraphicsItem *_item)
Redirect mouse release to tools area.
const QString & shortDescription() const
Short description.
Definition: element.hh:88
void addElement(SceneElement *_element)
Add the element to the scene.
void setValid(bool _value)
Sets the valid flag (needed during code generation)
Definition: elementInput.hh:81
Element * element(QString _name)
Returns the element with a given name.
Definition: context.cc:157
GraphicsScene(VSI::Context *_ctx, ElementFunction *_function=NULL)
Constructor.
void clearScene(bool _start=false)
clear the whole scene (_start = keep start element)
GraphicsScene * scene()
Scene.
const QString & shortDescription() const
Short description.
Definition: function.hh:84
void removeScene(GraphicsScene *_scene)
remove a scene
Definition: baseWidget.cc:504
QString name() const
Element name.
Definition: element.hh:82
const QList< SceneElement * > & elements() const
All elements.
Definition: elementArea.cc:123
bool removeElement(SceneElement *_element, bool _force=false)
Remove an element, if its removeable or _force is set.
Definition: elementArea.cc:103
qreal getNewZ()
Returns a new Z value that is above all elements.
void saveToXml(QDomDocument &_doc, QDomElement &_root)
Save to xml.
ElementInput * input()
Input of this connection.
Definition: connection.cc:239
Element * start() const
Start element of this function.
Definition: function.hh:90
QVector< ElementFunction * > functions()
Functions.
Definition: sceneElement.hh:97
Element * element() const
Context VSI::Element.
Definition: sceneElement.hh:88
bool isForceAskSet() const
Return "ForceAsk" flag.
void resetCodeGeneration()
Reset code block for code generation.
Function * function()
Function class.
~GraphicsScene()
Destructor.
void replaceCodeBlock(QString _name, QString _id, QString _value)
Replace block with name _name and id _id with _value.
void mouseRelease(QPointF _pos, QGraphicsItem *_item)
Handles mouse release (will be called by the scene, if the element is dropped)
Definition: sceneTools.cc:197
QVector< ElementInput * > inputs()
Inputs.
Definition: sceneElement.hh:91
void mouseMove(QPointF _pos)
Handles mouse movement (will be called by the scene, if the mouse with a draged element is moved) ...
Definition: sceneTools.cc:170
void saveToXml(QDomDocument &_doc, QDomElement &_root)
Save to xml.
QList< Connection * > connections() const
Connections.
Definition: elementInOut.hh:98
const QString & shortDescription() const
Short description.
Definition: inout.hh:73