Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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
92 GraphicsScene::GraphicsScene (Context *_ctx, ElementFunction *_function) :
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
151 if (BaseWidget::getBaseWidget ())
152 BaseWidget::getBaseWidget ()->addScene (this);
153
154 connect (this, SIGNAL(sceneRectChanged( const QRectF& )), this, SLOT(sceneResized(const QRectF&)));
155 dontMoveStart_ = false;
156 }
157
158 //------------------------------------------------------------------------------
159
161 GraphicsScene::~GraphicsScene ()
162 {
163 delete wayFind_;
164
165 if (BaseWidget::getBaseWidget ())
166 BaseWidget::getBaseWidget ()->removeScene (this);
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
258 qreal GraphicsScene::getNewZ ()
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
305 void GraphicsScene::addElement (SceneElement *_element)
306 {
307 contentChange ();
308 addItem (_element);
309 elementArea_->addElement (_element);
310 }
311
312 //------------------------------------------------------------------------------
313
315 bool GraphicsScene::removeElement (SceneElement *_element)
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
343 QRectF GraphicsScene::elementsBoundingRect ()
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
1113 void GraphicsScene::contentChange ()
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
VSI
Definition: baseWidget.cc:78
VSI::ElementInput::valid
bool valid()
Returns state of valid flag (needed during code generation)
Definition: elementInput.cc:120
VSI::GraphicsScene::removeElement
bool removeElement(SceneElement *_element)
Remove the element from the scene.
Definition: graphicsScene.cc:315
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:176
VSI::ElementInput::value
QString value() const
Returns value set by user.
Definition: elementInput.hh:96
VSI::InOut::shortDescription
const QString & shortDescription() const
Short description.
Definition: inout.hh:79
VSI::GraphicsScene::elementsBoundingRect
QRectF elementsBoundingRect()
Bounding rectangle of all scene elements.
Definition: graphicsScene.cc:343
VSI::InOut::name
const QString & name() const
Name.
Definition: inout.hh:76
VSI::Context
Definition: context.hh:76
VSI::GraphicsView
Definition: graphicsView.hh:67
VSI::ElementFunction::element
SceneElement * element()
The scene element of this function element.
Definition: elementFunction.hh:85
VSI::GraphicsScene::contentChanged
void contentChanged()
Informs about content changes.
VSI::SceneElement::inputs
QVector< ElementInput * > inputs()
Inputs.
Definition: sceneElement.hh:97
VSI::GraphicsScene::elements
const QList< SceneElement * > & elements() const
Scene elements.
Definition: graphicsScene.cc:354
VSI::Element::shortDescription
const QString & shortDescription() const
Short description.
Definition: element.hh:94
VSI::ElementOutput
Definition: elementOutput.hh:66
VSI::GraphicsScene::loadFromXml
void loadFromXml(QXmlQuery &_xml)
Load from xml.
Definition: graphicsScene.cc:889
VSI::BaseWidget::getBaseWidget
static BaseWidget * getBaseWidget()
Returns singleton.
Definition: baseWidget.cc:471
VSI::GraphicsScene::clearScene
void clearScene(bool _start=false)
clear the whole scene (_start = keep start element)
Definition: graphicsScene.cc:1042
VSI::GraphicsScene::scaleElements
void scaleElements(qreal _delta)
Scale all elements with scaling center in the center of the scene.
Definition: graphicsScene.cc:286
VSI::SceneElement::saveToXml
void saveToXml(QDomDocument &_doc, QDomElement &_root)
Save to xml.
Definition: sceneElement.cc:699
VSI::Function::start
Element * start() const
Start element of this function.
Definition: function.hh:96
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:203
VSI::ElementInOut::inOut
InOut * inOut() const
InOut context object.
Definition: elementInOut.hh:116
VSI::Function::name
QString name() const
Name.
Definition: function.hh:87
VSI::GraphicsScene::~GraphicsScene
~GraphicsScene()
Destructor.
Definition: graphicsScene.cc:161
VSI::Context::getXmlString
static QString getXmlString(QXmlQuery &_xml, QString _expr, QString _default="")
Gets the string of a xml query.
Definition: context.cc:540
VSI::ElementInput::isSet
bool isSet()
Return "set" flag.
Definition: elementInput.cc:205
VSI::Element::outputs
const QVector< Output * > & outputs() const
Outputs.
Definition: element.hh:103
VSI::BaseWidget::addScene
void addScene(GraphicsScene *_scene)
add a new scene
Definition: baseWidget.cc:502
VSI::SceneElement::loadFromXml
void loadFromXml(QXmlQuery &_xml)
Load from xml.
Definition: sceneElement.cc:751
VSI::Element::name
QString name() const
Element name.
Definition: element.hh:88
VSI::Context::element
Element * element(QString _name)
Returns the element with a given name.
Definition: context.cc:163
VSI::ElementInput::setValid
void setValid(bool _value)
Sets the valid flag (needed during code generation)
Definition: elementInput.hh:87
VSI::Connection::input
ElementInput * input()
Input of this connection.
Definition: connection.cc:245
VSI::WayFind
Definition: wayfind.hh:70
VSI::Element
Definition: element.hh:74
VSI::ElementInOut::connections
QList< Connection * > connections() const
Connections.
Definition: elementInOut.hh:104
VSI::GraphicsScene::GraphicsScene
GraphicsScene(VSI::Context *_ctx, ElementFunction *_function=NULL)
Constructor.
Definition: graphicsScene.cc:92
VSI::Output
Definition: output.hh:66
VSI::SceneElement::functions
QVector< ElementFunction * > functions()
Functions.
Definition: sceneElement.hh:103
VSI::ElementInput
Definition: elementInput.hh:73
VSI::ElementFunction::function
Function * function()
Function class.
Definition: elementFunction.hh:88
VSI::GraphicsScene::saveToXml
void saveToXml(QDomDocument &_doc, QDomElement &_root)
Save to xml.
Definition: graphicsScene.cc:857
VSI::SceneElement::element
Element * element() const
Context VSI::Element.
Definition: sceneElement.hh:94
VSI::Element::precode
QString precode() const
Precode segment.
Definition: element.hh:118
VSI::ElementFunction
Definition: elementFunction.hh:72
VSI::GraphicsScene::moveElements
void moveElements(qreal _dx, qreal _dy, bool _selected=false)
Moves all elements.
Definition: graphicsScene.cc:267
VSI::ElementArea::removeElement
bool removeElement(SceneElement *_element, bool _force=false)
Remove an element, if its removeable or _force is set.
Definition: elementArea.cc:109
VSI::GraphicsScene::contentChange
void contentChange()
handle content changes
Definition: graphicsScene.cc:1113
VSI::Function::end
Element * end() const
End element of this function (can be NULL)
Definition: function.hh:99
VSI::Function::shortDescription
const QString & shortDescription() const
Short description.
Definition: function.hh:90
VSI::GraphicsScene::addElement
void addElement(SceneElement *_element)
Add the element to the scene.
Definition: graphicsScene.cc:305
VSI::GraphicsScene::getNewZ
qreal getNewZ()
Returns a new Z value that is above all elements.
Definition: graphicsScene.cc:258
VSI::SceneElement::dataIn
ElementInput * dataIn()
Scene input.
Definition: sceneElement.hh:106
VSI::SceneTools
Definition: sceneTools.hh:73
VSI::SceneElement
Definition: sceneElement.hh:79
VSI::ElementInput::state
unsigned int state()
VSI::Input state passthrough.
Definition: elementInput.cc:134
VSI::ElementFunction::scene
GraphicsScene * scene()
Scene.
Definition: elementFunction.hh:91
VSI::GraphicsScene::generateCode
QString generateCode(QString &errors, bool _codeOnly=false)
Generate textual script code (_codeOnly = only pure code block)
Definition: graphicsScene.cc:464
VSI::ElementArea
Definition: elementArea.hh:68
VSI::ElementInput::isForceAskSet
bool isForceAskSet() const
Return "ForceAsk" flag.
Definition: elementInput.hh:114
VSI::SceneElement::dataOut
ElementOutput * dataOut()
Scene output.
Definition: sceneElement.hh:109
VSI::SceneElement::replaceCodeBlock
void replaceCodeBlock(QString _name, QString _id, QString _value)
Replace block with name _name and id _id with _value.
Definition: sceneElement.cc:578
VSI::SceneElement::code
QString code()
Code block.
Definition: sceneElement.hh:124
VSI::SceneElement::variableId
QString variableId()
Unique variable name for code generation.
Definition: sceneElement.cc:587
VSI::GraphicsScene::mouseMove
void mouseMove(QPointF _pos)
Redirect mouse movement to tools area.
Definition: graphicsScene.cc:328
VSI::Connection::updatePositions
void updatePositions()
called to update position on element movement
Definition: connection.cc:238
VSI::ElementArea::elements
const QList< SceneElement * > & elements() const
All elements.
Definition: elementArea.cc:129
VSI::Connection
Definition: connection.hh:72
VSI::BaseWidget::removeScene
void removeScene(GraphicsScene *_scene)
remove a scene
Definition: baseWidget.cc:510
VSI::SceneElement::outputs
QVector< ElementOutput * > outputs()
Outputs.
Definition: sceneElement.hh:100
VSI::ElementArea::addElement
void addElement(SceneElement *_element)
Add a child element.
Definition: elementArea.cc:92
VSI::GraphicsScene::mouseRelease
void mouseRelease(QPointF _pos, QGraphicsItem *_item)
Redirect mouse release to tools area.
Definition: graphicsScene.cc:336
VSI::SceneElement::resetCodeGeneration
void resetCodeGeneration()
Reset code block for code generation.
Definition: sceneElement.cc:565