]> git.sven.stormbind.net Git - sven/vym.git/blobdiff - src/xlinkobj.cpp
New upstream version 2.9.22
[sven/vym.git] / src / xlinkobj.cpp
diff --git a/src/xlinkobj.cpp b/src/xlinkobj.cpp
new file mode 100644 (file)
index 0000000..eae7421
--- /dev/null
@@ -0,0 +1,491 @@
+#include <QDebug>
+
+#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();
+}