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 setLinkStyle(other->style);
105 setLinkColor (other->linkcolor);
108 void LinkableMapObj::setChildObj(LinkableMapObj* o)
113 void LinkableMapObj::setParObj(LinkableMapObj* o)
116 mapEditor=parObj->getMapEditor();
119 void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPoint,int)
123 void LinkableMapObj::unsetParObjTmp()
127 LinkStyle LinkableMapObj::getDefLinkStyle ()
129 LinkStyle ls=mapEditor->getLinkStyle();
144 case StylePolyParabel:
156 void LinkableMapObj::setLinkStyle(LinkStyle newstyle)
158 //if (newstyle=style) return;
163 if (childObj!=NULL && parObj != NULL)
173 l = new QCanvasLine(canvas);
174 l->setPen( QPen(linkcolor, 1) );
182 for (i=0;i<arcsegs;i++)
184 cl = new QCanvasLine(canvas);
185 cl->setPen( QPen(linkcolor, 1) );
186 cl->setPoints( 0,0,i*10,100);
194 pa0.resize (arcsegs+1);
197 p = new QCanvasPolygon(canvas);
198 p->setBrush( linkcolor );
206 // a bit awkward: draw the lines additionally to polygon, to avoid
207 // missing pixels, when polygon is extremly flat
208 l = new QCanvasLine(canvas);
209 l->setPen( QPen(linkcolor, 1) );
216 case StylePolyParabel:
217 p = new QCanvasPolygon(canvas);
218 p->setBrush( linkcolor );
224 pa0.resize (arcsegs*2+2);
225 pa1.resize (arcsegs+1);
226 pa2.resize (arcsegs+1);
229 // a bit awkward: draw the lines additionally
230 // to polygon, to avoid missing pixels,
231 // if polygon is extremly flat
232 for (i=0;i<arcsegs;i++)
234 cl = new QCanvasLine(canvas);
235 cl->setPen( QPen(linkcolor, 1) );
236 cl->setPoints( 0,0,i*10,100);
248 // FIXME updateLink is usually called (multiple times) later:
252 qWarning ("Error: ChildObj or parObj == NULL in LinkableMapObj::setLinkStyle\n");
256 LinkStyle LinkableMapObj::getLinkStyle()
261 void LinkableMapObj::setLinkPos(LinkPos lp)
266 LinkPos LinkableMapObj::getLinkPos()
272 void LinkableMapObj::setLinkColor()
274 // Overloaded in BranchObj and childs
275 // here only set default color
276 setLinkColor (mapEditor->getDefLinkColor());
279 void LinkableMapObj::setLinkColor(QColor col)
282 bottomline->setPen( QPen(linkcolor, 1) );
287 l->setPen( QPen(col,1));
290 for (cl=segment.first(); cl; cl=segment.next() )
291 cl->setPen( QPen(col,1));
294 p->setBrush( QBrush(col));
295 l->setPen( QPen(col,1));
297 case StylePolyParabel:
298 p->setBrush( QBrush(col));
299 for (cl=segment.first(); cl; cl=segment.next() )
300 cl->setPen( QPen(col,1));
305 //FIXME updateLink();
308 QColor LinkableMapObj::getLinkColor()
313 FrameType LinkableMapObj::getFrameType()
315 return frame->getFrameType();
318 void LinkableMapObj::setFrameType(const FrameType &t)
320 frame->setFrameType(t);
326 void LinkableMapObj::setFrameType(const QString &t)
328 frame->setFrameType(t);
334 void LinkableMapObj::setVisibility (bool v)
336 MapObj::setVisibility (v);
340 // FIXME lines and segments should be done in LMO?
341 if (style==StyleLine && l)
347 for (cl=segment.first(); cl; cl=segment.next() )
353 if (style==StyleLine && l)
359 for (cl=segment.first(); cl; cl=segment.next() )
365 void LinkableMapObj::updateLink()
368 // childPos of parent
377 // drawing of the link itself
380 // updateLink is called from move, but called from constructor we don't
381 // have parents yet...
382 if (style==StyleUndef) return;
384 if (frame->getFrameType() == NoFrame)
391 offset=bbox.height() /2;
394 offset=bbox.height()-1; // draw link to bottom of bbox
398 double p2x,p2y; // Set P2 Before setting
401 p2x=QPoint( parObj->getChildPos() ).x(); // P1, we have to look at
402 p2y=QPoint( parObj->getChildPos() ).y(); // orientation
405 p2x=QPoint( parObj->getParPos() ).x();
406 p2y=QPoint( parObj->getParPos() ).y();
409 LinkOrient orientOld=orientation;
411 // Set orientation, first look for orientation of parent
412 if (parObj->getOrientation() != OrientUndef )
413 // use the orientation of the parent:
414 orientation=parObj->getOrientation();
417 // calc orientation depending on position rel to mapCenter
418 if (absPos.x() < QPoint(parObj->getChildPos() ).x() )
419 orientation=OrientLeftOfCenter;
421 orientation=OrientRightOfCenter;
424 if ((orientation!=orientOld) && (orientOld!= OrientUndef))
426 // Orientation just changed. Reorient this subbranch, because move is called
427 // before updateLink => Position is still the old one, which could lead to
428 // linking of subranch to itself => segfault
430 // Also possible: called in BranchObj::init(), then orientOld==OrientUndef,
431 // no need to reposition now
435 if (orientation==OrientLeftOfCenter )
437 childPos=QPoint (absPos.x(),absPos.y()+offset);
438 parPos=QPoint (absPos.x()+ bbox.width(), absPos.y() + offset );
441 childPos=QPoint (absPos.x()+ bbox.width(), absPos.y() + offset );
442 parPos=QPoint (absPos.x(),absPos.y()+offset);
445 double p1x=parPos.x(); // Link is drawn from P1 to P2
446 double p1y=parPos.y();
448 double vx=p2x - p1x; // V=P2-P1
451 // Draw the horizontal line below heading (from ChildPos to ParPos)
452 bottomline->setPoints (qRound(childPos.x()),
453 qRound(childPos.y()),
458 if (vx > -0.000001 && vx < 0.000001)
462 // "turning point" for drawing polygonal links
463 QPoint tp (-qRound(sin (a)*thickness_start), qRound(cos (a)*thickness_start));
473 l->setPoints( qRound (parPos.x()),
479 parabel (pa0, p1x,p1y,p2x,p2y);
481 for (cl=segment.first(); cl; cl=segment.next() )
483 cl->setPoints( pa0.point(i).x(), pa0.point(i).y(),pa0.point(i+1).x(),pa0.point(i+1).y());
488 pa0[0]=QPoint (qRound(p2x+tp.x()), qRound(p2y+tp.y()));
489 pa0[1]=QPoint (qRound(p2x-tp.x()), qRound(p2y-tp.y()));
490 pa0[2]=QPoint (qRound (parPos.x()), qRound(parPos.y()) );
492 // here too, draw line to avoid missing pixels
493 l->setPoints( qRound (parPos.x()),
498 case StylePolyParabel:
499 parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
500 parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
501 for (i=0;i<=arcsegs;i++)
503 // Combine the arrays to a single one
505 pa0[i+arcsegs+1]=pa2[arcsegs-i];
509 for (cl=segment.first(); cl; cl=segment.next() )
511 cl->setPoints( pa1.point(i).x(), pa1.point(i).y(),pa1.point(i+1).x(),pa1.point(i+1).y());
520 LinkableMapObj* LinkableMapObj::getChildObj()
525 LinkableMapObj* LinkableMapObj::getParObj()
530 LinkableMapObj* LinkableMapObj::findObjBySelect (QString s)
532 LinkableMapObj *lmo=this;
536 while (!s.isEmpty() )
538 part=s.section(",",0,0);
540 num=part.right(part.length() - 3);
544 return false; // in a subtree there is no center
549 lmo=((BranchObj*)(lmo))->getBranchNum (num.toUInt());
552 lmo=((BranchObj*)(lmo))->getFloatImageNum (num.toUInt());
556 s=s.right(s.length() - part.length() -1 );
563 QPoint LinkableMapObj::getChildPos()
568 QPoint LinkableMapObj::getParPos()
573 QPoint LinkableMapObj::getRelPos()
575 if (!parObj) return QPoint (0,0);
577 absPos.x() - parObj->x(),
578 absPos.y() - parObj->y()
582 LinkOrient LinkableMapObj::getOrientation()
587 int LinkableMapObj::getDepth()
592 void LinkableMapObj::setMapEditor (MapEditor *me)
597 MapEditor* LinkableMapObj::getMapEditor ()
602 QPoint LinkableMapObj::getRandPos()
604 // Choose a random position with given distance to parent:
605 double a=rand()%360 * 2 * M_PI / 360;
606 return QPoint ( (int)( + 150*cos (a)),
607 (int)( + 150*sin (a)));
610 void LinkableMapObj::alignRelativeTo (QPoint ref)
612 cout << "LMO::alignRelTo ref="<<ref<<endl;
616 void LinkableMapObj::reposition()
620 // only calculate the sizes once. If the deepest LMO changes its height,
621 // all upper LMOs have to change, too.
622 calcBBoxSizeWithChilds();
624 alignRelativeTo ( QPoint (absPos.x(),
625 absPos.y()-(bboxTotal.height()-bbox.height())/2) );
628 // This is only important for moving branches:
629 // For editing a branch it isn't called...
630 alignRelativeTo ( QPoint (absPos.x(),
631 absPos.y()-(bboxTotal.height()-bbox.height())/2) );
635 void LinkableMapObj::requestReposition()
637 if (!repositionRequest)
639 // Pass on the request to parental objects, if this hasn't
641 repositionRequest=true;
642 if (parObj) parObj->requestReposition();
646 void LinkableMapObj::forceReposition()
648 // Sometimes a reposition has to be done immediatly: For example
649 // if the note editor flag changes, there is no user event in mapeditor
650 // which could collect requests for a reposition.
651 // Then we have to call forceReposition()
652 // But no rule without exception: While loading a map or undoing it,
653 // we want to block expensive repositioning, but just do it once at
654 // the end, thus check first:
656 if (mapEditor->isRepositionBlocked()) return;
658 // Pass on the request to parental objects, if this hasn't been done yet
661 parObj->forceReposition();
666 bool LinkableMapObj::repositionRequested()
668 return repositionRequest;
672 void LinkableMapObj::setSelBox()
674 selbox->setX (bbox.x() );
675 selbox->setY (bbox.y() );
676 selbox->setSize (bbox.width(), bbox.height() );
679 void LinkableMapObj::select()
687 void LinkableMapObj::unselect()
693 void LinkableMapObj::parabel (QPointArray &ya, double p1x, double p1y, double p2x, double p2y)
696 double vx=p2x - p1x; // V=P2-P1
699 double dx; // delta x during calculation of parabel
701 double pnx; // next point
705 if (vx > -0.0001 && vx < 0.0001)
711 ya.setPoint (0,QPoint (qRound(p1x),qRound(p1y)));
712 for (i=1;i<=arcsegs;i++)
715 pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
716 ya.setPoint (i,QPoint (qRound(pnx),qRound(pny)));