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
86 GraphicsScene::GraphicsScene (Context *_ctx, ElementFunction *_function) :
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
145 if (BaseWidget::getBaseWidget ())
146 BaseWidget::getBaseWidget ()->addScene (this);
147
148 connect (this, SIGNAL(sceneRectChanged( const QRectF& )), this, SLOT(sceneResized(const QRectF&)));
149 dontMoveStart_ = false;
150 }
151
152 //------------------------------------------------------------------------------
153
155 GraphicsScene::~GraphicsScene ()
156 {
157 delete wayFind_;
158
159 if (BaseWidget::getBaseWidget ())
160 BaseWidget::getBaseWidget ()->removeScene (this);
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
252 qreal GraphicsScene::getNewZ ()
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
299 void GraphicsScene::addElement (SceneElement *_element)
300 {
301 contentChange ();
302 addItem (_element);
303 elementArea_->addElement (_element);
304 }
305
306 //------------------------------------------------------------------------------
307
309 bool GraphicsScene::removeElement (SceneElement *_element)
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
337 QRectF GraphicsScene::elementsBoundingRect ()
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
1107 void GraphicsScene::contentChange ()
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
VSI::GraphicsScene::scaleElements
void scaleElements(qreal _delta)
Scale all elements with scaling center in the center of the scene.
Definition: graphicsScene.cc:280
VSI::ElementInOut::inOut
InOut * inOut() const
InOut context object.
Definition: elementInOut.hh:110
VSI::GraphicsScene::elements
const QList< SceneElement * > & elements() const
Scene elements.
Definition: graphicsScene.cc:348
VSI::GraphicsScene::loadFromXml
void loadFromXml(QXmlQuery &_xml)
Load from xml.
Definition: graphicsScene.cc:883
VSI::ElementInput::valid
bool valid()
Returns state of valid flag (needed during code generation)
Definition: elementInput.cc:114
VSI::ElementInput::state
unsigned int state()
VSI::Input state passthrough.
Definition: elementInput.cc:128
VSI::GraphicsScene::contentChange
void contentChange()
handle content changes
Definition: graphicsScene.cc:1107
VSI::ElementArea::addElement
void addElement(SceneElement *_element)
Add a child element.
Definition: elementArea.cc:86
VSI::Element::outputs
const QVector< Output * > & outputs() const
Outputs.
Definition: element.hh:97
VSI::BaseWidget::addScene
void addScene(GraphicsScene *_scene)
add a new scene
Definition: baseWidget.cc:496
VSI::ElementInput::value
QString value() const
Returns value set by user.
Definition: elementInput.hh:90
VSI::ElementFunction::element
SceneElement * element()
The scene element of this function element.
Definition: elementFunction.hh:79
VSI::ElementInput
Definition: elementInput.hh:67
VSI::GraphicsScene::generateCode
QString generateCode(QString &errors, bool _codeOnly=false)
Generate textual script code (_codeOnly = only pure code block)
Definition: graphicsScene.cc:458
VSI::InOut::name
const QString & name() const
Name.
Definition: inout.hh:70
VSI::SceneElement::variableId
QString variableId()
Unique variable name for code generation.
Definition: sceneElement.cc:581
VSI::SceneElement::dataIn
ElementInput * dataIn()
Scene input.
Definition: sceneElement.hh:100
VSI::Context::getXmlString
static QString getXmlString(QXmlQuery &_xml, QString _expr, QString _default="")
Gets the string of a xml query.
Definition: context.cc:534
VSI::Connection::updatePositions
void updatePositions()
called to update position on element movement
Definition: connection.cc:232
VSI::SceneElement::id
int id()
Unique id for identification.
Definition: sceneElement.hh:115
VSI::GraphicsScene::removeElement
bool removeElement(SceneElement *_element)
Remove the element from the scene.
Definition: graphicsScene.cc:309
VSI::Connection
Definition: connection.hh:66
VSI::ElementInOut::connectionPointItem
ConnectionPoint * connectionPointItem() const
Connection point widget.
Definition: elementInOut.hh:89
VSI::GraphicsView
Definition: graphicsView.hh:61
VSI::Function::name
QString name() const
Name.
Definition: function.hh:81
VSI::ElementOutput
Definition: elementOutput.hh:60
VSI::SceneElement::code
QString code()
Code block.
Definition: sceneElement.hh:118
VSI::GraphicsScene::elementsBoundingRect
QRectF elementsBoundingRect()
Bounding rectangle of all scene elements.
Definition: graphicsScene.cc:337
VSI::SceneTools
Definition: sceneTools.hh:67
VSI::ElementArea
Definition: elementArea.hh:62
VSI::SceneElement::outputs
QVector< ElementOutput * > outputs()
Outputs.
Definition: sceneElement.hh:94
VSI::Element::precode
QString precode() const
Precode segment.
Definition: element.hh:112
VSI::SceneElement::loadFromXml
void loadFromXml(QXmlQuery &_xml)
Load from xml.
Definition: sceneElement.cc:745
VSI::ElementInput::isSet
bool isSet()
Return "set" flag.
Definition: elementInput.cc:199
VSI::GraphicsScene::moveElements
void moveElements(qreal _dx, qreal _dy, bool _selected=false)
Moves all elements.
Definition: graphicsScene.cc:261
VSI::ElementInOut::element
SceneElement * element()
Scene element.
Definition: elementInOut.hh:113
VSI::SceneElement::dataOut
ElementOutput * dataOut()
Scene output.
Definition: sceneElement.hh:103
VSI::BaseWidget::getBaseWidget
static BaseWidget * getBaseWidget()
Returns singleton.
Definition: baseWidget.cc:465
VSI::GraphicsScene::contentChanged
void contentChanged()
Informs about content changes.
VSI::Function::end
Element * end() const
End element of this function (can be NULL)
Definition: function.hh:93
VSI::GraphicsScene::mouseMove
void mouseMove(QPointF _pos)
Redirect mouse movement to tools area.
Definition: graphicsScene.cc:322
VSI::GraphicsScene::mouseRelease
void mouseRelease(QPointF _pos, QGraphicsItem *_item)
Redirect mouse release to tools area.
Definition: graphicsScene.cc:330
VSI::Element::shortDescription
const QString & shortDescription() const
Short description.
Definition: element.hh:88
VSI::GraphicsScene::addElement
void addElement(SceneElement *_element)
Add the element to the scene.
Definition: graphicsScene.cc:299
VSI::WayFind
Definition: wayfind.hh:64
VSI::ElementInput::setValid
void setValid(bool _value)
Sets the valid flag (needed during code generation)
Definition: elementInput.hh:81
VSI::Context::element
Element * element(QString _name)
Returns the element with a given name.
Definition: context.cc:157
VSI::GraphicsScene::GraphicsScene
GraphicsScene(VSI::Context *_ctx, ElementFunction *_function=NULL)
Constructor.
Definition: graphicsScene.cc:86
VSI::ElementFunction
Definition: elementFunction.hh:66
VSI::GraphicsScene::clearScene
void clearScene(bool _start=false)
clear the whole scene (_start = keep start element)
Definition: graphicsScene.cc:1036
VSI::ElementFunction::scene
GraphicsScene * scene()
Scene.
Definition: elementFunction.hh:85
VSI::Function::shortDescription
const QString & shortDescription() const
Short description.
Definition: function.hh:84
VSI::BaseWidget::removeScene
void removeScene(GraphicsScene *_scene)
remove a scene
Definition: baseWidget.cc:504
VSI::Element::name
QString name() const
Element name.
Definition: element.hh:82
VSI::ElementArea::elements
const QList< SceneElement * > & elements() const
All elements.
Definition: elementArea.cc:123
VSI::ElementArea::removeElement
bool removeElement(SceneElement *_element, bool _force=false)
Remove an element, if its removeable or _force is set.
Definition: elementArea.cc:103
VSI::GraphicsScene::getNewZ
qreal getNewZ()
Returns a new Z value that is above all elements.
Definition: graphicsScene.cc:252
VSI::SceneElement::saveToXml
void saveToXml(QDomDocument &_doc, QDomElement &_root)
Save to xml.
Definition: sceneElement.cc:693
VSI::Connection::input
ElementInput * input()
Input of this connection.
Definition: connection.cc:239
VSI::Function::start
Element * start() const
Start element of this function.
Definition: function.hh:90
VSI
Definition: baseWidget.cc:72
VSI::Output
Definition: output.hh:60
VSI::Element
Definition: element.hh:68
VSI::SceneElement::functions
QVector< ElementFunction * > functions()
Functions.
Definition: sceneElement.hh:97
VSI::SceneElement::element
Element * element() const
Context VSI::Element.
Definition: sceneElement.hh:88
VSI::ElementInput::isForceAskSet
bool isForceAskSet() const
Return "ForceAsk" flag.
Definition: elementInput.hh:108
VSI::SceneElement::resetCodeGeneration
void resetCodeGeneration()
Reset code block for code generation.
Definition: sceneElement.cc:559
VSI::ElementFunction::function
Function * function()
Function class.
Definition: elementFunction.hh:82
VSI::GraphicsScene::~GraphicsScene
~GraphicsScene()
Destructor.
Definition: graphicsScene.cc:155
VSI::SceneElement
Definition: sceneElement.hh:73
VSI::ConnectionPoint
Definition: connectionPoint.hh:67
VSI::SceneElement::replaceCodeBlock
void replaceCodeBlock(QString _name, QString _id, QString _value)
Replace block with name _name and id _id with _value.
Definition: sceneElement.cc:572
VSI::SceneTools::mouseRelease
void mouseRelease(QPointF _pos, QGraphicsItem *_item)
Handles mouse release (will be called by the scene, if the element is dropped)
Definition: sceneTools.cc:197
VSI::SceneElement::inputs
QVector< ElementInput * > inputs()
Inputs.
Definition: sceneElement.hh:91
VSI::SceneTools::mouseMove
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
VSI::GraphicsScene::saveToXml
void saveToXml(QDomDocument &_doc, QDomElement &_root)
Save to xml.
Definition: graphicsScene.cc:851
VSI::ElementInOut::connections
QList< Connection * > connections() const
Connections.
Definition: elementInOut.hh:98
VSI::Context
Definition: context.hh:70
VSI::InOut::shortDescription
const QString & shortDescription() const
Short description.
Definition: inout.hh:73