X-Git-Url: https://git.sven.stormbind.net/?a=blobdiff_plain;f=src%2Fxlinkobj.cpp;fp=src%2Fxlinkobj.cpp;h=eae742118881295bce356317e63d50f426ae4c78;hb=d483bd8e6523c23c6f1d8908a2e0611c2bc9ff4f;hp=0000000000000000000000000000000000000000;hpb=7dfa3fe589d1722d49681f42cdb0bf1e6efb5223;p=sven%2Fvym.git diff --git a/src/xlinkobj.cpp b/src/xlinkobj.cpp new file mode 100644 index 0000000..eae7421 --- /dev/null +++ b/src/xlinkobj.cpp @@ -0,0 +1,491 @@ +#include + +#include "xlinkobj.h" + +#include "branchitem.h" +#include "branchobj.h" +#include "math.h" // atan +#include "misc.h" // max + +///////////////////////////////////////////////////////////////// +// XLinkObj +///////////////////////////////////////////////////////////////// + +int XLinkObj::arrowSize = 6; // make instances +int XLinkObj::clickBorder = 8; +int XLinkObj::pointRadius = 10; +int XLinkObj::d_control = 300; + +XLinkObj::XLinkObj(QGraphicsItem *parent, Link *l) : MapObj(parent) +{ + // qDebug()<< "Const XLinkObj (parent,Link)"; + link = l; + init(); +} + +XLinkObj::~XLinkObj() +{ + // qDebug() << "Destr XLinkObj"; + delete (poly); + delete (path); + delete (ctrl_p0); + delete (ctrl_p1); + delete (pointerEnd); + delete (pointerBegin); +} + +void XLinkObj::init() +{ + visBranch = NULL; + + stateVis = Hidden; + + QPen pen = link->getPen(); + + path = scene()->addPath(QPainterPath(), pen, Qt::NoBrush); + path->setZValue(dZ_XLINK); + + pointerBegin = new ArrowObj(this); + pointerBegin->setPen(pen); + pointerBegin->setUseFixedLength(true); + pointerBegin->setFixedLength(0); + + pointerEnd = new ArrowObj(this); + pointerEnd->setPen(pen); + pointerEnd->setUseFixedLength(true); + pointerEnd->setFixedLength(0); + + pen.setStyle(Qt::SolidLine); + poly = scene()->addPolygon(QPolygonF(), pen, pen.color()); + poly->setZValue(dZ_XLINK); + + // Control points for bezier path + // (We have at least a begin branch, consider its orientation) + initC0(); + initC1(); + + ctrl_p0 = scene()->addEllipse(c0.x(), c0.y(), clickBorder * 2, + clickBorder * 2, pen, pen.color()); + ctrl_p1 = scene()->addEllipse(c1.x(), c1.y(), clickBorder * 2, + clickBorder * 2, pen, pen.color()); + + beginOrient = endOrient = LinkableMapObj::UndefinedOrientation; + pen.setWidth(1); + pen.setStyle(Qt::DashLine); + + curSelection = Unselected; + + setVisibility(true); +} + +QPointF XLinkObj::getAbsPos() +{ + switch (curSelection) { + case C0: + return c0; + break; + case C1: + return c1; + break; + default: + return QPointF(); + break; + } +} + +void XLinkObj::setStyleBegin(const QString &s) { pointerBegin->setStyleEnd(s); } + +void XLinkObj::setStyleBegin(ArrowObj::OrnamentStyle os) +{ + pointerBegin->setStyleEnd(os); +} + +ArrowObj::OrnamentStyle XLinkObj::getStyleBegin() +{ + return pointerBegin->getStyleEnd(); +} + +void XLinkObj::setStyleEnd(const QString &s) { pointerEnd->setStyleEnd(s); } + +void XLinkObj::setStyleEnd(ArrowObj::OrnamentStyle os) +{ + pointerEnd->setStyleEnd(os); +} + +ArrowObj::OrnamentStyle XLinkObj::getStyleEnd() +{ + return pointerEnd->getStyleEnd(); +} + +QPointF XLinkObj::getBeginPos() { return beginPos; } + +QPointF XLinkObj::getEndPos() { return endPos; } + +void XLinkObj::move(QPointF p) +{ + switch (curSelection) { + case C0: + c0 = p; + break; + case C1: + c1 = p; + break; + default: + break; + } + updateXLink(); +} + +void XLinkObj::setEnd(QPointF p) { endPos = p; } + +void XLinkObj::setSelection(CurrentSelection s) +{ + curSelection = s; + setVisibility(); +} + +void XLinkObj::setSelection(int cp) +{ + if (cp == 0) + setSelection(C0); + else if (cp == 1) + setSelection(C1); + else + qWarning() << "XLO::setSelection cp=" << cp; +} + +void XLinkObj::updateXLink() +{ + QPointF a, b; + QPolygonF pa; + + BranchObj *beginBO = NULL; + BranchObj *endBO = NULL; + BranchItem *bi = link->getBeginBranch(); + if (bi) + beginBO = (BranchObj *)(bi->getLMO()); + bi = link->getEndBranch(); + if (bi) + endBO = (BranchObj *)(bi->getLMO()); + + if (beginBO) { + if (beginOrient != LinkableMapObj::UndefinedOrientation && + beginOrient != beginBO->getOrientation()) + c0.setX(-c0.x()); + beginOrient = beginBO->getOrientation(); + } + if (endBO) { + if (endOrient != LinkableMapObj::UndefinedOrientation && + endOrient != endBO->getOrientation()) + c1.setX(-c1.x()); + endOrient = endBO->getOrientation(); + } + + if (visBranch) { + // Only one of the linked branches is visible + // Draw arrowhead //FIXME-3 missing shaft of arrow + BranchObj *bo = (BranchObj *)(visBranch->getLMO()); + if (!bo) + return; + + a = b = bo->getChildRefPos(); + + if (bo->getOrientation() == LinkableMapObj::RightOfCenter) { + b.setX(b.x() + 2 * arrowSize); + pa.clear(); + pa << a << b << QPointF(b.x(), b.y() - arrowSize) + << QPointF(b.x() + arrowSize, b.y()) + << QPointF(b.x(), b.y() + arrowSize) << b << a; + poly->setPolygon(pa); + } + else { + b.setX(b.x() - 2 * arrowSize); + pa.clear(); + pa << a << b << QPointF(b.x(), b.y() - arrowSize) + << QPointF(b.x() - arrowSize, b.y()) + << QPointF(b.x(), b.y() + arrowSize) << b << a; + poly->setPolygon(pa); + } + } + else { + // Both linked branches are visible + + // If a link is just drawn in the editor, + // we have already a beginBranch + if (beginBO) + beginPos = beginBO->getChildRefPos(); + if (endBO) + endPos = endBO->getChildRefPos(); + + if (beginBO && endBO) { + pointerBegin->move(beginPos + c0); + pointerBegin->setEndPoint(beginPos); + + pointerEnd->move(endPos + c1); + pointerEnd->setEndPoint(endPos); + } + } + + // Update control points for bezier + QPainterPath p(beginPos); + p.cubicTo(beginPos + c0, endPos + c1, endPos); + + clickPath = p; + path->setPath(p); + + // Go back to create closed curve, + // needed for intersection check: + clickPath.cubicTo(endPos + c1, beginPos + c0, beginPos); + + QPen pen = link->getPen(); + path->setPen(pen); + poly->setBrush(pen.color()); + + pointerBegin->setPen(pen); + pointerEnd->setPen(pen); + + pen.setStyle(Qt::SolidLine); + + ctrl_p0->setRect(beginPos.x() + c0.x() - pointRadius / 2, + beginPos.y() + c0.y() - pointRadius / 2, pointRadius, + pointRadius); + ctrl_p0->setPen(pen); + ctrl_p0->setBrush(pen.color()); + + ctrl_p1->setRect(endPos.x() + c1.x() - pointRadius / 2, + endPos.y() + c1.y() - pointRadius / 2, pointRadius, + pointRadius); + ctrl_p1->setPen(pen); + ctrl_p1->setBrush(pen.color()); + + BranchItem *bi_begin = link->getBeginBranch(); + BranchItem *bi_end = link->getEndBranch(); + if (bi_begin && bi_end && link->getState() == Link::activeXLink) + // Note: with MapObj being a GraphicsItem now, maybe better reparent the + // xlinkobj line->setZValue (dZ_DEPTH * + // max(bi_begin->depth(),bi_end->depth()) + dZ_XLINK); + path->setZValue(dZ_XLINK); + else + path->setZValue(dZ_XLINK); + + setVisibility(); +} + +void XLinkObj::positionBBox() {} + +void XLinkObj::calcBBoxSize() {} + +void XLinkObj::setVisibility(bool b) +{ + if (stateVis == FullShowControls) { + ctrl_p0->show(); + ctrl_p1->show(); + pointerBegin->setUseFixedLength(false); + pointerEnd->setUseFixedLength(false); + } + else { + ctrl_p0->hide(); + ctrl_p1->hide(); + pointerBegin->setUseFixedLength(true); + pointerBegin->setFixedLength(0); + pointerEnd->setUseFixedLength(true); + pointerEnd->setFixedLength(0); + } + + MapObj::setVisibility(b); + if (b) { + if (stateVis == OnlyBegin) { + path->hide(); + poly->show(); + pointerBegin->hide(); + pointerEnd->hide(); + } + else if (stateVis == OnlyEnd) { + path->hide(); + poly->show(); + pointerBegin->hide(); + pointerEnd->hide(); + } + else { + path->show(); + poly->hide(); + pointerBegin->show(); + pointerEnd->show(); + } + } + else { + poly->hide(); + path->hide(); + pointerBegin->hide(); + pointerEnd->hide(); + } +} + +void XLinkObj::setVisibility() +{ + BranchItem *beginBI = link->getBeginBranch(); + BranchObj *beginBO = NULL; + if (beginBI) + beginBO = (BranchObj *)(beginBI->getLMO()); + + BranchObj *endBO = NULL; + BranchItem *endBI = link->getEndBranch(); + if (endBI) + endBO = (BranchObj *)(endBI->getLMO()); + if (beginBO && endBO) { + if (beginBO->isVisibleObj() && + endBO->isVisibleObj()) { // Both ends are visible + visBranch = NULL; + if (curSelection != Unselected) + stateVis = FullShowControls; + else + stateVis = Full; + setVisibility(true); + } + else { + if (!beginBO->isVisibleObj() && + !endBO->isVisibleObj()) { // None of the ends is visible + visBranch = NULL; + stateVis = Hidden; + setVisibility(false); + } + else { // Just one end is visible, draw a symbol that shows + // that there is a link to a scrolled branch + if (beginBO->isVisibleObj()) { + stateVis = OnlyBegin; + visBranch = beginBI; + } + else { + visBranch = endBI; + stateVis = OnlyEnd; + } + setVisibility(true); + } + } + } +} + +void XLinkObj::initC0() +{ + if (!link) + return; + BranchItem *beginBranch = link->getBeginBranch(); + if (!beginBranch) + return; + BranchObj *bo = beginBranch->getBranchObj(); + if (!bo) + return; + if (bo->getOrientation() == LinkableMapObj::RightOfCenter) + c0 = QPointF(d_control, 0); + else + c0 = QPointF(-d_control, 0); +} + +void XLinkObj::initC1() +{ + if (!link) + return; + BranchItem *endBranch = link->getEndBranch(); + if (!endBranch) + return; + BranchObj *bo = endBranch->getBranchObj(); + if (!bo) + return; + if (bo->getOrientation() == LinkableMapObj::RightOfCenter) + c1 = QPointF(d_control, 0); + else + c1 = QPointF(-d_control, 0); +} + +void XLinkObj::setC0(const QPointF &p) { c0 = p; } + +QPointF XLinkObj::getC0() { return c0; } + +void XLinkObj::setC1(const QPointF &p) { c1 = p; } + +QPointF XLinkObj::getC1() { return c1; } + +int XLinkObj::ctrlPointInClickBox(const QPointF &p) +{ + CurrentSelection oldSel = curSelection; + int ret = -1; + + QRectF r(p.x() - clickBorder, p.y() - clickBorder, clickBorder * 2, + clickBorder * 2); + + if (curSelection == C0 || curSelection == C1) { + // If Cx selected, check both ctrl points + curSelection = C0; + if (getClickPath().intersects(r)) + ret = 0; + curSelection = C1; + if (getClickPath().intersects(r)) + ret = 1; + } + curSelection = oldSel; + return ret; +} + +bool XLinkObj::isInClickBox(const QPointF &p) +{ + // Return, if not visible at all... + if (stateVis == Hidden) + return false; + + CurrentSelection oldSel = curSelection; + bool b = false; + + QRectF r(p.x() - clickBorder, p.y() - clickBorder, clickBorder * 2, + clickBorder * 2); + + switch (stateVis) { + case FullShowControls: + // If Cx selected, check both ctrl points + if (ctrlPointInClickBox(p) > -1) + b = true; + + // Enable selecting the path, when a ctrl point is already selected + if (!b && curSelection != Unselected && clickPath.intersects(r)) + b = true; + break; + case OnlyBegin: + case OnlyEnd: + // not selected, only partially visible + if (poly->boundingRect().contains(p)) + b = true; + break; + default: + // not selected, but path is fully visible + curSelection = Path; + if (getClickPath().intersects(r)) + b = true; + break; + } + curSelection = oldSel; + return b; +} + +QPainterPath +XLinkObj::getClickPath() // also needs mirroring if oriented left. Create method + // to generate the coordinates +{ + QPainterPath p; + switch (curSelection) { + case C0: + p.addEllipse(beginPos + c0, 15, 15); + return p; + break; + case C1: + p.addEllipse(endPos + c1, 15, 15); + return p; + break; + default: + return clickPath; + break; + } +} + +QPainterPath XLinkObj::getSelectionPath() +{ + return getClickPath(); +}