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