]> git.sven.stormbind.net Git - sven/vym.git/blob - xlinkobj.cpp
Import Upstream version 2.6.11
[sven/vym.git] / xlinkobj.cpp
1 #include <QDebug>
2
3 #include "xlinkobj.h"
4
5 #include "branchobj.h"
6 #include "branchitem.h"
7 #include "math.h"       // atan
8 #include "misc.h"       // max
9
10 /////////////////////////////////////////////////////////////////
11 // XLinkObj
12 /////////////////////////////////////////////////////////////////
13
14 int XLinkObj::arrowSize = 6;                // make instances
15 int XLinkObj::clickBorder = 8;
16 int XLinkObj::pointRadius = 10;
17 int XLinkObj::d_control = 300;
18
19 XLinkObj::XLinkObj (QGraphicsItem* parent,Link *l):MapObj(parent)
20 {
21     //qDebug()<< "Const XLinkObj (parent,Link)";
22     link=l;
23     init();
24 }
25
26
27
28 XLinkObj::~XLinkObj ()
29 {
30     //qDebug() << "Destr XLinkObj";
31     delete (poly);
32     delete (path);
33     delete (ctrl_p0);
34     delete (ctrl_p1);
35     delete (pointerEnd);
36     delete (pointerBegin);
37 }
38
39
40 void XLinkObj::init () 
41 {
42     visBranch = NULL;
43
44     stateVis = Hidden;
45
46     QPen pen = link->getPen();
47
48     path = scene()->addPath (QPainterPath(), pen, Qt::NoBrush); 
49     path->setZValue (dZ_XLINK);
50
51     pointerBegin = new ArrowObj(this);
52     pointerBegin->setPen( pen );
53     pointerBegin->setUseFixedLength( true );
54     pointerBegin->setFixedLength( 0 );
55
56     pointerEnd = new ArrowObj(this);
57     pointerEnd->setPen( pen );
58     pointerEnd->setUseFixedLength( true );
59     pointerEnd->setFixedLength( 0 );
60
61     pen.setStyle (Qt::SolidLine);
62     poly = scene()->addPolygon (QPolygonF(), pen, pen.color()); 
63     poly->setZValue (dZ_XLINK);
64
65     // Control points for bezier path
66     // (We have at least a begin branch, consider its orientation)
67     initC0();
68     initC1();
69
70     ctrl_p0 = scene()->addEllipse (
71         c0.x(), c0.y(),
72         clickBorder*2, clickBorder*2,
73         pen, pen.color() );
74     ctrl_p1 = scene()->addEllipse (
75         c1.x(), c1.y(),
76         clickBorder*2, clickBorder*2,
77         pen, pen.color() );
78
79     beginOrient = endOrient=LinkableMapObj::UndefinedOrientation;
80     pen.setWidth (1);
81     pen.setStyle (Qt::DashLine);
82
83     curSelection = Unselected;
84
85     setVisibility (true);
86 }
87
88 QPointF XLinkObj::getAbsPos() 
89 {
90     switch (curSelection)
91     {
92         case C0:
93             return c0;
94             break;
95         case C1:
96             return c1;
97             break;
98         default:
99             return QPointF();
100             break;
101     }
102 }
103
104 void XLinkObj::setStyleBegin(const QString &s)
105 {
106     pointerBegin->setStyleEnd( s );
107 }
108
109 void XLinkObj::setStyleBegin(ArrowObj::OrnamentStyle os)
110 {
111     pointerBegin->setStyleEnd( os );
112 }
113
114 ArrowObj::OrnamentStyle XLinkObj::getStyleBegin()
115 {
116     return pointerBegin->getStyleEnd();
117 }
118
119 void XLinkObj::setStyleEnd(const QString &s)
120 {
121     pointerEnd->setStyleEnd( s );
122 }
123
124 void XLinkObj::setStyleEnd(ArrowObj::OrnamentStyle os)
125 {
126     pointerEnd->setStyleEnd( os );
127 }
128
129 ArrowObj::OrnamentStyle XLinkObj::getStyleEnd()
130 {
131     return pointerEnd->getStyleEnd();
132 }
133
134 QPointF XLinkObj::getBeginPos()
135 {
136     return beginPos;
137 }
138
139 QPointF XLinkObj::getEndPos()
140 {
141     return endPos;
142 }
143
144 void XLinkObj::move (QPointF p)
145 {
146     switch (curSelection)
147     {
148         case C0:
149             c0=p;
150             break;
151         case C1:
152             c1=p;
153             break;
154         default:
155             break;
156     }
157     updateXLink();
158 }
159
160 void XLinkObj::setEnd (QPointF p)
161 {
162     endPos=p;
163 }
164
165 void XLinkObj::setSelection (CurrentSelection s)
166 {
167     curSelection=s;
168     setVisibility();
169 }
170
171 void XLinkObj::setSelection (int cp)
172 {
173     if (cp==0) 
174         setSelection (C0);
175     else if (cp==1)
176         setSelection (C1);
177     else
178         qWarning()<<"XLO::setSelection cp="<<cp;
179 }
180
181 void XLinkObj::updateXLink()    
182 {
183     QPointF a,b;
184     QPolygonF pa;
185
186     BranchObj *beginBO=NULL;
187     BranchObj   *endBO=NULL;
188     BranchItem *bi=link->getBeginBranch();
189     if ( bi) beginBO=(BranchObj*)(bi->getLMO());
190     bi=link->getEndBranch();
191     if (bi) endBO=(BranchObj*)(bi->getLMO());
192
193     if (beginBO) 
194     {
195         if (beginOrient != LinkableMapObj::UndefinedOrientation  &&
196             beginOrient != beginBO->getOrientation() )
197             c0.setX( -c0.x() );
198         beginOrient = beginBO->getOrientation();
199     }
200     if (endBO)  
201     {
202         if (endOrient != LinkableMapObj::UndefinedOrientation  &&
203             endOrient != endBO->getOrientation() )
204             c1.setX( -c1.x() );
205         endOrient = endBO->getOrientation();
206     }
207
208     if (visBranch)   
209     {
210         // Only one of the linked branches is visible
211         // Draw arrowhead   //FIXME-3 missing shaft of arrow
212         BranchObj *bo=(BranchObj*)(visBranch->getLMO());
213         if (!bo) return;
214
215         a=b=bo->getChildRefPos();
216
217
218         if (bo->getOrientation()==LinkableMapObj::RightOfCenter)
219         {
220             b.setX (b.x() + 2*arrowSize);
221             pa.clear();
222             pa << a <<
223                   b <<
224                   QPointF (b.x(), b.y() - arrowSize) <<
225                   QPointF (b.x() + arrowSize, b.y()) <<
226                   QPointF (b.x(), b.y() + arrowSize) <<
227                   b <<
228                   a;
229             poly->setPolygon(pa);
230         } else
231         {
232             b.setX (b.x() - 2*arrowSize);
233             pa.clear();
234             pa << a <<
235                   b <<
236                   QPointF (b.x(), b.y() - arrowSize) <<
237                   QPointF (b.x() - arrowSize, b.y()) <<
238                   QPointF (b.x(), b.y() + arrowSize) <<
239                   b <<
240                   a;
241             poly->setPolygon (pa);
242         }   
243     } else
244     {
245         // Both linked branches are visible
246
247         // If a link is just drawn in the editor,
248         // we have already a beginBranch
249         if (beginBO) beginPos=beginBO->getChildRefPos();
250         if (endBO) endPos=endBO->getChildRefPos();
251
252         if (beginBO && endBO)
253         {
254             pointerBegin->move(beginPos + c0 );
255             pointerBegin->setEndPoint(beginPos);
256
257             pointerEnd->move(endPos + c1 );
258             pointerEnd->setEndPoint(endPos);
259         }
260     }
261
262     // Update control points for bezier
263     QPainterPath p(beginPos);
264     p.cubicTo ( beginPos + c0, endPos + c1, endPos);
265
266     clickPath=p;
267     path->setPath (p);  
268
269     // Go back to create closed curve, 
270     // needed for intersection check:   
271     clickPath.cubicTo ( endPos + c1, beginPos + c0, beginPos);  
272
273     QPen pen=link->getPen();
274     path->setPen (pen);
275     poly->setBrush (pen.color() );
276     
277     pointerBegin->setPen( pen );
278     pointerEnd->setPen( pen );
279
280     pen.setStyle (Qt::SolidLine);
281
282
283     ctrl_p0->setRect (
284         beginPos.x() + c0.x() - pointRadius/2, beginPos.y() + c0.y() - pointRadius/2,
285         pointRadius, pointRadius );
286     ctrl_p0->setPen (pen);
287     ctrl_p0->setBrush (pen.color() );
288
289     ctrl_p1->setRect (
290         endPos.x() + c1.x() - pointRadius/2, endPos.y() + c1.y() - pointRadius/2,
291         pointRadius, pointRadius );
292     ctrl_p1->setPen (pen);
293     ctrl_p1->setBrush (pen.color() );
294
295     BranchItem *bi_begin=link->getBeginBranch();
296     BranchItem *bi_end  =link->getEndBranch();
297     if (bi_begin && bi_end && link->getState()==Link::activeXLink)
298         // Note: with MapObj being a GraphicsItem now, maybe better reparent the xlinkobj
299         // line->setZValue (dZ_DEPTH * max(bi_begin->depth(),bi_end->depth()) + dZ_XLINK); 
300         path->setZValue (dZ_XLINK); 
301     else        
302         path->setZValue (dZ_XLINK);
303
304     setVisibility();
305 }
306
307 void XLinkObj::positionBBox()
308 {
309 }
310
311 void XLinkObj::calcBBoxSize()
312 {
313 }
314
315 void XLinkObj::setVisibility (bool b)
316 {
317     if (stateVis==FullShowControls)
318     {
319         ctrl_p0->show();
320         ctrl_p1->show();
321         pointerBegin->setUseFixedLength( false );
322         pointerEnd->setUseFixedLength( false );
323     } else
324     {
325         ctrl_p0->hide();
326         ctrl_p1->hide();
327         pointerBegin->setUseFixedLength( true );
328         pointerBegin->setFixedLength( 0 );
329         pointerEnd->setUseFixedLength( true );
330         pointerEnd->setFixedLength( 0 );
331     }
332
333     MapObj::setVisibility (b);
334     if (b)
335     {
336         if (stateVis==OnlyBegin) 
337         {
338             path->hide();
339             poly->show();
340             pointerBegin->hide();
341             pointerEnd->hide();
342         }
343         else if (stateVis==OnlyEnd)
344         {
345             path->hide();
346             poly->show();
347             pointerBegin->hide();
348             pointerEnd->hide();
349         }
350         else
351         {
352             path->show();
353             poly->hide();
354             pointerBegin->show();
355             pointerEnd->show();
356         }
357     }   
358     else
359     {
360         poly->hide();
361         path->hide();
362         pointerBegin->hide();
363         pointerEnd->hide();
364     }   
365
366 }
367
368 void XLinkObj::setVisibility ()
369 {
370     BranchItem* beginBI=link->getBeginBranch();
371     BranchObj* beginBO=NULL;
372     if (beginBI) beginBO=(BranchObj*)(beginBI->getLMO());
373
374     BranchObj* endBO=NULL;
375     BranchItem* endBI=link->getEndBranch();
376     if (endBI) endBO=(BranchObj*)(endBI->getLMO());
377     if (beginBO && endBO)
378     {
379         if(beginBO->isVisibleObj() && endBO->isVisibleObj())
380         {   // Both ends are visible
381             visBranch=NULL;
382             if (curSelection != Unselected)
383                 stateVis=FullShowControls;
384             else        
385                 stateVis=Full;
386             setVisibility (true);
387         } else
388         {
389             if(!beginBO->isVisibleObj() && !endBO->isVisibleObj())
390             {   //None of the ends is visible
391                 visBranch=NULL;
392                 stateVis=Hidden;
393                 setVisibility (false);
394             } else
395             {   // Just one end is visible, draw a symbol that shows
396                 // that there is a link to a scrolled branch
397                 if (beginBO->isVisibleObj())
398                 {
399                     stateVis=OnlyBegin;
400                     visBranch=beginBI;
401                 }
402                 else
403                 {
404                     visBranch=endBI;
405                     stateVis=OnlyEnd;
406                 }
407                 setVisibility (true);
408             }
409         }
410     }
411 }
412
413 void XLinkObj::initC0()
414 {
415     if ( !link ) return;
416     BranchItem *beginBranch = link->getBeginBranch();
417     if ( !beginBranch ) return;
418     BranchObj *bo = beginBranch->getBranchObj();
419     if ( !bo ) return;
420     if ( bo->getOrientation() == LinkableMapObj::RightOfCenter  ) 
421         c0 = QPointF ( d_control, 0);
422     else
423         c0 = QPointF ( -d_control, 0);
424 }
425
426 void XLinkObj::initC1()
427 {
428     if (!link ) return; 
429     BranchItem *endBranch = link->getEndBranch();
430     if (!endBranch) return;
431     BranchObj *bo = endBranch->getBranchObj();
432     if (!bo) return;
433     if ( bo->getOrientation() == LinkableMapObj::RightOfCenter  ) 
434         c1 = QPointF ( d_control, 0);
435     else
436         c1 = QPointF ( -d_control, 0);
437 }
438
439 void XLinkObj::setC0(const QPointF &p)
440 {
441     c0=p;
442 }
443
444 QPointF XLinkObj::getC0()
445 {
446     return c0;
447 }
448
449 void XLinkObj::setC1(const QPointF &p)
450 {
451     c1=p;
452 }
453
454 QPointF XLinkObj::getC1()
455 {
456     return c1;
457 }
458
459 int XLinkObj::ctrlPointInClickBox (const QPointF &p)    
460 {
461     CurrentSelection oldSel=curSelection;
462     int ret=-1;
463
464     QRectF r(p.x() - clickBorder, p.y() - clickBorder,
465                      clickBorder *2, clickBorder*2) ;
466
467     if (curSelection==C0 || curSelection==C1)
468     {
469         // If Cx selected, check both ctrl points 
470         curSelection=C0;
471         if (getClickPath().intersects (r) ) ret=0;
472         curSelection=C1;
473         if (getClickPath().intersects (r) ) ret=1;
474     } 
475     curSelection=oldSel;
476     return ret;
477 }
478
479 bool XLinkObj::isInClickBox (const QPointF &p)
480 {
481     // Return, if not visible at all...
482     if (stateVis==Hidden) return false;
483
484     CurrentSelection oldSel=curSelection;
485     bool b=false;
486
487     QRectF r(p.x() - clickBorder, p.y() - clickBorder,
488                      clickBorder *2, clickBorder*2) ;
489
490     switch (stateVis)
491     {
492         case FullShowControls:
493             // If Cx selected, check both ctrl points 
494             if (ctrlPointInClickBox(p) >-1) b=true;
495
496             // Enable selecting the path, when a ctrl point is already selected
497             if (!b && curSelection!=Unselected && clickPath.intersects (r)) b=true;
498             break;
499         case OnlyBegin || OnlyEnd:    
500             // not selected, only partially visible
501             if (poly->boundingRect().contains(p) ) 
502                 b=true;
503             break;
504         default:
505             // not selected, but path is fully visible
506             curSelection=Path;
507             if (getClickPath().intersects (r) ) b=true;
508             break;
509     }
510     curSelection=oldSel;
511     return b;
512 }
513
514 QPainterPath XLinkObj::getClickPath()  // also needs mirroring if oriented left. Create method to generate the coordinates
515 {
516     QPainterPath p;
517     switch (curSelection)
518     {
519         case C0:
520             p.addEllipse (beginPos + c0,15,15);
521             return p;
522             break;
523         case C1:
524             p.addEllipse (endPos + c1,15,15);
525             return p;
526             break;
527         default:
528             return clickPath;
529             break;
530     }
531 }