3 #include "linkablemapobj.h"
10 /////////////////////////////////////////////////////////////////
12 /////////////////////////////////////////////////////////////////
14 LinkableMapObj::LinkableMapObj():MapObj()
16 // cout << "Const LinkableMapObj ()\n";
20 LinkableMapObj::LinkableMapObj(QCanvas* c) :MapObj(c)
22 // cout << "Const LinkableMapObj\n";
26 LinkableMapObj::LinkableMapObj (LinkableMapObj* lmo) : MapObj (lmo->canvas)
31 LinkableMapObj::~LinkableMapObj()
39 void LinkableMapObj::delLink()
53 case StylePolyParabel:
62 void LinkableMapObj::init ()
72 orientation=OrientUndef;
77 segment.setAutoDelete (TRUE);
79 QPointArray pa(arcsegs*2+2);
81 bottomline=new QCanvasLine(canvas);
82 bottomline->setPen( QPen(linkcolor, 1) );
83 bottomline->setZ(Z_LINK);
86 // Prepare showing the selection of a MapObj
87 selbox = new QCanvasRectangle (canvas);
88 selbox->setZ(Z_SELBOX);
89 selbox->setBrush( QColor(255,255,0) );
90 selbox->setPen( QPen(QColor(255,255,0) ));
95 frame = new FrameObj (canvas);
97 repositionRequest=false;
100 void LinkableMapObj::copy (LinkableMapObj* other)
103 bboxTotal=other->bboxTotal;
104 // linkwidth=other->linkwidth;
106 setLinkStyle(other->style);
107 setLinkColor (other->linkcolor);
110 void LinkableMapObj::setChildObj(LinkableMapObj* o)
115 void LinkableMapObj::setParObj(LinkableMapObj* o)
118 mapEditor=parObj->getMapEditor();
121 void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPoint,int)
125 void LinkableMapObj::unsetParObjTmp()
129 LinkStyle LinkableMapObj::getDefLinkStyle ()
131 LinkStyle ls=mapEditor->getLinkStyle();
146 case StylePolyParabel:
158 void LinkableMapObj::setLinkStyle(LinkStyle newstyle)
160 //if (newstyle=style) return;
165 if (childObj!=NULL && parObj != NULL)
175 l = new QCanvasLine(canvas);
176 l->setPen( QPen(linkcolor, 1) );
184 for (i=0;i<arcsegs;i++)
186 cl = new QCanvasLine(canvas);
187 cl->setPen( QPen(linkcolor, 1) );
188 cl->setPoints( 0,0,i*10,100);
196 pa0.resize (arcsegs+1);
199 p = new QCanvasPolygon(canvas);
200 p->setBrush( linkcolor );
208 // a bit awkward: draw the lines additionally to polygon, to avoid
209 // missing pixels, when polygon is extremly flat
210 l = new QCanvasLine(canvas);
211 l->setPen( QPen(linkcolor, 1) );
218 case StylePolyParabel:
219 p = new QCanvasPolygon(canvas);
220 p->setBrush( linkcolor );
226 pa0.resize (arcsegs*2+2);
227 pa1.resize (arcsegs+1);
228 pa2.resize (arcsegs+1);
231 // a bit awkward: draw the lines additionally
232 // to polygon, to avoid missing pixels,
233 // if polygon is extremly flat
234 for (i=0;i<arcsegs;i++)
236 cl = new QCanvasLine(canvas);
237 cl->setPen( QPen(linkcolor, 1) );
238 cl->setPoints( 0,0,i*10,100);
253 qWarning ("Error: ChildObj or parObj == NULL in LinkableMapObj::setLinkStyle\n");
257 LinkStyle LinkableMapObj::getLinkStyle()
262 void LinkableMapObj::setLinkPos(LinkPos lp)
267 LinkPos LinkableMapObj::getLinkPos()
273 void LinkableMapObj::setLinkColor()
275 // Overloaded in BranchObj and childs
276 // here only set default color
277 setLinkColor (mapEditor->getDefLinkColor());
280 void LinkableMapObj::setLinkColor(QColor col)
283 bottomline->setPen( QPen(linkcolor, 1) );
288 l->setPen( QPen(col,1));
291 for (cl=segment.first(); cl; cl=segment.next() )
292 cl->setPen( QPen(col,1));
295 p->setBrush( QBrush(col));
296 l->setPen( QPen(col,1));
298 case StylePolyParabel:
299 p->setBrush( QBrush(col));
300 for (cl=segment.first(); cl; cl=segment.next() )
301 cl->setPen( QPen(col,1));
309 QColor LinkableMapObj::getLinkColor()
314 FrameType LinkableMapObj::getFrameType()
316 return frame->getFrameType();
319 void LinkableMapObj::setFrameType(const FrameType &t)
321 frame->setFrameType(t);
327 void LinkableMapObj::setFrameType(const QString &t)
329 frame->setFrameType(t);
335 void LinkableMapObj::setVisibility (bool v)
337 MapObj::setVisibility (v);
341 // FIXME lines and segments should be done in LMO?
342 if (style==StyleLine && l)
348 for (cl=segment.first(); cl; cl=segment.next() )
354 if (style==StyleLine && l)
360 for (cl=segment.first(); cl; cl=segment.next() )
366 void LinkableMapObj::updateLink()
369 // childPos of parent
378 // drawing of the link itself
381 // updateLink is called from move, but called from constructor we don't
382 // have parents yet...
383 if (style==StyleUndef) return;
385 if (frame->getFrameType() == NoFrame)
392 offset=bbox.height() /2;
395 offset=bbox.height()-1; // draw link to bottom of bbox
399 double p2x,p2y; // Set P2 Before setting
402 p2x=QPoint( parObj->getChildPos() ).x(); // P1, we have to look at
403 p2y=QPoint( parObj->getChildPos() ).y(); // orientation
406 p2x=QPoint( parObj->getParPos() ).x();
407 p2y=QPoint( parObj->getParPos() ).y();
410 LinkOrient orientOld=orientation;
412 // Set orientation, first look for orientation of parent
413 if (parObj->getOrientation() != OrientUndef )
414 // use the orientation of the parent:
415 orientation=parObj->getOrientation();
418 // calc orientation depending on position rel to mapCenter
419 if (absPos.x() < QPoint(parObj->getChildPos() ).x() )
420 orientation=OrientLeftOfCenter;
422 orientation=OrientRightOfCenter;
425 if ((orientation!=orientOld) && (orientOld!= OrientUndef))
427 // Orientation just changed. Reorient this subbranch, because move is called
428 // before updateLink => Position is still the old one, which could lead to
429 // linking of subranch to itself => segfault
431 // Also possible: called in BranchObj::init(), then orientOld==OrientUndef,
432 // no need to reposition now
436 if (orientation==OrientLeftOfCenter )
438 childPos=QPoint (absPos.x(),absPos.y()+offset);
439 parPos=QPoint (absPos.x()+ bbox.width(), absPos.y() + offset );
442 childPos=QPoint (absPos.x()+ bbox.width(), absPos.y() + offset );
443 parPos=QPoint (absPos.x(),absPos.y()+offset);
446 cout << " LMO::updateLink absPos="<<absPos<<endl;
447 cout << " LMO::updateLink childPos="<<childPos<<endl;
448 cout << " LMO::updateLink parPos="<<parPos<<endl;
449 cout << " LMO::updateLink offset="<<offset<<endl;
450 cout << " LMO::updateLink bbox.w="<<bbox.width()<<endl;
451 cout << " LMO::updateLink bbox.h="<<bbox.height()<<endl;
454 double p1x=parPos.x(); // Link is drawn from P1 to P2
455 double p1y=parPos.y();
457 double vx=p2x - p1x; // V=P2-P1
460 // Draw the horizontal line below heading (from ChildPos to ParPos)
461 bottomline->setPoints (lrint(childPos.x()),
467 if (vx > -0.000001 && vx < 0.000001)
471 // "turning point" for drawing polygonal links
472 QPoint tp (-lrint(sin (a)*thickness_start), lrint(cos (a)*thickness_start));
482 l->setPoints( lrint (parPos.x()),
488 parabel (pa0, p1x,p1y,p2x,p2y);
490 for (cl=segment.first(); cl; cl=segment.next() )
492 cl->setPoints( pa0.point(i).x(), pa0.point(i).y(),pa0.point(i+1).x(),pa0.point(i+1).y());
497 pa0[0]=QPoint (lrint(p2x+tp.x()), lrint(p2y+tp.y()));
498 pa0[1]=QPoint (lrint(p2x-tp.x()), lrint(p2y-tp.y()));
499 pa0[2]=QPoint (lrint (parPos.x()), lrint(parPos.y()) );
501 // here too, draw line to avoid missing pixels
502 l->setPoints( lrint (parPos.x()),
507 case StylePolyParabel:
508 parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
509 parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
510 for (i=0;i<=arcsegs;i++)
512 // Combine the arrays to a single one
514 pa0[i+arcsegs+1]=pa2[arcsegs-i];
518 for (cl=segment.first(); cl; cl=segment.next() )
520 cl->setPoints( pa1.point(i).x(), pa1.point(i).y(),pa1.point(i+1).x(),pa1.point(i+1).y());
529 LinkableMapObj* LinkableMapObj::getChildObj()
534 LinkableMapObj* LinkableMapObj::getParObj()
539 QPoint LinkableMapObj::getChildPos()
544 QPoint LinkableMapObj::getParPos()
549 QPoint LinkableMapObj::getRelPos()
551 if (!parObj) return QPoint (0,0);
553 absPos.x() - parObj->x(),
554 absPos.y() - parObj->y()
558 LinkOrient LinkableMapObj::getOrientation()
563 int LinkableMapObj::getDepth()
568 void LinkableMapObj::setMapEditor (MapEditor *me)
573 MapEditor* LinkableMapObj::getMapEditor ()
578 QPoint LinkableMapObj::getRandPos()
580 // Choose a random position with given distance to parent:
581 double a=rand()%360 * 2 * M_PI / 360;
582 return QPoint ( (int)( + 150*cos (a)),
583 (int)( + 150*sin (a)));
586 void LinkableMapObj::alignRelativeTo (QPoint ref)
590 void LinkableMapObj::reposition()
594 // only calculate the sizes once. If the deepest LMO changes its height,
595 // all upper LMOs have to change, too.
596 calcBBoxSizeWithChilds();
598 alignRelativeTo ( QPoint (absPos.x(),
599 absPos.y()-(bboxTotal.height()-bbox.height())/2) );
602 // This is only important for moving branches:
603 // For editing a branch it isn't called...
604 alignRelativeTo ( QPoint (absPos.x(),
605 absPos.y()-(bboxTotal.height()-bbox.height())/2) );
609 void LinkableMapObj::requestReposition()
611 if (!repositionRequest)
613 // Pass on the request to parental objects, if this hasn't
615 repositionRequest=true;
616 if (parObj) parObj->requestReposition();
620 void LinkableMapObj::forceReposition()
622 // Sometimes a reposition has to be done immediatly: For example
623 // if the note editor flag changes, there is no user event in mapeditor
624 // which could collect requests for a reposition.
625 // Then we have to call forceReposition()
626 // But no rule without exception: While loading a map or undoing it,
627 // we want to block expensive repositioning, but just do it once at
628 // the end, thus check first:
630 if (mapEditor->blockReposition()) return;
632 // Pass on the request to parental objects, if this hasn't been done yet
635 parObj->forceReposition();
640 bool LinkableMapObj::repositionRequested()
642 return repositionRequest;
646 void LinkableMapObj::setSelBox()
648 selbox->setX (bbox.x() );
649 selbox->setY (bbox.y() );
650 selbox->setSize (bbox.width(), bbox.height() );
653 void LinkableMapObj::select()
661 void LinkableMapObj::unselect()
667 void LinkableMapObj::parabel (QPointArray &ya, double p1x, double p1y, double p2x, double p2y)
670 double vx=p2x - p1x; // V=P2-P1
673 double dx; // delta x during calculation of parabel
675 double pnx; // next point
679 if (vx > -0.0001 && vx < 0.0001)
685 ya.setPoint (0,QPoint (lrint(p1x),lrint(p1y)));
686 for (i=1;i<=arcsegs;i++)
689 pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
690 ya.setPoint (i,QPoint (lrint(pnx),lrint(pny)));