insilmaril@721: #include insilmaril@139: #include insilmaril@139: insilmaril@0: #include "linkablemapobj.h" insilmaril@0: #include "branchobj.h" insilmaril@721: #include "vymmodel.h" insilmaril@721: insilmaril@721: using namespace std; insilmaril@0: insilmaril@0: ///////////////////////////////////////////////////////////////// insilmaril@0: // LinkableMapObj insilmaril@0: ///////////////////////////////////////////////////////////////// insilmaril@0: insilmaril@0: LinkableMapObj::LinkableMapObj():MapObj() insilmaril@0: { insilmaril@0: // cout << "Const LinkableMapObj ()\n"; insilmaril@0: init (); insilmaril@0: } insilmaril@0: insilmaril@408: LinkableMapObj::LinkableMapObj(QGraphicsScene* s) :MapObj(s) insilmaril@0: { insilmaril@408: // cout << "Const LinkableMapObj (s)\n"; insilmaril@0: init (); insilmaril@0: } insilmaril@0: insilmaril@408: LinkableMapObj::LinkableMapObj (LinkableMapObj* lmo) : MapObj (lmo->scene) insilmaril@0: { insilmaril@0: copy (lmo); insilmaril@0: } insilmaril@0: insilmaril@0: LinkableMapObj::~LinkableMapObj() insilmaril@0: { insilmaril@0: delete (bottomline); insilmaril@0: delLink(); insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::delLink() insilmaril@0: { insilmaril@0: switch (style) insilmaril@0: { insilmaril@473: case Line: insilmaril@0: delete (l); insilmaril@0: break; insilmaril@473: case Parabel: insilmaril@406: while (!segment.isEmpty()) delete segment.takeFirst(); insilmaril@0: break; insilmaril@473: case PolyLine: insilmaril@0: delete (p); insilmaril@0: break; insilmaril@473: case PolyParabel: insilmaril@0: delete (p); insilmaril@0: break; insilmaril@0: default: insilmaril@0: break; insilmaril@0: } insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::init () insilmaril@0: { insilmaril@0: parObj=NULL; insilmaril@0: parObjTmpBuf=NULL; insilmaril@408: parPos=QPointF(0,0); insilmaril@408: childPos=QPointF(0,0); insilmaril@0: link2ParPos=false; insilmaril@0: l=NULL; insilmaril@727: p=NULL; insilmaril@473: orientation=UndefinedOrientation; insilmaril@0: linkwidth=20; insilmaril@0: thickness_start=8; insilmaril@473: style=UndefinedStyle; insilmaril@473: linkpos=Bottom; insilmaril@0: arcsegs=13; insilmaril@0: insilmaril@412: // TODO instead of linkcolor pen.color() could be used all around insilmaril@408: pen.setWidth (1); insilmaril@408: pen.setColor (linkcolor); insilmaril@408: pen.setCapStyle ( Qt::RoundCap ); insilmaril@408: bottomline=scene->addLine(QLineF(1,1,1,1),pen); insilmaril@408: bottomline->setZValue(Z_LINK); insilmaril@0: bottomline->show(); insilmaril@0: insilmaril@175: topPad=botPad=leftPad=rightPad=0; insilmaril@175: insilmaril@0: repositionRequest=false; insilmaril@218: insilmaril@218: // Rel Positions insilmaril@408: relPos=QPointF(0,0); insilmaril@250: useRelPos=false; insilmaril@531: insilmaril@726: // Crossreference to treemodel insilmaril@726: treeItem=NULL; insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::copy (LinkableMapObj* other) insilmaril@0: { insilmaril@0: MapObj::copy(other); insilmaril@0: bboxTotal=other->bboxTotal; insilmaril@0: setLinkStyle(other->style); insilmaril@0: setLinkColor (other->linkcolor); insilmaril@218: relPos=other->relPos; insilmaril@726: treeItem=other->treeItem; insilmaril@726: } insilmaril@726: insilmaril@726: void LinkableMapObj::setTreeItem (TreeItem *ti) insilmaril@726: { insilmaril@726: treeItem=ti; insilmaril@726: } insilmaril@726: insilmaril@753: TreeItem* LinkableMapObj::getTreeItem () const insilmaril@726: { insilmaril@726: return treeItem; insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::setParObj(LinkableMapObj* o) insilmaril@0: { insilmaril@0: parObj=o; insilmaril@0: } insilmaril@0: insilmaril@746: void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPointF,int) // FIXME-3 make pure virtual insilmaril@0: { insilmaril@0: } insilmaril@0: insilmaril@746: void LinkableMapObj::unsetParObjTmp() // FIXME-3 make pure virtual insilmaril@0: { insilmaril@0: } insilmaril@0: insilmaril@164: bool LinkableMapObj::hasParObjTmp() insilmaril@164: { insilmaril@164: if (parObjTmpBuf) return true; insilmaril@164: return false; insilmaril@164: } insilmaril@164: insilmaril@218: void LinkableMapObj::setUseRelPos (const bool &b) insilmaril@218: { insilmaril@218: useRelPos=b; insilmaril@218: } insilmaril@218: insilmaril@218: void LinkableMapObj::setRelPos() insilmaril@218: { insilmaril@218: if (parObj) insilmaril@218: { insilmaril@395: relPos.setX (absPos.x() - parObj->getChildPos().x() ); insilmaril@395: relPos.setY (absPos.y() - parObj->getChildPos().y() ); insilmaril@218: parObj->calcBBoxSize(); insilmaril@494: } insilmaril@218: } insilmaril@218: insilmaril@408: void LinkableMapObj::setRelPos(const QPointF &p) insilmaril@218: { insilmaril@218: relPos=p; insilmaril@218: if (parObj) insilmaril@388: { insilmaril@388: parObj->calcBBoxSize(); insilmaril@388: requestReposition(); insilmaril@395: } insilmaril@218: } insilmaril@218: insilmaril@408: QPointF LinkableMapObj::getRelPos() insilmaril@366: { insilmaril@408: if (!parObj) return QPointF(); insilmaril@366: return relPos; insilmaril@366: } insilmaril@366: insilmaril@408: qreal LinkableMapObj::getTopPad() insilmaril@175: { insilmaril@175: return topPad; insilmaril@175: } insilmaril@175: insilmaril@408: qreal LinkableMapObj::getLeftPad() insilmaril@175: { insilmaril@175: return leftPad; insilmaril@175: } insilmaril@175: insilmaril@408: qreal LinkableMapObj::getRightPad() insilmaril@175: { insilmaril@175: return rightPad; insilmaril@175: } insilmaril@175: insilmaril@786: LinkableMapObj::Style LinkableMapObj::getDefLinkStyle (TreeItem *parent) insilmaril@0: { insilmaril@773: VymModel *model=treeItem->getModel(); insilmaril@721: if (!model) insilmaril@721: { insilmaril@721: qWarning ("LMO::getDefLinkStyle model=NULL"); insilmaril@727: //return UndefinedStyle; insilmaril@721: } insilmaril@721: Style ls=model->getMapLinkStyle(); insilmaril@786: int depth=1+parent->depth(); insilmaril@727: if (depth==0) return UndefinedStyle; insilmaril@0: switch (ls) insilmaril@0: { insilmaril@473: case Line: insilmaril@0: return ls; insilmaril@0: break; insilmaril@473: case Parabel: insilmaril@0: return ls; insilmaril@0: break; insilmaril@473: case PolyLine: insilmaril@0: if (depth>1) insilmaril@473: return Line; insilmaril@0: else insilmaril@0: return ls; insilmaril@0: break; insilmaril@473: case PolyParabel: insilmaril@0: if (depth>1) insilmaril@473: return Parabel; insilmaril@0: else insilmaril@0: return ls; insilmaril@0: break; insilmaril@0: default: insilmaril@0: break; insilmaril@0: } insilmaril@473: return UndefinedStyle; insilmaril@0: } insilmaril@0: insilmaril@473: void LinkableMapObj::setLinkStyle(Style newstyle) insilmaril@0: { insilmaril@786: //if (newstyle==style) return; FIXME-3 insilmaril@0: delLink(); insilmaril@0: insilmaril@0: style=newstyle; insilmaril@0: insilmaril@773: if (parObj != NULL) insilmaril@0: { insilmaril@408: QGraphicsLineItem *cl; insilmaril@0: switch (style) insilmaril@0: { insilmaril@473: case UndefinedStyle: insilmaril@0: bottomline->hide(); insilmaril@0: break; insilmaril@473: case Line: insilmaril@408: l = scene->addLine(QLineF(1,1,1,1),pen); insilmaril@408: l->setZValue(Z_LINK); insilmaril@0: if (visible) insilmaril@0: l->show(); insilmaril@0: else insilmaril@0: l->hide(); insilmaril@0: break; insilmaril@473: case Parabel: insilmaril@408: for (int i=0;iaddLine(QLineF(i*5,0,i*10,100),pen); insilmaril@408: cl->setZValue(Z_LINK); insilmaril@0: if (visible) insilmaril@0: cl->show(); insilmaril@0: else insilmaril@0: cl->hide(); insilmaril@0: segment.append(cl); insilmaril@0: } insilmaril@0: pa0.resize (arcsegs+1); insilmaril@0: break; insilmaril@473: case PolyLine: insilmaril@408: p =scene->addPolygon(QPolygonF(),pen,linkcolor); insilmaril@408: p->setZValue(Z_LINK); insilmaril@0: if (visible) insilmaril@0: p->show(); insilmaril@0: else insilmaril@0: p->hide(); insilmaril@0: pa0.resize (3); insilmaril@0: break; insilmaril@473: case PolyParabel: insilmaril@408: p = scene->addPolygon(QPolygonF(),pen,linkcolor); insilmaril@408: p->setZValue(Z_LINK); insilmaril@0: if (visible) insilmaril@0: p->show(); insilmaril@0: else insilmaril@0: p->hide(); insilmaril@0: pa0.resize (arcsegs*2+2); insilmaril@0: pa1.resize (arcsegs+1); insilmaril@0: pa2.resize (arcsegs+1); insilmaril@0: break; insilmaril@0: default: insilmaril@0: break; insilmaril@0: } insilmaril@164: } insilmaril@0: } insilmaril@0: insilmaril@473: LinkableMapObj::Style LinkableMapObj::getLinkStyle() insilmaril@0: { insilmaril@0: return style; insilmaril@0: } insilmaril@0: insilmaril@779: void LinkableMapObj::setHideLinkUnselected() insilmaril@160: { insilmaril@160: setVisibility (visible); insilmaril@779: updateLinkGeometry(); insilmaril@160: } insilmaril@160: insilmaril@473: void LinkableMapObj::setLinkPos(Position lp) insilmaril@0: { insilmaril@0: linkpos=lp; insilmaril@0: } insilmaril@0: insilmaril@473: LinkableMapObj::Position LinkableMapObj::getLinkPos() insilmaril@0: { insilmaril@0: return linkpos; insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::setLinkColor() insilmaril@0: { insilmaril@721: // Overloaded in BranchObj and children insilmaril@0: // here only set default color insilmaril@773: VymModel *model=treeItem->getModel(); insilmaril@721: if (model) insilmaril@721: setLinkColor (model->getMapDefLinkColor()); insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::setLinkColor(QColor col) insilmaril@0: { insilmaril@0: linkcolor=col; insilmaril@408: pen.setColor(col); insilmaril@408: bottomline->setPen( pen ); insilmaril@0: switch (style) insilmaril@0: { insilmaril@473: case Line: insilmaril@408: l->setPen( pen); insilmaril@0: break; insilmaril@473: case Parabel: insilmaril@406: for (int i=0; isetPen( pen); insilmaril@0: break; insilmaril@473: case PolyLine: insilmaril@0: p->setBrush( QBrush(col)); insilmaril@497: p->setPen( pen); insilmaril@0: break; insilmaril@473: case PolyParabel: insilmaril@0: p->setBrush( QBrush(col)); insilmaril@497: p->setPen( pen); insilmaril@0: break; insilmaril@0: default: insilmaril@0: break; insilmaril@755: } insilmaril@0: } insilmaril@0: insilmaril@0: QColor LinkableMapObj::getLinkColor() insilmaril@0: { insilmaril@0: return linkcolor; insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::setVisibility (bool v) insilmaril@0: { insilmaril@0: MapObj::setVisibility (v); insilmaril@779: updateVisibility(); insilmaril@779: } insilmaril@779: insilmaril@779: void LinkableMapObj::setOrientation() insilmaril@779: { insilmaril@779: Orientation orientOld=orientation; insilmaril@779: insilmaril@779: if (!parObj) insilmaril@779: { insilmaril@779: orientation=UndefinedOrientation; insilmaril@779: return; insilmaril@779: } insilmaril@779: insilmaril@779: // Set orientation, first look for orientation of parent insilmaril@779: if (parObj->getOrientation() != UndefinedOrientation ) insilmaril@779: // use the orientation of the parent: insilmaril@779: orientation=parObj->getOrientation(); insilmaril@779: else insilmaril@779: { insilmaril@779: // calc orientation depending on position rel to parent insilmaril@779: if (absPos.x() < QPointF(parObj->getChildPos() ).x() ) insilmaril@779: orientation=LeftOfCenter; insilmaril@779: else insilmaril@779: orientation=RightOfCenter; insilmaril@779: } insilmaril@779: if (orientOld!=orientation) requestReposition(); insilmaril@779: } insilmaril@779: insilmaril@779: void LinkableMapObj::updateVisibility() insilmaril@779: { insilmaril@160: bool visnow=visible; insilmaril@260: insilmaril@779: if (((MapItem*)treeItem)->getHideLinkUnselected() insilmaril@779: && treeItem->getModel()->getSelectedLMO() !=this) insilmaril@160: visnow=false; insilmaril@160: insilmaril@160: if (visnow) insilmaril@0: { insilmaril@0: bottomline->show(); insilmaril@160: switch (style) insilmaril@0: { insilmaril@473: case Line: insilmaril@160: if (l) l->show(); insilmaril@160: break; insilmaril@473: case Parabel: insilmaril@406: for (int i=0; ishow(); insilmaril@160: break; insilmaril@473: case PolyLine: insilmaril@779: if (!p) cout << "LMO::updateVis p==0 (PolyLine)\n"; //FIXME-3 insilmaril@160: if (p) p->show(); insilmaril@160: break; insilmaril@473: case PolyParabel: insilmaril@779: if (!p) cout << "LMO::updateVis p==0 (PolyParabel) "<getHeading().toStdString()<show(); insilmaril@160: break; insilmaril@160: default: insilmaril@160: break; insilmaril@160: } insilmaril@0: } else insilmaril@0: { insilmaril@0: bottomline->hide(); insilmaril@160: switch (style) insilmaril@0: { insilmaril@473: case Line: insilmaril@160: if (l) l->hide(); insilmaril@160: break; insilmaril@473: case Parabel: insilmaril@406: for (int i=0; ihide(); insilmaril@160: break; insilmaril@473: case PolyLine: insilmaril@160: if (p) p->hide(); insilmaril@160: break; insilmaril@473: case PolyParabel: insilmaril@160: if (p) p->hide(); insilmaril@160: break; insilmaril@160: default: insilmaril@160: break; insilmaril@160: } insilmaril@0: } insilmaril@0: } insilmaril@0: insilmaril@779: void LinkableMapObj::updateLinkGeometry() insilmaril@0: { insilmaril@0: // needs: insilmaril@0: // childPos of parent insilmaril@0: // orient of parent insilmaril@0: // style insilmaril@0: // insilmaril@0: // sets: insilmaril@0: // orientation insilmaril@225: // childPos (by calling setDockPos()) insilmaril@225: // parPos (by calling setDockPos()) insilmaril@175: // bottomlineY insilmaril@0: // drawing of the link itself insilmaril@0: insilmaril@779: // updateLinkGeometry is called from move, but called from constructor we don't insilmaril@0: // have parents yet... insilmaril@775: insilmaril@785: //cout <<"LMO::updateLinkGeometry: "<getHeadingStd()<<" "<branchCount(); ++i) insilmaril@779: treeItem->getBranchObjNum(i)->updateLinkGeometry(); insilmaril@775: return; insilmaril@775: } insilmaril@775: insilmaril@473: if (style==UndefinedStyle) return; insilmaril@0: insilmaril@0: switch (linkpos) insilmaril@0: { insilmaril@473: case Middle: insilmaril@442: bottomlineY=bbox.top() + bbox.height()/2; // draw link to middle (of frame) insilmaril@0: break; insilmaril@473: case Bottom: insilmaril@785: //bottomlineY=bbox.bottom()-1; // draw link to bottom of box insilmaril@785: bottomlineY=bbox.bottom()-botPad; insilmaril@0: break; insilmaril@0: } insilmaril@0: insilmaril@0: double p2x,p2y; // Set P2 Before setting insilmaril@0: if (!link2ParPos) insilmaril@0: { insilmaril@408: p2x=QPointF( parObj->getChildPos() ).x(); // P1, we have to look at insilmaril@408: p2y=QPointF( parObj->getChildPos() ).y(); // orientation insilmaril@0: } else insilmaril@0: { insilmaril@408: p2x=QPointF( parObj->getParPos() ).x(); insilmaril@408: p2y=QPointF( parObj->getParPos() ).y(); insilmaril@0: } insilmaril@0: insilmaril@388: setDockPos(); // Call overloaded method insilmaril@393: setOrientation(); insilmaril@0: insilmaril@0: double p1x=parPos.x(); // Link is drawn from P1 to P2 insilmaril@0: double p1y=parPos.y(); insilmaril@0: insilmaril@0: double vx=p2x - p1x; // V=P2-P1 insilmaril@0: double vy=p2y - p1y; insilmaril@0: insilmaril@0: // Draw the horizontal line below heading (from ChildPos to ParPos) insilmaril@427: //bottomline->prepareGeometryChange(); insilmaril@408: bottomline->setLine (QLine (qRound(childPos.x()), insilmaril@104: qRound(childPos.y()), insilmaril@104: qRound(p1x), insilmaril@408: qRound(p1y) )); insilmaril@0: insilmaril@0: double a; // angle insilmaril@0: if (vx > -0.000001 && vx < 0.000001) insilmaril@0: a=M_PI_2; insilmaril@0: else insilmaril@0: a=atan( vy / vx ); insilmaril@0: // "turning point" for drawing polygonal links insilmaril@408: QPointF tp (-qRound(sin (a)*thickness_start), qRound(cos (a)*thickness_start)); insilmaril@0: insilmaril@0: // Draw the link insilmaril@0: switch (style) insilmaril@0: { insilmaril@473: case Line: insilmaril@408: l->setLine( QLine(qRound (parPos.x()), insilmaril@104: qRound(parPos.y()), insilmaril@104: qRound(p2x), insilmaril@408: qRound(p2y) )); insilmaril@0: break; insilmaril@473: case Parabel: insilmaril@0: parabel (pa0, p1x,p1y,p2x,p2y); insilmaril@406: for (int i=0; isetLine(QLineF( pa0.at(i).x(), pa0.at(i).y(),pa0.at(i+1).x(),pa0.at(i+1).y())); insilmaril@0: break; insilmaril@473: case PolyLine: insilmaril@408: pa0.clear(); insilmaril@408: pa0<setPolygon(QPolygonF (pa0)); insilmaril@0: break; insilmaril@473: case PolyParabel: insilmaril@0: parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y()); insilmaril@0: parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y()); insilmaril@408: pa0.clear(); insilmaril@406: for (int i=0;i<=arcsegs;i++) insilmaril@408: pa0 << QPointF (pa1.at(i)); insilmaril@408: for (int i=0;i<=arcsegs;i++) insilmaril@408: pa0 << QPointF (pa2.at(arcsegs-i)); insilmaril@408: p->setPolygon(QPolygonF (pa0)); insilmaril@0: break; insilmaril@0: default: insilmaril@0: break; insilmaril@779: } insilmaril@0: } insilmaril@0: insilmaril@0: LinkableMapObj* LinkableMapObj::getParObj() insilmaril@0: { insilmaril@0: return parObj; insilmaril@0: } insilmaril@0: insilmaril@408: QPointF LinkableMapObj::getChildPos() insilmaril@0: { insilmaril@0: return childPos; insilmaril@0: } insilmaril@0: insilmaril@408: QPointF LinkableMapObj::getParPos() insilmaril@0: { insilmaril@0: return parPos; insilmaril@0: } insilmaril@0: insilmaril@473: LinkableMapObj::Orientation LinkableMapObj::getOrientation() insilmaril@0: { insilmaril@0: return orientation; insilmaril@0: } insilmaril@0: insilmaril@408: QPointF LinkableMapObj::getRandPos() insilmaril@0: { insilmaril@0: // Choose a random position with given distance to parent: insilmaril@0: double a=rand()%360 * 2 * M_PI / 360; insilmaril@408: return QPointF ( (int)( + 150*cos (a)), insilmaril@0: (int)( + 150*sin (a))); insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::reposition() insilmaril@0: { insilmaril@0: } insilmaril@0: insilmaril@785: void LinkableMapObj::requestReposition() //FIXME-3 needed? insilmaril@0: { insilmaril@0: if (!repositionRequest) insilmaril@0: { insilmaril@0: // Pass on the request to parental objects, if this hasn't insilmaril@0: // been done yet insilmaril@0: repositionRequest=true; insilmaril@0: if (parObj) parObj->requestReposition(); insilmaril@0: } insilmaril@0: } insilmaril@0: insilmaril@0: void LinkableMapObj::forceReposition() insilmaril@0: { insilmaril@0: // Sometimes a reposition has to be done immediatly: For example insilmaril@0: // if the note editor flag changes, there is no user event in mapeditor insilmaril@0: // which could collect requests for a reposition. insilmaril@0: // Then we have to call forceReposition() insilmaril@0: // But no rule without exception: While loading a map or undoing it, insilmaril@0: // we want to block expensive repositioning, but just do it once at insilmaril@0: // the end, thus check first: insilmaril@0: insilmaril@773: VymModel *model=treeItem->getModel(); insilmaril@724: if (model->isRepositionBlocked()) return; insilmaril@0: insilmaril@724: // Pass on the request to parent objects, if this hasn't been done yet insilmaril@0: if (parObj) insilmaril@0: parObj->forceReposition(); insilmaril@0: else insilmaril@83: reposition(); insilmaril@83: } insilmaril@0: insilmaril@0: bool LinkableMapObj::repositionRequested() insilmaril@0: { insilmaril@0: return repositionRequest; insilmaril@0: } insilmaril@0: insilmaril@408: void LinkableMapObj::parabel (QPolygonF &ya, double p1x, double p1y, double p2x, double p2y) insilmaril@0: insilmaril@0: { insilmaril@0: double vx=p2x - p1x; // V=P2-P1 insilmaril@0: double vy=p2y - p1y; insilmaril@0: insilmaril@0: double dx; // delta x during calculation of parabel insilmaril@0: insilmaril@0: double pnx; // next point insilmaril@0: double pny; insilmaril@0: double m; insilmaril@0: insilmaril@0: if (vx > -0.0001 && vx < 0.0001) insilmaril@0: m=0; insilmaril@0: else insilmaril@0: m=(vy / (vx*vx)); insilmaril@0: dx=vx/(arcsegs); insilmaril@408: ya.clear(); insilmaril@579: ya<