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)
164 if (childObj!=NULL && parObj != NULL)
174 l = new QCanvasLine(canvas);
175 l->setPen( QPen(linkcolor, 1) );
183 for (i=0;i<arcsegs;i++)
185 cl = new QCanvasLine(canvas);
186 cl->setPen( QPen(linkcolor, 1) );
187 cl->setPoints( 0,0,i*10,100);
195 pa0.resize (arcsegs+1);
198 p = new QCanvasPolygon(canvas);
199 p->setBrush( linkcolor );
207 // a bit awkward: draw the lines additionally to polygon, to avoid
208 // missing pixels, when polygon is extremly flat
209 l = new QCanvasLine(canvas);
210 l->setPen( QPen(linkcolor, 1) );
217 case StylePolyParabel:
218 p = new QCanvasPolygon(canvas);
219 p->setBrush( linkcolor );
225 pa0.resize (arcsegs*2+2);
226 pa1.resize (arcsegs+1);
227 pa2.resize (arcsegs+1);
230 // a bit awkward: draw the lines additionally
231 // to polygon, to avoid missing pixels,
232 // if polygon is extremly flat
233 for (i=0;i<arcsegs;i++)
235 cl = new QCanvasLine(canvas);
236 cl->setPen( QPen(linkcolor, 1) );
237 cl->setPoints( 0,0,i*10,100);
251 cout << "Error: ChildObj or parObj == NULL in LinkableMapObj::setLinkStyle\n";
255 LinkStyle LinkableMapObj::getLinkStyle()
260 void LinkableMapObj::setLinkPos(LinkPos lp)
265 LinkPos LinkableMapObj::getLinkPos()
271 void LinkableMapObj::setLinkColor()
273 // Overloaded in BranchObj and childs
274 // here only set default color
275 setLinkColor (mapEditor->getDefLinkColor());
278 void LinkableMapObj::setLinkColor(QColor col)
281 bottomline->setPen( QPen(linkcolor, 1) );
286 l->setPen( QPen(col,1));
289 for (cl=segment.first(); cl; cl=segment.next() )
290 cl->setPen( QPen(col,1));
293 p->setBrush( QBrush(col));
294 l->setPen( QPen(col,1));
296 case StylePolyParabel:
297 p->setBrush( QBrush(col));
298 for (cl=segment.first(); cl; cl=segment.next() )
299 cl->setPen( QPen(col,1));
307 QColor LinkableMapObj::getLinkColor()
312 FrameType LinkableMapObj::getFrameType()
314 return frame->getFrameType();
317 void LinkableMapObj::setFrameType(const FrameType &t)
319 frame->setFrameType(t);
325 void LinkableMapObj::setFrameType(const QString &t)
327 frame->setFrameType(t);
333 void LinkableMapObj::setVisibility (bool v)
335 MapObj::setVisibility (v);
339 // FIXME lines and segments should be done in LMO?
340 if (style==StyleLine && l)
346 for (cl=segment.first(); cl; cl=segment.next() )
352 if (style==StyleLine && l)
358 for (cl=segment.first(); cl; cl=segment.next() )
364 void LinkableMapObj::updateLink()
367 // childPos of parent
376 // drawing of the link itself
379 // updateLink is called from move, but called from constructor we don't
380 // have parents yet...
381 if (style==StyleUndef) return;
383 if (frame->getFrameType() == NoFrame)
390 offset=bbox.height() /2;
393 offset=bbox.height()-1; // draw link to bottom of bbox
397 double p2x,p2y; // Set P2 Before setting
400 p2x=QPoint( parObj->getChildPos() ).x(); // P1, we have to look at
401 p2y=QPoint( parObj->getChildPos() ).y(); // orientation
404 p2x=QPoint( parObj->getParPos() ).x();
405 p2y=QPoint( parObj->getParPos() ).y();
408 LinkOrient orientOld=orientation;
410 // Set orientation, first look for orientation of parent
411 if (parObj->getOrientation() != OrientUndef )
412 // use the orientation of the parent:
413 orientation=parObj->getOrientation();
416 // calc orientation depending on position rel to mapCenter
417 if (absPos.x() < QPoint(parObj->getChildPos() ).x() )
418 orientation=OrientLeftOfCenter;
420 orientation=OrientRightOfCenter;
423 if ((orientation!=orientOld) && (orientOld!= OrientUndef))
425 // Orientation just changed. Reorient this subbranch, because move is called
426 // before updateLink => Position is still the old one, which could lead to
427 // linking of subranch to itself => segfault
429 // Also possible: called in BranchObj::init(), then orientOld==OrientUndef,
430 // no need to reposition now
434 if (orientation==OrientLeftOfCenter )
436 childPos=QPoint (absPos.x(),absPos.y()+offset);
437 parPos=QPoint (absPos.x()+ bbox.width(), absPos.y() + offset );
440 childPos=QPoint (absPos.x()+ bbox.width(), absPos.y() + offset );
441 parPos=QPoint (absPos.x(),absPos.y()+offset);
444 cout << " LMO::updateLink absPos="<<absPos<<endl;
445 cout << " LMO::updateLink childPos="<<childPos<<endl;
446 cout << " LMO::updateLink parPos="<<parPos<<endl;
447 cout << " LMO::updateLink offset="<<offset<<endl;
448 cout << " LMO::updateLink bbox.w="<<bbox.width()<<endl;
449 cout << " LMO::updateLink bbox.h="<<bbox.height()<<endl;
452 double p1x=parPos.x(); // Link is drawn from P1 to P2
453 double p1y=parPos.y();
455 double vx=p2x - p1x; // V=P2-P1
458 // Draw the horizontal line below heading (from ChildPos to ParPos)
459 bottomline->setPoints (lrint(childPos.x()),
465 if (vx > -0.000001 && vx < 0.000001)
469 // "turning point" for drawing polygonal links
470 QPoint tp (-lrint(sin (a)*thickness_start), lrint(cos (a)*thickness_start));
480 l->setPoints( lrint (parPos.x()),
486 parabel (pa0, p1x,p1y,p2x,p2y);
488 for (cl=segment.first(); cl; cl=segment.next() )
490 cl->setPoints( pa0.point(i).x(), pa0.point(i).y(),pa0.point(i+1).x(),pa0.point(i+1).y());
495 pa0[0]=QPoint (lrint(p2x+tp.x()), lrint(p2y+tp.y()));
496 pa0[1]=QPoint (lrint(p2x-tp.x()), lrint(p2y-tp.y()));
497 pa0[2]=QPoint (lrint (parPos.x()), lrint(parPos.y()) );
499 // here too, draw line to avoid missing pixels
500 l->setPoints( lrint (parPos.x()),
505 case StylePolyParabel:
506 parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
507 parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
508 for (i=0;i<=arcsegs;i++)
510 // Combine the arrays to a single one
512 pa0[i+arcsegs+1]=pa2[arcsegs-i];
516 for (cl=segment.first(); cl; cl=segment.next() )
518 cl->setPoints( pa1.point(i).x(), pa1.point(i).y(),pa1.point(i+1).x(),pa1.point(i+1).y());
527 LinkableMapObj* LinkableMapObj::getChildObj()
532 LinkableMapObj* LinkableMapObj::getParObj()
537 QPoint LinkableMapObj::getChildPos()
542 QPoint LinkableMapObj::getParPos()
547 QPoint LinkableMapObj::getRelPos()
549 if (!parObj) return QPoint (0,0);
551 absPos.x() - parObj->x(),
552 absPos.y() - parObj->y()
556 LinkOrient LinkableMapObj::getOrientation()
561 int LinkableMapObj::getDepth()
566 void LinkableMapObj::setMapEditor (MapEditor *me)
571 MapEditor* LinkableMapObj::getMapEditor ()
576 QPoint LinkableMapObj::getRandPos()
578 // Choose a random position with given distance to parent:
579 double a=rand()%360 * 2 * M_PI / 360;
580 return QPoint ( (int)( + 150*cos (a)),
581 (int)( + 150*sin (a)));
584 void LinkableMapObj::alignRelativeTo (QPoint ref)
588 void LinkableMapObj::reposition()
590 cout << "LMO::reposition ???"<<endl;
593 // only calculate the sizes once. If the deepest LMO changes its height,
594 // all upper LMOs have to change, too.
595 calcBBoxSizeWithChilds();
597 alignRelativeTo ( QPoint (absPos.x(),
598 absPos.y()-(bboxTotal.height()-bbox.height())/2) );
601 // This is only important for moving branches:
602 // For editing a branch it isn't called...
603 alignRelativeTo ( QPoint (absPos.x(),
604 absPos.y()-(bboxTotal.height()-bbox.height())/2) );
608 void LinkableMapObj::requestReposition()
610 if (!repositionRequest)
612 // Pass on the request to parental objects, if this hasn't
614 repositionRequest=true;
615 if (parObj) parObj->requestReposition();
619 void LinkableMapObj::forceReposition()
621 // Sometimes a reposition has to be done immediatly: For example
622 // if the note editor flag changes, there is no user event in mapeditor
623 // which could collect requests for a reposition.
624 // Then we have to call forceReposition()
625 // But no rule without exception: While loading a map or undoing it,
626 // we want to block expensive repositioning, but just do it once at
627 // the end, thus check first:
629 if (mapEditor->blockReposition()) return;
631 // Pass on the request to parental objects, if this hasn't been done yet
634 parObj->forceReposition();
638 bool LinkableMapObj::repositionRequested()
640 return repositionRequest;
644 void LinkableMapObj::setSelBox()
646 selbox->setX (bbox.x() );
647 selbox->setY (bbox.y() );
648 selbox->setSize (bbox.width(), bbox.height() );
651 void LinkableMapObj::select()
659 void LinkableMapObj::unselect()
665 void LinkableMapObj::parabel (QPointArray &ya, double p1x, double p1y, double p2x, double p2y)
668 double vx=p2x - p1x; // V=P2-P1
671 double dx; // delta x during calculation of parabel
673 double pnx; // next point
677 if (vx > -0.0001 && vx < 0.0001)
683 ya.setPoint (0,QPoint (lrint(p1x),lrint(p1y)));
684 for (i=1;i<=arcsegs;i++)
687 pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
688 ya.setPoint (i,QPoint (lrint(pnx),lrint(pny)));