1 #include "linkablemapobj.h"
8 /////////////////////////////////////////////////////////////////
10 /////////////////////////////////////////////////////////////////
12 LinkableMapObj::LinkableMapObj():MapObj()
14 // cout << "Const LinkableMapObj ()\n";
18 LinkableMapObj::LinkableMapObj(QCanvas* c) :MapObj(c)
20 // cout << "Const LinkableMapObj\n";
24 LinkableMapObj::LinkableMapObj (LinkableMapObj* lmo) : MapObj (lmo->canvas)
29 LinkableMapObj::~LinkableMapObj()
37 void LinkableMapObj::delLink()
51 case StylePolyParabel:
60 void LinkableMapObj::init ()
70 orientation=OrientUndef;
75 segment.setAutoDelete (TRUE);
77 QPointArray pa(arcsegs*2+2);
79 bottomline=new QCanvasLine(canvas);
80 bottomline->setPen( QPen(linkcolor, 1) );
81 bottomline->setZ(Z_LINK);
84 // Prepare showing the selection of a MapObj
85 selbox = new QCanvasRectangle (canvas);
86 selbox->setZ(Z_SELBOX);
87 selbox->setBrush( QColor(255,255,0) );
88 selbox->setPen( QPen(QColor(255,255,0) ));
93 frame = new FrameObj (canvas);
95 repositionRequest=false;
98 void LinkableMapObj::copy (LinkableMapObj* other)
101 bboxTotal=other->bboxTotal;
102 setLinkStyle(other->style);
103 setLinkColor (other->linkcolor);
106 void LinkableMapObj::setChildObj(LinkableMapObj* o)
111 void LinkableMapObj::setParObj(LinkableMapObj* o)
114 mapEditor=parObj->getMapEditor();
117 void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPoint,int)
121 void LinkableMapObj::unsetParObjTmp()
125 LinkStyle LinkableMapObj::getDefLinkStyle ()
127 LinkStyle ls=mapEditor->getLinkStyle();
142 case StylePolyParabel:
154 void LinkableMapObj::setLinkStyle(LinkStyle newstyle)
156 //if (newstyle=style) return;
161 if (childObj!=NULL && parObj != NULL)
171 l = new QCanvasLine(canvas);
172 l->setPen( QPen(linkcolor, 1) );
180 for (i=0;i<arcsegs;i++)
182 cl = new QCanvasLine(canvas);
183 cl->setPen( QPen(linkcolor, 1) );
184 cl->setPoints( 0,0,i*10,100);
192 pa0.resize (arcsegs+1);
195 p = new QCanvasPolygon(canvas);
196 p->setBrush( linkcolor );
204 // a bit awkward: draw the lines additionally to polygon, to avoid
205 // missing pixels, when polygon is extremly flat
206 l = new QCanvasLine(canvas);
207 l->setPen( QPen(linkcolor, 1) );
214 case StylePolyParabel:
215 p = new QCanvasPolygon(canvas);
216 p->setBrush( linkcolor );
222 pa0.resize (arcsegs*2+2);
223 pa1.resize (arcsegs+1);
224 pa2.resize (arcsegs+1);
227 // a bit awkward: draw the lines additionally
228 // to polygon, to avoid missing pixels,
229 // if polygon is extremly flat
230 for (i=0;i<arcsegs;i++)
232 cl = new QCanvasLine(canvas);
233 cl->setPen( QPen(linkcolor, 1) );
234 cl->setPoints( 0,0,i*10,100);
246 // FIXME updateLink is usually called (multiple times) later:
250 qWarning ("Error: ChildObj or parObj == NULL in LinkableMapObj::setLinkStyle\n");
254 LinkStyle LinkableMapObj::getLinkStyle()
259 void LinkableMapObj::setLinkPos(LinkPos lp)
264 LinkPos LinkableMapObj::getLinkPos()
270 void LinkableMapObj::setLinkColor()
272 // Overloaded in BranchObj and childs
273 // here only set default color
274 setLinkColor (mapEditor->getDefLinkColor());
277 void LinkableMapObj::setLinkColor(QColor col)
280 bottomline->setPen( QPen(linkcolor, 1) );
285 l->setPen( QPen(col,1));
288 for (cl=segment.first(); cl; cl=segment.next() )
289 cl->setPen( QPen(col,1));
292 p->setBrush( QBrush(col));
293 l->setPen( QPen(col,1));
295 case StylePolyParabel:
296 p->setBrush( QBrush(col));
297 for (cl=segment.first(); cl; cl=segment.next() )
298 cl->setPen( QPen(col,1));
303 //FIXME updateLink();
306 QColor LinkableMapObj::getLinkColor()
311 FrameType LinkableMapObj::getFrameType()
313 return frame->getFrameType();
316 void LinkableMapObj::setFrameType(const FrameType &t)
318 frame->setFrameType(t);
324 void LinkableMapObj::setFrameType(const QString &t)
326 frame->setFrameType(t);
332 void LinkableMapObj::setVisibility (bool v)
334 MapObj::setVisibility (v);
338 // FIXME lines and segments should be done in LMO?
339 if (style==StyleLine && l)
345 for (cl=segment.first(); cl; cl=segment.next() )
351 if (style==StyleLine && l)
357 for (cl=segment.first(); cl; cl=segment.next() )
363 void LinkableMapObj::updateLink()
366 // childPos of parent
375 // drawing of the link itself
378 // updateLink is called from move, but called from constructor we don't
379 // have parents yet...
380 if (style==StyleUndef) return;
382 if (frame->getFrameType() == NoFrame)
389 offset=bbox.height() /2;
392 offset=bbox.height()-1; // draw link to bottom of bbox
396 double p2x,p2y; // Set P2 Before setting
399 p2x=QPoint( parObj->getChildPos() ).x(); // P1, we have to look at
400 p2y=QPoint( parObj->getChildPos() ).y(); // orientation
403 p2x=QPoint( parObj->getParPos() ).x();
404 p2y=QPoint( parObj->getParPos() ).y();
407 LinkOrient orientOld=orientation;
409 // Set orientation, first look for orientation of parent
410 if (parObj->getOrientation() != OrientUndef )
411 // use the orientation of the parent:
412 orientation=parObj->getOrientation();
415 // calc orientation depending on position rel to mapCenter
416 if (absPos.x() < QPoint(parObj->getChildPos() ).x() )
417 orientation=OrientLeftOfCenter;
419 orientation=OrientRightOfCenter;
422 if ((orientation!=orientOld) && (orientOld!= OrientUndef))
424 // Orientation just changed. Reorient this subbranch, because move is called
425 // before updateLink => Position is still the old one, which could lead to
426 // linking of subranch to itself => segfault
428 // Also possible: called in BranchObj::init(), then orientOld==OrientUndef,
429 // no need to reposition now
433 if (orientation==OrientLeftOfCenter )
435 childPos=QPoint (absPos.x(),absPos.y()+offset);
436 parPos=QPoint (absPos.x()+ bbox.width(), absPos.y() + offset );
439 childPos=QPoint (absPos.x()+ bbox.width(), absPos.y() + offset );
440 parPos=QPoint (absPos.x(),absPos.y()+offset);
443 double p1x=parPos.x(); // Link is drawn from P1 to P2
444 double p1y=parPos.y();
446 double vx=p2x - p1x; // V=P2-P1
449 // Draw the horizontal line below heading (from ChildPos to ParPos)
450 bottomline->setPoints (qRound(childPos.x()),
451 qRound(childPos.y()),
456 if (vx > -0.000001 && vx < 0.000001)
460 // "turning point" for drawing polygonal links
461 QPoint tp (-qRound(sin (a)*thickness_start), qRound(cos (a)*thickness_start));
471 l->setPoints( qRound (parPos.x()),
477 parabel (pa0, p1x,p1y,p2x,p2y);
479 for (cl=segment.first(); cl; cl=segment.next() )
481 cl->setPoints( pa0.point(i).x(), pa0.point(i).y(),pa0.point(i+1).x(),pa0.point(i+1).y());
486 pa0[0]=QPoint (qRound(p2x+tp.x()), qRound(p2y+tp.y()));
487 pa0[1]=QPoint (qRound(p2x-tp.x()), qRound(p2y-tp.y()));
488 pa0[2]=QPoint (qRound (parPos.x()), qRound(parPos.y()) );
490 // here too, draw line to avoid missing pixels
491 l->setPoints( qRound (parPos.x()),
496 case StylePolyParabel:
497 parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
498 parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
499 for (i=0;i<=arcsegs;i++)
501 // Combine the arrays to a single one
503 pa0[i+arcsegs+1]=pa2[arcsegs-i];
507 for (cl=segment.first(); cl; cl=segment.next() )
509 cl->setPoints( pa1.point(i).x(), pa1.point(i).y(),pa1.point(i+1).x(),pa1.point(i+1).y());
518 LinkableMapObj* LinkableMapObj::getChildObj()
523 LinkableMapObj* LinkableMapObj::getParObj()
528 LinkableMapObj* LinkableMapObj::findObjBySelect (QString s)
530 LinkableMapObj *lmo=this;
534 while (!s.isEmpty() )
536 part=s.section(",",0,0);
538 num=part.right(part.length() - 3);
543 return false; // in a subtree there is no center
548 lmo=((BranchObj*)(lmo))->getBranchNum (num.toUInt());
551 lmo=((BranchObj*)(lmo))->getFloatImageNum (num.toUInt());
555 s=s.right(s.length() - part.length() -1 );
562 QPoint LinkableMapObj::getChildPos()
567 QPoint LinkableMapObj::getParPos()
572 QPoint LinkableMapObj::getRelPos()
574 if (!parObj) return QPoint (0,0);
576 absPos.x() - parObj->x(),
577 absPos.y() - parObj->y()
581 LinkOrient LinkableMapObj::getOrientation()
586 int LinkableMapObj::getDepth()
591 void LinkableMapObj::setMapEditor (MapEditor *me)
596 MapEditor* LinkableMapObj::getMapEditor ()
601 QPoint LinkableMapObj::getRandPos()
603 // Choose a random position with given distance to parent:
604 double a=rand()%360 * 2 * M_PI / 360;
605 return QPoint ( (int)( + 150*cos (a)),
606 (int)( + 150*sin (a)));
609 void LinkableMapObj::alignRelativeTo (QPoint ref)
611 cout << "LMO::alignRelTo ref="<<ref<<endl;
615 void LinkableMapObj::reposition()
619 // only calculate the sizes once. If the deepest LMO changes its height,
620 // all upper LMOs have to change, too.
621 calcBBoxSizeWithChilds();
623 alignRelativeTo ( QPoint (absPos.x(),
624 absPos.y()-(bboxTotal.height()-bbox.height())/2) );
627 // This is only important for moving branches:
628 // For editing a branch it isn't called...
629 alignRelativeTo ( QPoint (absPos.x(),
630 absPos.y()-(bboxTotal.height()-bbox.height())/2) );
634 void LinkableMapObj::requestReposition()
636 if (!repositionRequest)
638 // Pass on the request to parental objects, if this hasn't
640 repositionRequest=true;
641 if (parObj) parObj->requestReposition();
645 void LinkableMapObj::forceReposition()
647 // Sometimes a reposition has to be done immediatly: For example
648 // if the note editor flag changes, there is no user event in mapeditor
649 // which could collect requests for a reposition.
650 // Then we have to call forceReposition()
651 // But no rule without exception: While loading a map or undoing it,
652 // we want to block expensive repositioning, but just do it once at
653 // the end, thus check first:
655 if (mapEditor->blockReposition()) return;
657 // Pass on the request to parental objects, if this hasn't been done yet
660 parObj->forceReposition();
665 bool LinkableMapObj::repositionRequested()
667 return repositionRequest;
671 void LinkableMapObj::setSelBox()
673 selbox->setX (bbox.x() );
674 selbox->setY (bbox.y() );
675 selbox->setSize (bbox.width(), bbox.height() );
678 void LinkableMapObj::select()
686 void LinkableMapObj::unselect()
692 void LinkableMapObj::parabel (QPointArray &ya, double p1x, double p1y, double p2x, double p2y)
695 double vx=p2x - p1x; // V=P2-P1
698 double dx; // delta x during calculation of parabel
700 double pnx; // next point
704 if (vx > -0.0001 && vx < 0.0001)
710 ya.setPoint (0,QPoint (qRound(p1x),qRound(p1y)));
711 for (i=1;i<=arcsegs;i++)
714 pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
715 ya.setPoint (i,QPoint (qRound(pnx),qRound(pny)));