Index: resources/iconsets/1_7_0/1_7_0.xml =================================================================== --- resources/iconsets/1_7_0/1_7_0.xml (Revision 26704) +++ resources/iconsets/1_7_0/1_7_0.xml (Arbeitskopie) @@ -141,7 +141,7 @@ - + @@ -184,11 +184,13 @@ + + @@ -196,16 +198,25 @@ + + + + + + + + + - + @@ -248,6 +259,8 @@ + + - + Index: scribus/canvasmode.cpp =================================================================== --- scribus/canvasmode.cpp (Revision 26704) +++ scribus/canvasmode.cpp (Arbeitskopie) @@ -221,13 +221,13 @@ // } drawSelectionHandle(psx, QPointF(x, y), p, m_canvas->scale()); - drawSelectionHandle(psx, QPointF(x+w/2.0, y), p, m_canvas->scale()); - drawSelectionHandle(psx, QPointF(x+w, y), p, m_canvas->scale()); - drawSelectionHandle(psx, QPointF(x+w, y+h/2.0), p, m_canvas->scale()); - drawSelectionHandle(psx, QPointF(x+w, y+h), p, m_canvas->scale()); - drawSelectionHandle(psx, QPointF(x+w/2.0, y+h), p, m_canvas->scale()); - drawSelectionHandle(psx, QPointF(x, y+h), p, m_canvas->scale()); - drawSelectionHandle(psx, QPointF(x, y+h/2.0), p, m_canvas->scale()); + drawSelectionHandle(psx, QPointF(x + w / 2.0, y), p, m_canvas->scale()); + drawSelectionHandle(psx, QPointF(x + w, y), p, m_canvas->scale()); + drawSelectionHandle(psx, QPointF(x + w, y + h / 2.0), p, m_canvas->scale()); + drawSelectionHandle(psx, QPointF(x + w, y + h), p, m_canvas->scale()); + drawSelectionHandle(psx, QPointF(x + w / 2.0, y + h), p, m_canvas->scale()); + drawSelectionHandle(psx, QPointF(x, y + h), p, m_canvas->scale()); + drawSelectionHandle(psx, QPointF(x, y + h / 2.0), p, m_canvas->scale()); } void CanvasMode::drawSelection(QPainter* psx, bool drawHandles) @@ -257,6 +257,7 @@ if (!m_doc->Items->contains(currItem)) continue; psx->save(); + double lineAdjust(psx->pen().width() / m_canvas->scale()); double x, y, w, h; w = currItem->visualWidth() ; h = currItem->visualHeight() ; @@ -265,14 +266,14 @@ psx->setRenderHint(QPainter::Antialiasing); psx->translate(currItem->xPos(), currItem->yPos()); psx->rotate(currItem->rotation()); - x = currItem->asLine() ? 0 : (currItem->visualXPos() - currItem->xPos()); - y = currItem->asLine() ? (h / -2.0) : (currItem->visualYPos() - currItem->yPos()); + x = currItem->asLine() ? 0 : (currItem->visualXPos() - currItem->xPos() - lineAdjust); + y = currItem->asLine() ? (h / -2.0) : (currItem->visualYPos() - currItem->yPos() - lineAdjust); } else { psx->translate(currItem->visualXPos(), currItem->visualYPos()); - x = 0; - y = 0; + x = currItem->asLine() ? 0 : -lineAdjust; + y = currItem->asLine() ? 0 : -lineAdjust; } // psx->setBrush(Qt::NoBrush); // psx->setPen(m_pen["frame-outline"]); @@ -285,12 +286,13 @@ } psx->save(); psx->setPen(m_pen["selection-group"]); + double lineAdjust(psx->pen().width() / m_canvas->scale()); double x, y, w, h; m_doc->m_Selection->getVisualGroupRect(&x, &y, &w, &h); psx->translate(x,y); - x = 0; - y = 0; + x = -lineAdjust; + y = -lineAdjust; // psx->setBrush(Qt::NoBrush); // psx->setPen(m_pen["frame-outline"]); @@ -314,6 +316,7 @@ psx->save(); psx->setPen(m_pen["selection"]); psx->setBrush(m_brush["selection"]); + double lineAdjust(psx->pen().width() / m_canvas->scale()); double x, y, w, h; if (currItem->isGroupChild()) { @@ -358,14 +361,14 @@ psx->setRenderHint(QPainter::Antialiasing); psx->translate(currItem->xPos(), currItem->yPos()); psx->rotate(currItem->rotation()); - x = currItem->asLine() ? 0 : (currItem->visualXPos() - currItem->xPos()); - y = currItem->asLine() ? (h / -2.0) : (currItem->visualYPos() - currItem->yPos()); + x = currItem->asLine() ? 0 : (currItem->visualXPos() - currItem->xPos() - lineAdjust); + y = currItem->asLine() ? (h / -2.0) : (currItem->visualYPos() - currItem->yPos() - lineAdjust); } else { psx->translate(currItem->visualXPos(), currItem->visualYPos()); - x = 0; - y = 0; + x = currItem->asLine() ? 0 : -lineAdjust; + y = currItem->asLine() ? 0 : -lineAdjust; } // psx->setBrush(Qt::NoBrush); if (m_doc->drawAsPreview && !m_doc->editOnPreview) @@ -740,7 +743,7 @@ QPoint pageOrigin = m_canvas->canvasToLocal(QPointF(xOffset, yOffset)); if (ySnap) { - p->setPen(Qt::green); + p->setPen(m_pen["snap-line"]); QPoint pt = m_canvas->canvasToLocal(QPointF(xOffset, ySnap)); double w = (dragToPage->width() + bleedValues.left() + bleedValues.right()) * m_canvas->scale(); p->drawLine(pageOrigin.x(), pt.y(), pageOrigin.x() + w, pt.y()); @@ -748,7 +751,7 @@ } if (xSnap) { - p->setPen(Qt::green); + p->setPen(m_pen["snap-line"]); QPoint pt = m_canvas->canvasToLocal(QPointF(xSnap, yOffset)); double h = (dragToPage->height() + bleedValues.bottom() + bleedValues.top()) * m_canvas->scale(); p->drawLine(pt.x(), pageOrigin.y(), pt.x(), pageOrigin.y() + h); @@ -1291,7 +1294,7 @@ { int storedClRe = m_doc->nodeEdit.clre(); const auto& nodeSelection = m_doc->nodeEdit.selNode(); - if ((nodeSelection.count() != 0) && (m_doc->nodeEdit.edPoints())) + if (nodeSelection.count() != 0) { QPolygonF poly; m_doc->nodeEdit.beginTransaction(currItem); @@ -1385,7 +1388,7 @@ { int storedClRe = m_doc->nodeEdit.clre(); const auto& nodeSelection = m_doc->nodeEdit.selNode(); - if ((nodeSelection.count() != 0) && (m_doc->nodeEdit.edPoints())) + if (nodeSelection.count() != 0) { QPolygonF poly; m_doc->nodeEdit.beginTransaction(currItem); @@ -1479,7 +1482,7 @@ { int storedClRe = m_doc->nodeEdit.clre(); const auto& nodeSelection = m_doc->nodeEdit.selNode(); - if ((nodeSelection.count() != 0) && (m_doc->nodeEdit.edPoints())) + if (nodeSelection.count() != 0) { QPolygonF poly; m_doc->nodeEdit.beginTransaction(currItem); @@ -1573,7 +1576,7 @@ { int storedClRe = m_doc->nodeEdit.clre(); const auto& nodeSelection = m_doc->nodeEdit.selNode(); - if ((nodeSelection.count() != 0) && (m_doc->nodeEdit.edPoints())) + if (nodeSelection.count() != 0) { QPolygonF poly; m_doc->nodeEdit.beginTransaction(currItem); @@ -1734,9 +1737,11 @@ m_color["frame-group"] = PrefsManager::instance().appPrefs.displayPrefs.frameGroupColor; m_color["frame"] = PrefsManager::instance().appPrefs.displayPrefs.frameNormColor; m_color["frame-move"] = Qt::gray; - m_color["weld"] = QColor(214, 146, 43); - m_color["node"] = QColor(0, 136, 255); - m_color["node-handle"] = QColor(255, 51, 187); + m_color["weld"] = QColor(238, 152, 0); + m_color["node"] = QColor(0, 123, 241); + m_color["node-handle"] = QColor(166, 74, 253); + m_color["highlight"] = QColor(220, 58, 140); + m_color["snap-line"] = Qt::green; m_color["test"] = Qt::magenta; QColor selectionAlpha = m_color["frame-selection"]; selectionAlpha.setAlphaF(.05f); @@ -1747,18 +1752,19 @@ #else double stroke = 1.0; #endif - + // frame m_pen["frame-move"] = QPen(m_color["frame-move"], 1.0 , Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); m_pen["frame-move"].setCosmetic(true); m_pen["frame-preview"] = QPen(Qt::black, 1.0, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin); m_pen["frame-preview"].setCosmetic(true); - m_pen["selection"] = QPen(m_color["frame-selection"], stroke, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); + m_pen["selection"] = QPen(m_color["frame-selection"], 1.0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); m_pen["selection"].setCosmetic(true); - m_pen["selection-handle"] = QPen(m_color["frame-selection"], stroke, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); + m_pen["selection-handle"] = QPen(m_color["frame-selection"], 1.0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); m_pen["selection-handle"].setCosmetic(true); m_pen["selection-group"] = m_pen["selection"]; m_pen["selection-group-inside"] = QPen(m_color["frame-group"], 1.0 , Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); m_pen["selection-group-inside"].setCosmetic(true); + // vector editing m_pen["vector"] = QPen(m_color["node"], stroke, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); m_pen["vector"].setCosmetic(true); m_pen["node"] = QPen(m_color["node"], stroke, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); @@ -1767,6 +1773,10 @@ m_pen["node-handle"].setCosmetic(true); m_pen["node-dash"] = QPen(m_color["node-handle"], stroke, Qt::DashLine, Qt::FlatCap, Qt::MiterJoin); m_pen["node-dash"].setCosmetic(true); + m_pen["highlight"] = QPen(m_color["highlight"], stroke, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); + m_pen["highlight"].setCosmetic(true); + // guides + m_pen["snap-line"] = QPen(m_color["snap-line"], 1.0 , Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); m_brush["frame-move"] = Qt::NoBrush; m_brush["selection"] = Qt::NoBrush; Index: scribus/canvasmode_nodeedit.cpp =================================================================== --- scribus/canvasmode_nodeedit.cpp (Revision 26704) +++ scribus/canvasmode_nodeedit.cpp (Arbeitskopie) @@ -30,6 +30,7 @@ #include "scribusdoc.h" #include "scribusview.h" #include "selection.h" +#include "ui/nodeeditpalette.h" #include "ui/pageselector.h" #include "ui/scrspinbox.h" @@ -38,20 +39,20 @@ m_ScMW = m_view->m_ScMW; } -void CanvasMode_NodeEdit::drawControls(QPainter* p) +void CanvasMode_NodeEdit::drawControls(QPainter* p) { - if (m_doc->m_Selection->isEmpty()) + if (m_doc->m_Selection->isEmpty() || m_doc->nodeEdit.previewMode()) return; - if (m_doc->nodeEdit.previewMode()) - return; + PageItem* currItem = m_doc->m_Selection->itemAt(0); FPointArray cli; - + p->save(); p->scale(m_canvas->scale(), m_canvas->scale()); p->translate(-m_doc->minCanvasCoordinate.x(), -m_doc->minCanvasCoordinate.y()); p->setTransform(currItem->getTransform(), true); p->setBrush(Qt::NoBrush); + p->setRenderHint(QPainter::Antialiasing); if ((m_doc->nodeEdit.isContourLine()) && (!currItem->ContourLine.empty())) cli = currItem->ContourLine; @@ -71,15 +72,25 @@ p->scale(1, -1); } } - } + } const double scale = m_canvas->m_viewMode.scale; + double nx = 0.0; + double ny = 0.0; + double cx = 0.0; + double cy = 0.0; + + QPen penControl = pens().value("node"); + bool isActiveNode = false; + bool isActiveControl = false; + bool highlight = false; + bool mergedNodes = true; + int nr, nl, inr; + FPoint pn, pc; + // Draw Vector Path if (cli.size() > 3) { - p->save(); - p->setRenderHint(QPainter::Antialiasing); - for (int i = 0; i < cli.size() - 3; i += 4) { if (cli.isMarker(i)) @@ -88,20 +99,18 @@ const FPoint& a1 = cli.point(i); const FPoint& a2 = cli.point(i + 1); const FPoint& a3 = cli.point(i + 3); - const FPoint& a4 = cli.point(i + 2); + const FPoint& a4 = cli.point(i + 2); QPainterPath Bez; Bez.moveTo(a1.x(), a1.y()); Bez.cubicTo(a2.x(), a2.y(), a3.x(), a3.y(), a4.x(), a4.y()); + + // Vector Path p->setPen(pens().value("vector")); p->drawPath(Bez); - p->setPen(pens().value("node-handle")); - p->drawLine(QPointF(a1.x(), a1.y()), QPointF(a2.x(), a2.y())); - p->drawLine(QPointF(a3.x(), a3.y()), QPointF(a4.x(), a4.y())); + } - p->restore(); } - double x = 0.0; - double y = 0.0; + // Draw Nodes for (int i = 0; i < cli.size() - 1; i += 2) { @@ -108,51 +117,90 @@ if (cli.isMarker(i)) continue; - if (m_doc->nodeEdit.edPoints()) - { - cli.point(i + 1, &x, &y); - drawNodeControl(p, QPointF(x, y), pens().value("node"), scale); + nr = NodeEditContext::indexOfNode(m_doc->nodeEdit.clre(), NodeEditContext::NodeType::NodeRight, cli.size()); + nl = NodeEditContext::indexOfNode(m_doc->nodeEdit.clre(), NodeEditContext::NodeType::NodeLeft, cli.size()); + inr = NodeEditContext::indexOfNode(i, NodeEditContext::NodeType::NodeRight, cli.size()); - cli.point(i, &x, &y); - drawNodeHandle(p, QPointF(x, y), pens().value("node"), scale); - } - else + mergedNodes = NodeEditContext::hasTwoNodes(i, cli); + highlight = (i == nr || i == nl) && NodeEditContext::hasTwoNodes(m_doc->nodeEdit.clre(), cli); + + isActiveControl = m_doc->nodeEdit.clre() == i + 1 ? true : false; + isActiveNode = m_doc->nodeEdit.clre() == i || + m_doc->nodeEdit.selNode().contains(i) || + m_doc->nodeEdit.selNode().contains(i - 2) || + (m_doc->nodeEdit.selNode().contains(inr) && mergedNodes) ? true : false; + + cli.point(i, &nx, &ny); + cli.point(i + 1, &cx, &cy); + + // Draw Control Handle Lines + if (FPoint(cx, cy) != FPoint(nx, ny)) { - cli.point(i, &x, &y); - drawNodeHandle(p, QPointF(x, y), pens().value("node"), scale); + // changes color to highlight if angle is same as opponent handle + if (highlight && state.isSameAngle && state.clickedOn) + p->setPen(pens().value("highlight")); + else + p->setPen(pens().value("node-handle")); - cli.point(i + 1, &x, &y); - drawNodeControl(p, QPointF(x, y), pens().value("node"), scale); + p->setRenderHint(QPainter::Antialiasing, true); + p->drawLine(QPointF(nx, ny), QPointF(cx, cy)); } - } - - if (m_doc->nodeEdit.clre() != -1) - { - cli.point(m_doc->nodeEdit.clre(), &x, &y); - drawNodeControl(p, QPointF(x, y), pens().value("node"), scale, true); - const auto& selectedNodes = m_doc->nodeEdit.selNode(); - for (int i = 0; i < selectedNodes.count(); ++i) + p->setRenderHint(QPainter::Antialiasing, false); + + // Draw Node Handle + drawNodeHandle(p, QPointF(nx, ny), pens().value("node"), scale, isActiveNode); + + // Draw Control Handle + if (FPoint(cx, cy) != FPoint(nx, ny)) { - int selectedNode = selectedNodes.at(i); - cli.point(selectedNode, &x, &y); - drawNodeHandle(p, QPointF(x, y), pens().value("node"), scale, true); + // changes color to highlight if length is same as opponent handle + if (highlight && state.isSameLength && state.isSameAngle && state.clickedOn) + penControl = pens().value("highlight"); + else + penControl = pens().value("node"); + + drawNodeControl(p, QPointF(cx, cy), penControl, scale, isActiveControl); } } - bool havePoint = (m_doc->nodeEdit.clre() != -1); - emit m_view->HavePoint(havePoint, m_doc->nodeEdit.moveSym()); + emit m_view->HavePoint(m_doc->nodeEdit.clre() != -1); + if (m_doc->nodeEdit.clre() != -1) { - cli.point(m_doc->nodeEdit.clre(), &x, &y); - emit m_view->ClipPo(x, y); + cli.point(m_doc->nodeEdit.clre(), &nx, &ny); + emit m_view->ClipPo(nx, ny); } p->restore(); } +QMap CanvasMode_NodeEdit::selectedNodesList(FPointArray points) +{ + QMap selList; + const auto& selNodes = m_doc->nodeEdit.selNode(); + if (points.size() > 3) + { + for (int i = 0; i < points.size() - 1; i += 2) + { + if (points.isMarker(i)) + continue; + + // i = path start; + // i + 2 = path end OR left part of a node + // i - 2 = right part of a node + if (selNodes.contains(i) || selNodes.contains(i + 2) || selNodes.contains(i - 2) || selNodes.contains(i - 4)) + { + selList.insert(i, i + 1); + } + } + } + + return selList; +} + void CanvasMode_NodeEdit::activate(bool fromGesture) { CanvasMode::activate(fromGesture); @@ -236,19 +284,47 @@ return (*pi) != nullptr; } +FPoint CanvasMode_NodeEdit::constraintControlAngle(FPoint anchor, FPoint mouse, double angleStep) +{ + QLineF line(anchor.toQPointF(), mouse.toQPointF()); + line.setAngle(constrainAngle(line.angle(), angleStep)); + return line.p2(); +} -void CanvasMode_NodeEdit::enterEvent(QEvent *e) +FPoint CanvasMode_NodeEdit::snapControlAngle(FPoint anchor, FPoint mouse, double angle) { + double snap = m_doc->prefsData().guidesPrefs.guideRad / m_canvas->scale(); + QLineF lineAM(anchor.x(), anchor.y(), mouse.x(), mouse.y()); // anchor to mouse + QLineF lineAC = lineAM; // anchor to opposite control point + lineAC.setAngle(360.0 - angle); // invert angle, Qt angle is counter-clockwise + + if (qMax(lineAM.angle(), lineAC.angle()) - qMin(lineAM.angle(), lineAC.angle()) <= 0.00001) + return lineAC.p2(); + + return QLineF(lineAM.p2(), lineAC.p2()).length() <= snap ? lineAC.p2() : mouse; } +FPoint CanvasMode_NodeEdit::snapControlLength(FPoint anchor, FPoint mouse, double length) +{ + double snap = m_doc->prefsData().guidesPrefs.guideRad / m_canvas->scale(); + QLineF line(anchor.toQPointF(), mouse.toQPointF()); -void CanvasMode_NodeEdit::leaveEvent(QEvent *e) -{ + if (length - snap <= line.length() && length + snap >= line.length()) + line.setLength(length); + + return line.p2(); } +FPoint CanvasMode_NodeEdit::snapControlOrigin(FPoint anchor, FPoint mouse) +{ + double snap = m_doc->prefsData().guidesPrefs.guideRad / m_canvas->scale(); + QLineF line(anchor.toQPointF(), mouse.toQPointF()); + return (line.length() <= snap) ? anchor : mouse; +} + void CanvasMode_NodeEdit::mouseDoubleClickEvent(QMouseEvent *m) { m->accept(); @@ -257,11 +333,11 @@ m_view->requestMode(submodeEndNodeEdit); } - void CanvasMode_NodeEdit::mouseMoveEvent(QMouseEvent *m) { double sc = m_canvas->scale(); FPoint npf = m_canvas->globalToCanvas(m->globalPosition()); + m_doc->nodeEdit.setScale(sc); m->accept(); @@ -348,6 +424,7 @@ m_canvas->m_viewMode.operItemMoving = false; m_doc->DragP = false; m_doc->leaveDrag = false; + m_doc->nodeEdit.setScale(m_canvas->scale()); m_MoveGX = m_MoveGY = false; m->accept(); m_view->registerMousePress(m->globalPosition()); @@ -369,7 +446,8 @@ if (m_doc->m_Selection->count() != 0) { handleNodeEditPress(m, mpo); - } + } + if ((m_doc->m_Selection->count() != 0) && (m->button() == Qt::RightButton)) { m_canvas->m_viewMode.m_MouseButtonPressed = true; @@ -378,16 +456,27 @@ } } - - void CanvasMode_NodeEdit::mouseReleaseEvent(QMouseEvent *m) { PageItem *currItem; + m_canvas->m_viewMode.m_MouseButtonPressed = false; m_canvas->resetRenderMode(); m->accept(); + + // Deselect selected node if SHIFT is pressed + if (state.clickedOn == NodeHandle && + m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT && + !state.wasNewlySelected && + m->modifiers() == Qt::ShiftModifier) + { + m_doc->nodeEdit.deselectNode(m_doc->nodeEdit.clre()); + m_doc->regionsChanged()->update(QRectF()); + } + if (m_view->moveTimerElapsed()) { + // Path Segment if (m_doc->nodeEdit.segP1() != -1 && m_doc->nodeEdit.segP2() != -1) { m_doc->nodeEdit.deselect(); @@ -394,53 +483,58 @@ m_doc->nodeEdit.setSegP1(-1); m_doc->nodeEdit.setSegP2(-1); } + + m_canvas->m_viewMode.operItemMoving = false; currItem = m_doc->m_Selection->itemAt(0); - m_canvas->m_viewMode.operItemMoving = false; double xposOrig = currItem->xPos(); double yposOrig = currItem->yPos(); - ScOldNewState *state = m_doc->nodeEdit.finishTransaction1(currItem); + ScOldNewState *onState = m_doc->nodeEdit.finishTransaction1(currItem); + if (m_doc->nodeEdit.hasNodeSelected() && (m_doc->nodeEdit.selectionCount() == 1)) { + //FIXME:av - FPoint newP = m_canvas->globalToCanvas(m->globalPosition()); + // FPoint newP = m_canvas->globalToCanvas(m->globalPosition()); currItem->OldB2 = currItem->width(); currItem->OldH2 = currItem->height(); - FPointArray Clip; - FPoint npf; - double nx = newP.x(); - double ny = newP.y(); - if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true)) - npf = m_doc->ApplyGridF(FPoint(nx, ny)); - else - npf = FPoint(nx, ny); - QTransform pp = currItem->getTransform(); - npf = npf.transformPoint(pp, true); - if (m_doc->nodeEdit.isContourLine()) - Clip = currItem->ContourLine; - else - { - Clip = currItem->PoLine; - if (currItem->isSymbol() || currItem->isGroup()) - { - if (currItem->imageFlippedH()) - { - QTransform p; - p.translate(currItem->width(), 0); - p.scale(-1, 1); - npf = npf.transformPoint(p, false); - } - if (currItem->imageFlippedV()) - { - QTransform p; - p.translate(0, currItem->height()); - p.scale(1, -1); - npf = npf.transformPoint(p, false); - } - } - } - m_doc->nodeEdit.moveClipPoint(currItem, npf); + // currItem->ClipEdited = true; + // FPointArray Clip; + // FPoint npf; + // double nx = newP.x(); + // double ny = newP.y(); + // if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true)) + // npf = m_doc->ApplyGridF(FPoint(nx, ny)); + // else + // npf = FPoint(nx, ny); + // QTransform pp = currItem->getTransform(); + // npf = npf.transformPoint(pp, true); + // if (m_doc->nodeEdit.isContourLine()) + // Clip = currItem->ContourLine; + // else + // { + // Clip = currItem->PoLine; + // if (currItem->isSymbol() || currItem->isGroup()) + // { + // if (currItem->imageFlippedH()) + // { + // QTransform p; + // p.translate(currItem->width(), 0); + // p.scale(-1, 1); + // npf = npf.transformPoint(p, false); + // } + // if (currItem->imageFlippedV()) + // { + // QTransform p; + // p.translate(0, currItem->height()); + // p.scale(1, -1); + // npf = npf.transformPoint(p, false); + // } + // } + // } + // m_doc->nodeEdit.moveClipPoint(currItem, npf); } + // nitramr: Scribus crashes if ESC key is pressed during mouse drag operation m_doc->adjustItemSize(currItem, true); if (!m_doc->nodeEdit.isContourLine()) { @@ -450,41 +544,58 @@ currItem->ContourLine.translate(delta.x(), delta.y()); } m_doc->regionsChanged()->update(QRectF()); - if (state) - m_doc->nodeEdit.finishTransaction2(currItem, state); - return; - } + if (onState) + m_doc->nodeEdit.finishTransaction2(currItem, onState); - m_canvas->setRenderModeUseBuffer(false); - m_doc->DragP = false; - m_doc->leaveDrag = false; - m_canvas->m_viewMode.operItemMoving = false; - m_canvas->m_viewMode.operItemResizing = false; - m_view->MidButt = false; - if (m_view->groupTransactionStarted()) - { - for (int i = 0; i < m_doc->m_Selection->count(); ++i) - m_doc->m_Selection->itemAt(i)->checkChanges(true); - m_view->endGroupTransaction(); } - //Commit drag created items to undo manager. - if (m_doc->m_Selection->itemAt(0) != nullptr) + else { - m_doc->itemAddCommit(m_doc->m_Selection->itemAt(0)); + m_canvas->setRenderModeUseBuffer(false); + m_doc->DragP = false; + m_doc->leaveDrag = false; + m_canvas->m_viewMode.operItemMoving = false; + m_canvas->m_viewMode.operItemResizing = false; + m_view->MidButt = false; + if (m_view->groupTransactionStarted()) + { + for (int i = 0; i < m_doc->m_Selection->count(); ++i) + m_doc->m_Selection->itemAt(i)->checkChanges(true); + m_view->endGroupTransaction(); + } + //Commit drag created items to undo manager. + if (m_doc->m_Selection->itemAt(0) != nullptr) + m_doc->itemAddCommit(m_doc->m_Selection->itemAt(0)); + //Make sure the Zoom spinbox and page selector don't have focus if we click on the canvas + m_view->m_ScMW->zoomSpinBox->clearFocus(); + m_view->m_ScMW->pageSelector->clearFocus(); + if (m_doc->m_Selection->itemAt(0) != nullptr) // is there the old clip stored for the undo action + { + currItem = m_doc->m_Selection->itemAt(0); + m_doc->nodeEdit.finishTransaction(currItem); + } } - //Make sure the Zoom spinbox and page selector don't have focus if we click on the canvas - m_view->m_ScMW->zoomSpinBox->clearFocus(); - m_view->m_ScMW->pageSelector->clearFocus(); - if (m_doc->m_Selection->itemAt(0) != nullptr) // is there the old clip stored for the undo action - { - currItem = m_doc->m_Selection->itemAt(0); - m_doc->nodeEdit.finishTransaction(currItem); - } + + m_doc->nodeEdit.setMoveMode(state.originalMoveMode); + state.reset(); } void CanvasMode_NodeEdit::keyPressEvent(QKeyEvent *e) { commonkeyPressEvent_NormalNodeEdit(e); + + int kk = e->key(); +// Qt::KeyboardModifiers buttonModifiers = e->modifiers(); +// ScribusMainWindow* mainWindow = m_view->m_ScMW; + PageItem* currItem = m_doc->m_Selection->itemAt(0); + + if (kk == Qt::Key_Delete || kk == Qt::Key_Backspace) + { + if (currItem && m_doc->nodeEdit.hasNodeSelected()) + { + // delete Nodes + refreshPath(deleteNodes()); + } + } } void CanvasMode_NodeEdit::keyReleaseEvent(QKeyEvent *e) @@ -494,58 +605,131 @@ void CanvasMode_NodeEdit::handleNodeEditPress(QMouseEvent* m, QRect r) { - FPoint npf2; - bool edited = false; - bool pfound = false; - PageItem* currItem = m_doc->m_Selection->itemAt(0); FPointArray Clip = m_doc->nodeEdit.beginTransaction(currItem); - m_doc->nodeEdit.deselect(); + QTransform pm2 = currItem->getTransform(); + FPoint npf2 = m_canvas->globalToCanvas(m->globalPosition()).transformPoint(pm2, true); + bool edited = false; - QTransform pm2 = currItem->getTransform(); - npf2 = m_canvas->globalToCanvas(m->globalPosition()).transformPoint(pm2, true); - if ((currItem->isSymbol() || currItem->isGroup()) && (!m_doc->nodeEdit.isContourLine())) + state.originalMoveMode = m_doc->nodeEdit.moveMode(); + state.moveMode = state.originalMoveMode; + state.clickedOn = None; + m_doc->nodeEdit.oppositeControl.isValid = false; + + switch (state.hoveredOver) { - if (currItem->imageFlippedH()) + case ControlHandle: + case NodeHandle: + { + if ((currItem->isSymbol() || currItem->isGroup()) && (!m_doc->nodeEdit.isContourLine())) { - pm2.translate(currItem->width(), 0); - pm2.scale(-1, 1); + if (currItem->imageFlippedH()) + { + pm2.translate(currItem->width(), 0); + pm2.scale(-1, 1); + } + if (currItem->imageFlippedV()) + { + pm2.translate(0, currItem->height()); + pm2.scale(1, -1); + } } - if (currItem->imageFlippedV()) + + for (int i = 0; i < Clip.size(); ++i) { - pm2.translate(0, currItem->height()); - pm2.scale(1, -1); - } - } - for (int i = 0; i < Clip.size(); ++i) - { - if (((m_doc->nodeEdit.edPoints()) && (i % 2 != 0)) || ((!m_doc->nodeEdit.edPoints()) && (i % 2 == 0))) - continue; - QPointF npf = pm2.map(Clip.pointQF(i)); - if (m_canvas->hitsCanvasPoint(m->globalPosition(), npf)) - { - m_doc->nodeEdit.setClre(i); - if ((m_doc->nodeEdit.edPoints()) && (m_doc->nodeEdit.selNode().contains(i) == 0)) + if (m_canvas->hitsCanvasPoint(m->globalPosition(), pm2.map(Clip.pointQF(i)))) { - if (m->modifiers() != Qt::ShiftModifier) + if (state.originalMoveMode == NodeEditContext::Auto) + { + bool sameAngle = m_doc->nodeEdit.sameAngle(currItem, i); + bool sameLength = m_doc->nodeEdit.sameLength(currItem, i); + + if (sameLength && sameAngle) + state.moveMode = NodeEditContext::Symmetric; + else if (!sameLength && sameAngle) + state.moveMode = NodeEditContext::Asymmetric; + else if (!sameLength && !sameAngle) + state.moveMode = NodeEditContext::Independent; + } + + state.clickedOn = NodeEditContext::isNode(i) ? NodeHandle : ControlHandle; + + if (state.clickedOn == NodeHandle) + { + // Deselect all controls + m_doc->nodeEdit.deselectNodeControls(); + + if (!m_doc->nodeEdit.selNode().contains(i) && m->modifiers() != Qt::ShiftModifier) + m_doc->nodeEdit.selNode().clear(); + + state.wasNewlySelected = !m_doc->nodeEdit.selNode().contains(i); + + m_doc->nodeEdit.selectNode(i); + + if (m->modifiers() == Qt::AltModifier || m_doc->nodeEdit.submode() == NodeEditContext::EDIT_POINT) + { + // Reset Controls + if (state.moveMode != NodeEditContext::Independent || !NodeEditContext::hasTwoNodes(i, Clip)) + m_doc->nodeEdit.resetControl(currItem); + else // Make Control Handles symetric + m_doc->nodeEdit.equalizeControls(currItem); + } + } + + if (state.clickedOn == ControlHandle) + { m_doc->nodeEdit.selNode().clear(); - m_doc->nodeEdit.selectNode(i); + m_doc->nodeEdit.selectNode(i); + } + + m_doc->nodeEdit.setClre(i); + + // Save position of opposite control handle + int indexNode = NodeEditContext::indexOfNode(i, NodeEditContext::OppositeSibling, Clip.size()); + int indexControl = NodeEditContext::indexOfNode(i, NodeEditContext::Opposite, Clip.size()); + + double dx = Clip.point(indexControl).x() - Clip.point(indexNode).x(); + double dy = Clip.point(indexControl).y() - Clip.point(indexNode).y(); + + m_doc->nodeEdit.oppositeControl.isValid = NodeEditContext::hasTwoNodes(i, Clip); + m_doc->nodeEdit.oppositeControl.relativePos = Clip.point(indexControl) - Clip.point(indexNode); + m_doc->nodeEdit.oppositeControl.controlIndex = indexControl; + m_doc->nodeEdit.oppositeControl.nodeIndex = indexNode; + m_doc->nodeEdit.oppositeControl.distance = distance(dx, dy); + m_doc->nodeEdit.oppositeControl.angle = xy2Deg(dx, dy); + m_doc->nodeEdit.update(Clip.pointQF(i)); + edited = true; + + break; } - m_doc->nodeEdit.update(Clip.pointQF(i)); - pfound = true; - edited = true; - break; + + //deselect all if no node or control has hit + if (i == Clip.size() - 1) + m_doc->nodeEdit.deselect(); + } + + break; } - if ((!pfound) || (!m_doc->nodeEdit.edPoints())) - m_doc->nodeEdit.selNode().clear(); + case PathSegment: + m_doc->nodeEdit.deselect(); + state.clickedOn = PathSegment; + break; + case None: + default: + m_doc->nodeEdit.deselect(); + state.clickedOn = None; + break; + } - if ((m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT) && (m_doc->nodeEdit.clre() != -1) && !m_doc->nodeEdit.hasNodeSelected()) + if (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT && !m_doc->nodeEdit.hasNodeSelected() && state.clickedOn == PathSegment) { m_doc->nodeEdit.setSegP1(m_doc->nodeEdit.clre2()); m_doc->nodeEdit.setSegP2(m_doc->nodeEdit.clre2()+2); m_doc->nodeEdit.setClre(m_doc->nodeEdit.clre2()); } + + FPointArray cli; int EndInd = Clip.size(); int StartInd = 0; @@ -568,10 +752,10 @@ } } } - if (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH) + + if (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH && (state.clickedOn == NodeHandle || state.clickedOn == PathSegment)) { - if (!m_doc->nodeEdit.edPoints()) - return; + // Path Segment if ((!m_doc->nodeEdit.hasNodeSelected()) && (m_doc->nodeEdit.clre2() != -1)) // We don't have a Point, try to add one onto the current curve segment { bool foundP = false; @@ -582,7 +766,7 @@ FPoint tangent(0, 0); FPoint nearPoint(0, 0); double nearT = 0.0; - QRect mpo2(0, 0, m_doc->guidesPrefs().grabRadius*3, m_doc->guidesPrefs().grabRadius*3); + QRect mpo2(0, 0, m_doc->guidesPrefs().grabRadius * 3, m_doc->guidesPrefs().grabRadius * 3); mpo2.moveCenter(QPoint(qRound(npf2.x()), qRound(npf2.y()))); for (int poi = 0; poi < Clip.size() - 3; poi += 4) { @@ -594,7 +778,7 @@ Bez.moveTo(a1.x(), a1.y()); Bez.cubicTo(a2.x(), a2.y(), a3.x(), a3.y(), a4.x(), a4.y()); QPolygon cli2 = Bez.toFillPolygon().toPolygon(); - for (int clp = 0; clp < cli2.size()-1; ++clp) + for (int clp = 0; clp < cli2.size() - 1; ++clp) { if (m_view->PointOnLine(cli2.point(clp), cli2.point(clp + 1), mpo2)) { @@ -604,7 +788,7 @@ while (sp < 1.0) { Clip.pointTangentNormalAt(seg, sp, &point, &tangent, &normal ); - double d1 = fabs(sqrt(pow(point.x() - npf2.x(), 2) + pow(point.y() - npf2.y() ,2))); + double d1 = fabs(sqrt(pow(point.x() - npf2.x(), 2) + pow(point.y() - npf2.y(), 2))); if (d1 < absDist) { foundP = true; @@ -673,6 +857,7 @@ else m_doc->nodeEdit.deselect(); } + // Node Handle if (m_doc->nodeEdit.hasNodeSelected()) { if (currItem->isPolygon()) @@ -762,69 +947,14 @@ } } } - if ((m_doc->nodeEdit.submode() == NodeEditContext::DEL_POINT) && m_doc->nodeEdit.hasNodeSelected()) + + if ((m_doc->nodeEdit.submode() == NodeEditContext::DEL_POINT || m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT && m->modifiers() == Qt::ControlModifier) && m_doc->nodeEdit.hasNodeSelected() && state.clickedOn == NodeHandle) { - if (!m_doc->nodeEdit.edPoints()) - return; + edited = deleteNodes(); + } - int minClipSize = 4; - if (!currItem->isLine() && !currItem->isPathText() && !currItem->isPolyLine()) - minClipSize = 12; - - if (Clip.size() <= minClipSize) - { - m_doc->nodeEdit.deselect(); - return; - } - - int numPoints = (StartInd != 0) ? (StartInd-4) : 0; - numPoints += (Clip.size() - EndInd); - if ((currItem->Segments.count() > 0) && ((EndInd - StartInd) <= minClipSize) && (numPoints > 0)) - { - if (StartInd != 0) - cli.putPoints(0, StartInd - 4, Clip); - cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd); - } - else if (m_doc->nodeEdit.clre() == StartInd) - { - if (!currItem->isLine() && !currItem->isPathText() && !currItem->isPolyLine()) - { - const FPoint& kp(Clip.point(EndInd - 3)); - cli.putPoints(0, StartInd, Clip); - cli.putPoints(cli.size(), EndInd - StartInd - 4, Clip, StartInd); - cli.setPoint(StartInd, cli.point(cli.size() - 2)); - cli.setPoint(StartInd + 1, kp); - cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd); - } - else - { - cli.putPoints(0, StartInd, Clip); - cli.putPoints(cli.size(), EndInd - StartInd - 4, Clip, StartInd+4); - cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd); - } - } - else if (m_doc->nodeEdit.clre() == (EndInd - 2)) - { - Clip.remove(m_doc->nodeEdit.clre() - 2, 4); - cli = Clip.copy(); - } - else - { - if (m_doc->nodeEdit.clre() != 0) - cli.putPoints(0, m_doc->nodeEdit.clre(), Clip); - cli.putPoints(cli.size(), Clip.size() - (m_doc->nodeEdit.clre() + 4), Clip, m_doc->nodeEdit.clre() + 4); - } - while (cli.isMarker(0)) - cli.remove(0, 4); - if (m_doc->nodeEdit.isContourLine()) - currItem->ContourLine = cli.copy(); - else - currItem->PoLine = cli.copy(); - m_doc->nodeEdit.deselect(); - currItem->ClipEdited = true; - edited = true; - } - if ((m_doc->nodeEdit.submode() == NodeEditContext::ADD_POINT) && (m_doc->nodeEdit.clre2() != -1)) + // Add node id "add point" mode OR "move point" mode + CTRL + if ((m_doc->nodeEdit.submode() == NodeEditContext::ADD_POINT || m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT && m->modifiers() == Qt::ControlModifier) && (m_doc->nodeEdit.clre2() != -1)) { bool foundP = false; uint seg = 0; @@ -856,7 +986,7 @@ while (sp < 1.0) { Clip.pointTangentNormalAt(seg, sp, &point, &tangent, &normal ); - double d1 = fabs(sqrt(pow(point.x() - npf2.x(), 2) + pow(point.y() - npf2.y() ,2))); + double d1 = fabs(sqrt(pow(point.x() - npf2.x(), 2) + pow(point.y() - npf2.y(), 2))); if (d1 < absDist) { foundP = true; @@ -911,30 +1041,11 @@ currItem->ClipEdited = true; edited = true; } - if (edited) + + refreshPath(edited); + + if ((m_doc->nodeEdit.selectionCount() != 0) || ((m_doc->nodeEdit.segP1() != -1) && (m_doc->nodeEdit.segP2() != -1)) || (m_doc->nodeEdit.hasNodeSelected() && state.clickedOn == ControlHandle)) { - currItem->FrameType = 3; - double xp = currItem->xPos(); - double yp = currItem->yPos(); - double w = currItem->width(); - double h = currItem->height(); - m_doc->adjustItemSize(currItem, true); - double xp2 = currItem->xPos(); - double yp2 = currItem->yPos(); - double w2 = currItem->width(); - double h2 = currItem->height(); - currItem->update(); - if ((xp != xp2) || (yp != yp2) || (w != w2) || (h != h2)) - m_view->DrawNew(); - emit m_view->PolyStatus(currItem->itemType(), currItem->PoLine.size()); - } - else - { - currItem->update(); - m_view->DrawNew(); - } - if ((m_doc->nodeEdit.selectionCount() != 0) || ((m_doc->nodeEdit.segP1() != -1) && (m_doc->nodeEdit.segP2() != -1)) || (m_doc->nodeEdit.hasNodeSelected() && (!m_doc->nodeEdit.edPoints()))) - { m_Mxp = m->position().x(); m_Myp = m->position().y(); m_canvas->setRenderModeFillBuffer(); @@ -950,11 +1061,9 @@ m_rectangleSelect->prepare(m->globalPosition()); m_view->startGesture(m_rectangleSelect); } - + } - - bool CanvasMode_NodeEdit::handleNodeEditMove(QMouseEvent* m, QRect /*r*/, PageItem* currItem, const QTransform& /*t*/) { QTransform itemPos = currItem->getTransform(); @@ -965,6 +1074,7 @@ itemPos.translate(currItem->width(), 0); itemPos.scale(-1, 1); } + if (currItem->imageFlippedV()) { itemPos.translate(0, currItem->height()); @@ -971,38 +1081,49 @@ itemPos.scale(1, -1); } } - FPointArray Clip; + FPointArray Clip = m_doc->nodeEdit.clipFromItem(currItem); m_doc->nodeEdit.setClre2(-1); m_doc->nodeEdit.setSegP1(-1); m_doc->nodeEdit.setSegP2(-1); - if (m_doc->nodeEdit.isContourLine()) - Clip = currItem->ContourLine; - else - Clip = currItem->PoLine; + state.hoveredOver = None; + + // Hover mouse on node or control handle if ((m_doc->nodeEdit.submode() == NodeEditContext::DEL_POINT) || (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT) || - (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH)) + (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH) || + (m_doc->nodeEdit.submode() == NodeEditContext::EDIT_POINT)) { for (int i = 0; i < Clip.size(); ++i) { - if (((m_doc->nodeEdit.edPoints()) && (i % 2 != 0)) || ((!m_doc->nodeEdit.edPoints()) && (i % 2 == 0))) - continue; QPointF point = Clip.pointQF(i); if (m_canvas->hitsCanvasPoint(m->globalPosition(), itemPos.map(point))) { if (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT) - m_view->setCursor(QCursor(Qt::SizeAllCursor)); - if (m_doc->nodeEdit.submode() == NodeEditContext::DEL_POINT) - m_view->setCursor(IconManager::instance().loadCursor("cursor-remove-point", 1, 1)); - if (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH) - m_view->setCursor(IconManager::instance().loadCursor("cursor-split", 1, 1)); + m_view->setCursor(IconManager::instance().loadCursor("cursor-move", 1, 1)); + else if (m_doc->nodeEdit.submode() == NodeEditContext::EDIT_POINT) + m_view->setCursor(IconManager::instance().loadCursor("cursor-node-edit", 1, 1)); + + if (NodeEditContext::isNode(i)) + { + if (m_doc->nodeEdit.submode() == NodeEditContext::DEL_POINT || (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT && m->modifiers() == Qt::ControlModifier)) + m_view->setCursor(IconManager::instance().loadCursor("cursor-remove-point", 1, 1)); + else if (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH) + m_view->setCursor(IconManager::instance().loadCursor("cursor-split", 1, 1)); + + state.hoveredOver = NodeHandle; + } + else + state.hoveredOver = ControlHandle; + return true; } } } + + // Hover mouse on path segment if ((m_doc->nodeEdit.submode() == NodeEditContext::ADD_POINT) || (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT) || - (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH && m_doc->nodeEdit.edPoints())) + (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH)) { for (int poi = 0; poi < Clip.size() - 3; poi += 4) { @@ -1015,6 +1136,7 @@ Bez.moveTo(a1); Bez.cubicTo(a2, a3, a4); double len = Bez.length(); + if (len > 0.0) { double delta = 2.0 / len; @@ -1023,15 +1145,17 @@ QPointF pl = Bez.pointAtPercent(d); if (m_canvas->hitsCanvasPoint(m->globalPosition(), FPoint(pl.x(), pl.y()))) { - if (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT) + if (m_doc->nodeEdit.submode() == NodeEditContext::ADD_POINT || (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT && m->modifiers() == Qt::ControlModifier)) + m_view->setCursor(IconManager::instance().loadCursor("cursor-add-point", 1, 1)); + else if (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT) m_view->setCursor(IconManager::instance().loadCursor("cursor-hand")); - else if (m_doc->nodeEdit.submode() == NodeEditContext::ADD_POINT) - m_view->setCursor(IconManager::instance().loadCursor("cursor-add-point", 1, 1)); else if (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH) m_view->setCursor(IconManager::instance().loadCursor("cursor-split", 1, 1)); else m_view->setCursor(QCursor(Qt::ArrowCursor)); + m_doc->nodeEdit.setClre2(poi); + state.hoveredOver = PathSegment; return true; } } @@ -1044,6 +1168,7 @@ void CanvasMode_NodeEdit::handleNodeEditDrag(QMouseEvent* m, PageItem* currItem) { + // Selection Frame if ((m_canvas->m_viewMode.m_MouseButtonPressed) && !m_doc->nodeEdit.hasNodeSelected() && (m_doc->nodeEdit.segP1() == -1) && (m_doc->nodeEdit.segP2() == -1)) { if (!m_rectangleSelect) @@ -1052,6 +1177,7 @@ m_view->startGesture(m_rectangleSelect); return; } + FPoint npf; double newX = m->position().x(); double newY = m->position().y(); @@ -1059,6 +1185,8 @@ np = np * (1.0 / m_canvas->scale()); m_canvas->m_viewMode.operItemMoving = true; currItem = m_doc->m_Selection->itemAt(0); + + // Move Path Segment if ((m_doc->nodeEdit.segP1() != -1) && (m_doc->nodeEdit.segP2() != -1)) { if ((currItem->isSymbol() || currItem->isGroup()) && (!m_doc->nodeEdit.isContourLine())) @@ -1068,37 +1196,38 @@ if (currItem->imageFlippedV()) np.setY(np.y() * -1); } - if (m_doc->nodeEdit.isContourLine()) - npf = currItem->ContourLine.point(m_doc->nodeEdit.segP2()) + np; - else - npf = currItem->PoLine.point(m_doc->nodeEdit.segP2()) + np; + + // First segment + npf = m_doc->nodeEdit.clipFromItem(currItem).point(m_doc->nodeEdit.segP2()) + np; m_doc->nodeEdit.setClre(m_doc->nodeEdit.segP2()); m_doc->nodeEdit.moveClipPoint(currItem, npf); - if (m_doc->nodeEdit.isContourLine()) - npf = currItem->ContourLine.point(m_doc->nodeEdit.segP1() ) + np; - else - npf = currItem->PoLine.point(m_doc->nodeEdit.segP1() ) + np; + + // Second segment + npf = m_doc->nodeEdit.clipFromItem(currItem).point(m_doc->nodeEdit.segP1()) + np; m_doc->nodeEdit.setClre(m_doc->nodeEdit.segP1()); m_doc->nodeEdit.moveClipPoint(currItem, npf); m_Mxp = newX; m_Myp = newY; } + // Move Nodes or Controls else { - if ((m_doc->nodeEdit.selectionCount() != 0) && (m_doc->nodeEdit.edPoints())) + if ((m_doc->nodeEdit.selectionCount() > 0) && (state.clickedOn == NodeHandle || state.clickedOn == ControlHandle)) { - int storedClRe = m_doc->nodeEdit.clre(); + // Single Nodes if (m_doc->nodeEdit.selectionCount() == 1) { npf = m_canvas->globalToCanvas(m->globalPosition()); double nx = npf.x(); double ny = npf.y(); - if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true)) + if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny, true)) npf = m_doc->ApplyGridF(FPoint(nx, ny)); else npf = FPoint(nx, ny); + QTransform pp = currItem->getTransform(); npf = npf.transformPoint(pp, true); + if ((currItem->isSymbol() || currItem->isGroup()) && (!m_doc->nodeEdit.isContourLine())) { if (currItem->imageFlippedH()) @@ -1116,55 +1245,81 @@ npf = npf.transformPoint(p, false); } } - FPoint npf1(npf); - //Control Modifier to have parallel shape - if (m->modifiers() == Qt::ControlModifier) + + int curr = m_doc->nodeEdit.clre(); + FPoint pOpposite = m_doc->nodeEdit.getPoint(currItem, m_doc->nodeEdit.oppositeControl.nodeIndex); + FPoint pSibling = m_doc->nodeEdit.getPoint(currItem, curr, NodeEditContext::Sibling); + + if (m->modifiers() & Qt::ShiftModifier || m_doc->nodeEdit.submode() == NodeEditContext::EDIT_POINT) { - FPointArray cli; - if (m_doc->nodeEdit.isContourLine()) - cli = currItem->ContourLine; - else - cli = currItem->PoLine; - int tmpNode; - int curr = (m_doc->nodeEdit.clre() == 0) ? cli.size() - 2 : m_doc->nodeEdit.clre(); - int prev = (curr + cli.size() - 4) % cli.size(); - int next = (curr + 4) % cli.size(); + // Shift + drag on control + if (!NodeEditContext::isNode(curr) && state.clickedOn == ControlHandle) + { + m_doc->nodeEdit.setMoveMode(NodeEditContext::Independent); - if (std::abs(cli.point(prev).x() - cli.point(curr).x()) < std::abs(cli.point(next).x() - cli.point(curr).x())) - tmpNode = next; - else if (std::abs(cli.point(prev).x() - cli.point(curr).x()) == std::abs(cli.point(next).x() - cli.point(curr).x())) + if (m_doc->nodeEdit.oppositeControl.isValid) + { + m_doc->nodeEdit.setClre(m_doc->nodeEdit.oppositeControl.controlIndex); + m_doc->nodeEdit.moveClipPoint(currItem, pOpposite + m_doc->nodeEdit.oppositeControl.relativePos); + m_doc->nodeEdit.setClre(curr); + } + } + + // Shift + drag on node + if (NodeEditContext::isNode(curr) && state.clickedOn == NodeHandle) { - if (cli.point(prev).y() != cli.point(curr).y()) - tmpNode = next; - else - tmpNode = prev; + m_doc->nodeEdit.setMoveMode(NodeEditContext::Symmetric); + m_doc->nodeEdit.setClre(curr + 1); } - else - tmpNode = prev; + } + else + m_doc->nodeEdit.setMoveMode(state.moveMode); - m_doc->nodeEdit.moveClipPoint(currItem, npf); - m_doc->nodeEdit.setClre(tmpNode); + if (m->modifiers() & Qt::ControlModifier) + { + // Snap control handle at 15° steps + if (!NodeEditContext::isNode(curr)) + npf = constraintControlAngle(m_doc->nodeEdit.getPoint(currItem, curr, NodeEditContext::Sibling), npf, 15.0); - if (m_doc->nodeEdit.isContourLine()) - npf1.setX(currItem->ContourLine.point(m_doc->nodeEdit.clre()).x()); - else - npf1.setX(currItem->PoLine.point(m_doc->nodeEdit.clre()).x()); + } - m_doc->nodeEdit.moveClipPoint(currItem, npf1); + // Snap control handle + if (!NodeEditContext::isNode(curr) && state.clickedOn == ControlHandle) + { + state.isSameAngle = m_doc->nodeEdit.sameAngle(currItem, curr); + state.isSameLength = m_doc->nodeEdit.sameLength(currItem, curr); - if (m_doc->nodeEdit.clre() == prev) - m_doc->nodeEdit.setClre(next); - else - m_doc->nodeEdit.setClre(prev); + bool modifier = m->modifiers() & Qt::ShiftModifier || m_doc->nodeEdit.submode() == NodeEditContext::EDIT_POINT; - if (m_doc->nodeEdit.isContourLine()) - npf.setY(currItem->ContourLine.point(m_doc->nodeEdit.clre()).y()); - else - npf.setY(currItem->PoLine.point(m_doc->nodeEdit.clre()).y()); + // let's snap the control angle to opposite reference + if (state.isSameAngle && (m_doc->nodeEdit.moveMode() == NodeEditContext::Auto || m_doc->nodeEdit.moveMode() == NodeEditContext::Independent || modifier)) + npf = snapControlAngle(pOpposite, npf, m_doc->nodeEdit.oppositeControl.angle - 180.0); + + // let's snap the control length to opposite reference + if (state.isSameLength && state.isSameAngle && (m_doc->nodeEdit.moveMode() != NodeEditContext::Symmetric || modifier)) + npf = snapControlLength(pOpposite, npf, m_doc->nodeEdit.oppositeControl.distance); + + // let's snap the control to same position as control anchor if control is too close + npf = snapControlOrigin(pSibling, npf); } + + // Snap node handle + // if (NodeEditContext::isNode(curr) && state.clickedOn == NodeHandle) + // { + // FPointArray Clip = m_doc->nodeEdit.isContourLine() ? currItem->ContourLine : currItem->PoLine; + // FPoint pOppositeNode = m_doc->nodeEdit.getPoint(currItem, curr, NodeEditContext::Opposite); + + // if (curr == 0 || curr == Clip.size() -2) + // { + // // TODO: close bezier curve and merge endpoints + // npf = snapControlOrigin(pOppositeNode, npf); + // } + // } + m_doc->nodeEdit.moveClipPoint(currItem, npf); - m_canvas->displayXYHUD(m->globalPosition(), npf.x(), npf1.y()); + m_canvas->displayXYHUD(m->globalPosition(), npf.x(), npf.y()); } + // Multiple Nodes else { if ((currItem->isSymbol() || currItem->isGroup()) && (!m_doc->nodeEdit.isContourLine())) @@ -1174,53 +1329,147 @@ if (currItem->imageFlippedV()) np.setY(np.y() * -1); } + const auto& nodeSelection = m_doc->nodeEdit.selNode(); for (int itm = 0; itm < nodeSelection.count(); ++itm) { m_doc->nodeEdit.setClre(nodeSelection.at(itm)); - if (m_doc->nodeEdit.isContourLine()) - npf = currItem->ContourLine.point(m_doc->nodeEdit.clre()) + np; - else - npf = currItem->PoLine.point(m_doc->nodeEdit.clre()) + np; + npf = m_doc->nodeEdit.clipFromItem(currItem).point(m_doc->nodeEdit.clre()) + np; m_doc->nodeEdit.moveClipPoint(currItem, npf); } } - m_doc->nodeEdit.setClre(storedClRe); } - else + + m_Mxp = newX; + m_Myp = newY; + + } + m_canvas->m_viewMode.operItemMoving = false; + m_doc->regionsChanged()->update(QRectF()); +} + +bool CanvasMode_NodeEdit::deleteNodes() +{ + PageItem* currItem = m_doc->m_Selection->itemAt(0); + FPointArray Clip = m_doc->nodeEdit.beginTransaction(currItem); + + if (!currItem || Clip.size() == 0) + return false; + + FPointArray cli; + int EndInd = Clip.size(); + int StartInd = 0; + if (m_doc->nodeEdit.clre() > 0) + { + for (int n = m_doc->nodeEdit.clre(); n < Clip.size(); ++n) { - npf = m_canvas->globalToCanvas(m->globalPosition()); - double nx = npf.x(); - double ny = npf.y(); - if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true)) - npf = m_doc->ApplyGridF(FPoint(nx, ny)); + if (Clip.isMarker(n)) + { + EndInd = n; + break; + } + } + for (int n2 = m_doc->nodeEdit.clre(); n2 > 0; n2--) + { + if (Clip.isMarker(n2)) + { + StartInd = n2 + 1; + break; + } + } + } + + if (m_doc->nodeEdit.hasNodeSelected()) + { + int minClipSize = 4; + if (!currItem->isLine() && !currItem->isPathText() && !currItem->isPolyLine()) + minClipSize = 12; + + if (Clip.size() <= minClipSize) + { + m_doc->nodeEdit.deselect(); + return false; + } + + int numPoints = (StartInd != 0) ? (StartInd-4) : 0; + numPoints += (Clip.size() - EndInd); + if ((currItem->Segments.count() > 0) && ((EndInd - StartInd) <= minClipSize) && (numPoints > 0)) + { + if (StartInd != 0) + cli.putPoints(0, StartInd - 4, Clip); + cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd); + } + else if (m_doc->nodeEdit.clre() == StartInd) + { + if (!currItem->isLine() && !currItem->isPathText() && !currItem->isPolyLine()) + { + const FPoint& kp(Clip.point(EndInd - 3)); + cli.putPoints(0, StartInd, Clip); + cli.putPoints(cli.size(), EndInd - StartInd - 4, Clip, StartInd); + cli.setPoint(StartInd, cli.point(cli.size() - 2)); + cli.setPoint(StartInd + 1, kp); + cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd); + } else - npf = FPoint(nx, ny); - QTransform pp = currItem->getTransform(); - npf = npf.transformPoint(pp, true); - if ((currItem->isSymbol() || currItem->isGroup()) && (!m_doc->nodeEdit.isContourLine())) { - if (currItem->imageFlippedH()) - { - QTransform p; - p.translate(currItem->width(), 0); - p.scale(-1, 1); - npf = npf.transformPoint(p, false); - } - if (currItem->imageFlippedV()) - { - QTransform p; - p.translate(0, currItem->height()); - p.scale(1, -1); - npf = npf.transformPoint(p, false); - } + cli.putPoints(0, StartInd, Clip); + cli.putPoints(cli.size(), EndInd - StartInd - 4, Clip, StartInd+4); + cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd); } - m_doc->nodeEdit.moveClipPoint(currItem, npf); - m_canvas->displayXYHUD(m->globalPosition(), npf.x(), npf.y()); } - m_Mxp = newX; - m_Myp = newY; + else if (m_doc->nodeEdit.clre() == (EndInd - 2)) + { + Clip.remove(m_doc->nodeEdit.clre() - 2, 4); + cli = Clip.copy(); + } + else + { + if (m_doc->nodeEdit.clre() != 0) + cli.putPoints(0, m_doc->nodeEdit.clre(), Clip); + cli.putPoints(cli.size(), Clip.size() - (m_doc->nodeEdit.clre() + 4), Clip, m_doc->nodeEdit.clre() + 4); + } + while (cli.isMarker(0)) + cli.remove(0, 4); + if (m_doc->nodeEdit.isContourLine()) + currItem->ContourLine = cli.copy(); + else + currItem->PoLine = cli.copy(); + m_doc->nodeEdit.deselect(); + currItem->ClipEdited = true; + return true; } - m_canvas->m_viewMode.operItemMoving = false; - m_doc->regionsChanged()->update(QRectF()); + + + return false; } + +void CanvasMode_NodeEdit::refreshPath(bool edited) +{ + PageItem* currItem = m_doc->m_Selection->itemAt(0); + + if (!currItem) + return; + + if (edited) + { + currItem->FrameType = 3; + double xp = currItem->xPos(); + double yp = currItem->yPos(); + double w = currItem->width(); + double h = currItem->height(); + m_doc->adjustItemSize(currItem, true); + double xp2 = currItem->xPos(); + double yp2 = currItem->yPos(); + double w2 = currItem->width(); + double h2 = currItem->height(); + currItem->update(); + if ((xp != xp2) || (yp != yp2) || (w != w2) || (h != h2)) + m_view->DrawNew(); + emit m_view->PolyStatus(currItem->itemType(), currItem->PoLine.size()); + } + else + { + currItem->update(); + m_view->DrawNew(); + } +} Index: scribus/canvasmode_nodeedit.h =================================================================== --- scribus/canvasmode_nodeedit.h (Revision 26704) +++ scribus/canvasmode_nodeedit.h (Arbeitskopie) @@ -19,6 +19,7 @@ #define CANVAS_MODE_NODEEDIT_H #include "canvasmode.h" +#include "nodeeditcontext.h" #include #include @@ -38,8 +39,8 @@ void activate(bool fromgesture) override; void deactivate(bool forGesture) override; - void enterEvent(QEvent *) override; - void leaveEvent(QEvent *) override; + void enterEvent(QEvent *) override {}; + void leaveEvent(QEvent *) override {}; void mouseDoubleClickEvent(QMouseEvent *m) override; void mouseReleaseEvent(QMouseEvent *m) override; @@ -55,13 +56,45 @@ void drawControls(QPainter* p) override; private: + + enum MouseMode { None = 0, NodeHandle, ControlHandle, PathSegment }; + + struct StateManager { + MouseMode clickedOn { None }; + MouseMode hoveredOver { None }; + bool isSameLength {false}; + bool isSameAngle {false}; + bool wasNewlySelected { false }; + NodeEditContext::ControlMoveMode originalMoveMode { NodeEditContext::ControlMoveMode::Auto }; + NodeEditContext::ControlMoveMode moveMode { originalMoveMode }; // we need this for converted auto mode + + void reset() + { + clickedOn = None; + isSameLength = false; + isSameAngle = false; + wasNewlySelected = false; + moveMode = NodeEditContext::ControlMoveMode::Auto; + } + }; + inline bool GetItem(PageItem** pi); + QMap selectedNodesList(FPointArray points); void handleNodeEditPress(QMouseEvent*, QRect r); void handleNodeEditDrag(QMouseEvent*, PageItem*); bool handleNodeEditMove(QMouseEvent*, QRect r, PageItem*, const QTransform&); + FPoint constraintControlAngle(FPoint anchor, FPoint mouse, double angleStep); + FPoint snapControlAngle(FPoint anchor, FPoint mouse, double angle); + FPoint snapControlLength(FPoint anchor, FPoint mouse, double length); + FPoint snapControlOrigin(FPoint anchor, FPoint mouse); + bool deleteNodes(); + void updateItem(PageItem* currItem); + void refreshPath(bool edited); + ScribusMainWindow* m_ScMW { nullptr }; RectSelect* m_rectangleSelect { nullptr }; + StateManager state; double m_Mxp { -1.0 }; // last mouse position double m_Myp { -1.0 }; @@ -71,6 +104,7 @@ double m_GyM { -1.0 }; bool m_MoveGX { false }; bool m_MoveGY { false }; + }; Index: scribus/nodeeditcontext.cpp =================================================================== --- scribus/nodeeditcontext.cpp (Revision 26704) +++ scribus/nodeeditcontext.cpp (Arbeitskopie) @@ -23,9 +23,34 @@ void NodeEditContext::selectNode(int i) { m_ClRe = i; - m_SelNode.append(i); + if (!m_SelNode.contains(i)) + m_SelNode.append(i); } +void NodeEditContext::deselectNode(int i) +{ + int index = m_SelNode.indexOf(i); + m_SelNode.removeAll(i); + if (m_SelNode.count() == 0) + m_ClRe = -1; + else // select previous node or last one if there is no previous one + m_ClRe = (index - 1 >= 0) ? m_SelNode.at(index - 1) : m_SelNode.last(); +} + +void NodeEditContext::deselectNodeControls() +{ + for (int i = 0; i < m_SelNode.count(); i++) + { + if (!isNode(m_SelNode.at(i))) + { + m_SelNode.removeAt(i); + i --; + } + } + if (m_SelNode.count() == 0) + m_ClRe = -1; +} + int NodeEditContext::selectionCount() const { return m_SelNode.count(); @@ -42,7 +67,7 @@ delete oldClip; oldClip = nullptr; nodeTransaction.reset(); - m_MoveSym = false; + m_moveMode = Auto; m_SelNode.clear(); m_preview = false; } @@ -83,8 +108,6 @@ return Clip; } - - void NodeEditContext::finishTransaction(PageItem* currItem) { ScribusDoc* Doc = currItem->doc(); @@ -116,7 +139,6 @@ oldClip = nullptr; } - /** first part: create a new UndoState or cancel the current transaction */ @@ -167,25 +189,28 @@ delete oldClip; oldClip = nullptr; } - //CB-->Doc void NodeEditContext::moveClipPoint(PageItem *currItem, const FPoint& ip) { ScribusDoc* Doc = currItem->doc(); - if (((m_EdPoints) && (m_ClRe % 2 != 0)) || ((!m_EdPoints) && (m_ClRe % 2 == 0))) - return; + double xposOrig = currItem->xPos(); double yposOrig = currItem->yPos(); currItem->ClipEdited = true; + FPointArray Clip; + FPoint np(ip); + if (m_isContourLine) Clip = currItem->ContourLine.copy(); else Clip = currItem->PoLine.copy(); currItem->FrameType = 3; + uint EndInd = Clip.size(); uint StartInd = 0; + for (int n = m_ClRe; n < Clip.size(); ++n) { if (Clip.isMarker(n)) @@ -194,6 +219,7 @@ break; } } + if (m_ClRe > 0) { for (int n2 = m_ClRe; n2 > 0; n2--) @@ -205,9 +231,10 @@ } } } - FPoint np(ip); + if (hasNodeSelected()) { + // expand item on left side if x is out of bound if ((np.x() < 0) && (!m_isContourLine) && (!(currItem->isGroup() || currItem->isSymbol()))) { Doc->sizeItem(currItem->width() - np.x(), currItem->height(), currItem, false, false, false); @@ -223,6 +250,8 @@ currItem->moveImageInFrame(-np.x()/currItem->imageXScale(), 0); np.setX(0); } + + // expand item on top side if y is out of bound if ((np.y() < 0) && (!m_isContourLine) && (!(currItem->isGroup() || currItem->isSymbol()))) { Doc->sizeItem(currItem->width(), currItem->height() - np.y(), currItem, false, false, false); @@ -239,7 +268,9 @@ np.setY(0); } update(QPointF(np.x(), np.y())); - if ((m_ClRe + 1 < static_cast(EndInd)) && (m_ClRe % 2 == 0)) + + // update control of node + if (isNode(m_ClRe) && (m_ClRe + 1 < static_cast(EndInd))) { FPoint ap(Clip.point(m_ClRe)); FPoint ap2(Clip.point(m_ClRe + 1)); @@ -247,8 +278,11 @@ ap2.setY(ap2.y() - (ap.y() - np.y())); Clip.setPoint(m_ClRe + 1, ap2); } + Clip.setPoint(m_ClRe, np); - if (((m_ClRe % 4 != 0) && (m_ClRe % 2 == 0)) && (m_ClRe + 3 < static_cast(EndInd)) && (m_ClRe != static_cast(StartInd))) + + // update right node with control + if (isLeftNode(m_ClRe) && (m_ClRe + 3 < static_cast(EndInd)) && (m_ClRe != static_cast(StartInd))) { FPoint ap(Clip.point(m_ClRe + 2)); FPoint ap2(Clip.point(m_ClRe + 3)); @@ -257,7 +291,9 @@ Clip.setPoint(m_ClRe + 3, ap2); Clip.setPoint(m_ClRe + 2, np); } - if ((m_ClRe % 4 == 0) && (m_ClRe + 3 < static_cast(EndInd)) && (m_ClRe != static_cast(StartInd))) + + // update left node with control + if (isRightNode(m_ClRe) && (m_ClRe + 3 < static_cast(EndInd)) && (m_ClRe != static_cast(StartInd))) { FPoint ap(Clip.point(m_ClRe - 2)); FPoint ap2(Clip.point(m_ClRe - 1)); @@ -266,6 +302,8 @@ Clip.setPoint(m_ClRe - 1, ap2); Clip.setPoint(m_ClRe - 2, np); } + + // update first or last node with control if (((m_ClRe == static_cast(StartInd)) || (m_ClRe == static_cast(EndInd - 2))) && ((currItem->itemType() == PageItem::Polygon) || (currItem->itemType() == PageItem::Group) @@ -275,7 +313,7 @@ { if (m_ClRe == static_cast(StartInd)) { - FPoint ap(Clip.point(EndInd- 2)); + FPoint ap(Clip.point(EndInd - 2)); FPoint ap2(Clip.point(EndInd - 1)); ap2.setX(ap2.x() - (ap.x() - np.x())); ap2.setY(ap2.y() - (ap.y() - np.y())); @@ -292,48 +330,53 @@ Clip.setPoint(StartInd + 1, ap2); } } - if (((m_ClRe == static_cast(StartInd + 1)) || (m_ClRe == static_cast(EndInd - 1))) && - ((currItem->itemType() == PageItem::Polygon) + + bool firstLastControl = ((m_ClRe == static_cast(StartInd + 1)) || (m_ClRe == static_cast(EndInd - 1))) + && ((currItem->itemType() == PageItem::Polygon) || (currItem->itemType() == PageItem::Group) || (currItem->itemType() == PageItem::Symbol) || (currItem->itemType() == PageItem::TextFrame) - || (currItem->itemType() == PageItem::ImageFrame)) && - (m_MoveSym)) + || (currItem->itemType() == PageItem::ImageFrame)); + + bool anyControl = !isNode(m_ClRe) && (m_ClRe != static_cast(StartInd + 1)) && (m_ClRe != static_cast(EndInd - 1)); + + // update control if there is an opposite control + if (firstLastControl || anyControl) { - uint kon = 0; - if (m_ClRe == static_cast(StartInd + 1)) - kon = EndInd - 1; - else - kon = StartInd + 1; - FPoint lxy(Clip.point(m_ClRe - 1)); - FPoint lk(Clip.point(m_ClRe)); - double dx = lxy.x() - lk.x(); - double dy = lxy.y() - lk.y(); - lk.setX(lk.x() + dx * 2); - lk.setY(lk.y() + dy * 2); - Clip.setPoint(kon, lk); + int kon = indexOfNode(m_ClRe, Opposite, Clip.size()); + + FPoint pn1(Clip.point(m_ClRe - 1)); + FPoint pc1(Clip.point(m_ClRe)); + FPoint pc2(pn1 + oppositeControl.relativePos); + + double dx = pn1.x() - pc1.x(); + double dy = pn1.y() - pc1.y(); + + if (moveMode() == Symmetric) + { + pc2.setX(pc1.x() + dx * 2); + pc2.setY(pc1.y() + dy * 2); + Clip.setPoint(kon, pc2); + } + else if (moveMode() == Asymmetric) + { + double dx2 = pn1.x() - pc2.x(); + double dy2 = pn1.y() - pc2.y(); + + double angle = xy2Deg(dx, dy); + double dist = distance(dx2, dy2); + Clip.setPoint(kon, getPointFromRotation(pn1, dist, angle)); + } } - if ((m_ClRe % 2 != 0) && (m_MoveSym) && (m_ClRe != static_cast(StartInd + 1)) && (m_ClRe != static_cast(EndInd - 1))) - { - uint kon = 0; - if ((m_ClRe + 1) % 4 == 0) - kon = m_ClRe + 2; - else - kon = m_ClRe - 2; - FPoint lxy(Clip.point(m_ClRe - 1)); - FPoint lk(Clip.point(m_ClRe)); - double dx = lxy.x() - lk.x(); - double dy = lxy.y() - lk.y(); - lk.setX(lk.x() + dx * 2); - lk.setY(lk.y() + dy * 2); - Clip.setPoint(kon, lk); - } + if (Doc->nodeEdit.m_isContourLine) currItem->ContourLine = Clip.copy(); else currItem->PoLine = Clip.copy(); + currItem->Clip = flattenPath(currItem->PoLine, currItem->Segments); } + if (!m_isContourLine) { // Move the contour accordingly in the item's coordinate space @@ -343,12 +386,265 @@ } } +void NodeEditContext::equalizeControls(PageItem* currItem) +{ + FPointArray Clip(clipFromItem(currItem)); + int old = m_ClRe; + ControlMoveMode cmm = moveMode(); + FPoint cl, nl, nr, cr; + getPoints(currItem, m_ClRe, cl, nl, nr, cr); + + // if there is no left control we use the right one as reference + int indexControl = indexOfNode(m_ClRe, (nl == cl) ? ControlRight : ControlLeft, Clip.size()); + + // apply changes to opposite control + setMoveMode(Symmetric); + setClre(indexControl); + moveClipPoint(currItem, Clip.point(indexControl)); + + // restore old values + setClre(old); + setMoveMode(cmm); +} + +/** + * @brief NodeEditContext::getPoints Map all handle indecies based on i. A bezier curve start with right node and ends with left node + * @param currItem Current PageItem + * @param i index of any point in page item path + * @param ctrlLeft return index of left control handle + * @param nodeLeft return index of left node + * @param nodeRight return index of right node + * @param ctrlRight return index of right control handle + */ +void NodeEditContext::getPoints(PageItem* currItem, int i, FPoint& ctrlLeft, FPoint& nodeLeft, FPoint& nodeRight, FPoint& ctrlRight) +{ + i = (i == -1) ? m_ClRe : i; + + if (i < 0) + return; + + nodeLeft = getPoint(currItem, i, NodeType::NodeLeft); + ctrlLeft = getPoint(currItem, i, NodeType::ControlLeft); + nodeRight = getPoint(currItem, i, NodeType::NodeRight); + ctrlRight = getPoint(currItem, i, NodeType::ControlRight); +} + +FPoint NodeEditContext::getPoint(PageItem* currItem, int i, NodeType nodeType) +{ + FPointArray Clip(clipFromItem(currItem)); + return Clip.point(indexOfNode(i, nodeType, Clip.size())); +} + +bool NodeEditContext::isSymetric(PageItem* currItem, int i) +{ + return sameAngle(currItem, i) && sameLength(currItem, i); +} + +bool NodeEditContext::sameAngle(PageItem* currItem, int i) +{ + double snap = currItem->doc()->prefsData().guidesPrefs.guideRad / m_scale; + + FPoint pcl, pnl, pnr, pcr; + getPoints(currItem, i, pcl, pnl, pnr, pcr); + + if (pnr != pnl) + return false; + + QLineF lineLeft(pnl.toQPointF(), pcl.toQPointF()); + QLineF lineRight(pnr.toQPointF(), pcr.toQPointF()); + lineRight.setAngle(lineRight.angle() - 180); + + if (qMax(lineLeft.angle(), lineRight.angle()) - qMin(lineLeft.angle(), lineRight.angle()) <= 0.00001) + return true; + + if (lineLeft.length() >= lineRight.length()) + lineRight.setLength(lineLeft.length()); + else + lineLeft.setLength(lineRight.length()); + + QLineF distance(lineLeft.p2(), lineRight.p2()); + + return distance.length() <= snap ? true : false; +} + +bool NodeEditContext::sameLength(PageItem* currItem, int i) +{ + double snap = currItem->doc()->prefsData().guidesPrefs.guideRad / m_scale; + FPoint pcl, pnl, pnr, pcr; + getPoints(currItem, i, pcl, pnl, pnr, pcr); + + if (pnl != pnr) + return false; + + // length = 0 + if (pcl == pcr) + return true; + + double l1 = QLineF(pnl.toQPointF(), pcl.toQPointF()).length(); + double l2 = QLineF(pnr.toQPointF(), pcr.toQPointF()).length(); + + // Check if both controls have same length with difference + return (qMax(l1, l2) - qMin(l1, l2) <= snap) ? true : false; +} + +bool NodeEditContext::isLeftControl(int i) +{ + return (i + 1) % 4 == 0; +} + +bool NodeEditContext::isLeftNode(int i) +{ + return (i % 4 != 0) && isNode(i); +} + +bool NodeEditContext::isRightNode(int i) +{ + return i % 4 == 0; +} + +bool NodeEditContext::isRightControl(int i) +{ + return (i - 1) % 4 == 0; +} + +bool NodeEditContext::hasTwoNodes(int i, FPointArray clip) +{ + int ln = indexOfNode(i, NodeLeft, clip.size()); + int rn = indexOfNode(i, NodeRight, clip.size()); + + return clip.point(ln) == clip.point(rn); +} + +bool NodeEditContext::isSharpNode(int i, FPointArray clip) +{ + int lc = indexOfNode(i, ControlLeft, clip.size()); + int rc = indexOfNode(i, ControlRight, clip.size()); + int ln = indexOfNode(i, NodeLeft, clip.size()); + int rn = indexOfNode(i, NodeRight, clip.size()); + + return clip.point(ln) == clip.point(rn) && clip.point(ln) == clip.point(lc) && clip.point(rn) == clip.point(rc); +} + +/** + * @brief NodeEditContext::indexOfNode Returns the node index based on the input index and node type. + * If size is specified, an index between 0 and size is returned. Values ​​outside this range are corrected. + * @param i Any index of FPointArray + * @param type Node type for output + * @param size Max size of node array + * @return return index of requested node type based on input index. + */ +int NodeEditContext::indexOfNode(int i, NodeType type, int size) +{ + if (size != -1) + i = qBound(0, i, size); + + if (isRightControl(i)) + { + switch (type) + { + case NodeType::OppositeSibling: + case NodeType::NodeLeft: + i -= 3; + break; + case NodeType::Opposite: + case NodeType::ControlLeft: + i -= 2; + break; + case NodeType::Sibling: + case NodeType::NodeRight: + i -= 1; + break; + case NodeType::Self: + case NodeType::ControlRight: + break; + } + + if (size != -1 && i < 0) + i = size - abs(i); + } + else if (isLeftControl(i)) + { + switch (type) + { + case NodeType::Sibling: + case NodeType::NodeLeft: + i -= 1; + break; + case NodeType::Self: + case NodeType::ControlLeft: + break; + case NodeType::OppositeSibling: + case NodeType::NodeRight: + i += 1; + break; + case NodeType::Opposite: + case NodeType::ControlRight: + i += 2; + break; + } + + if (size != -1 && i >= size) + i -= size; + } + else if (isRightNode(i)) + { + switch (type) + { + case NodeType::Opposite: + case NodeType::NodeLeft: + i -= 2; + break; + case NodeType::OppositeSibling: + case NodeType::ControlLeft: + i -= 1; + break; + case NodeType::Self: + case NodeType::NodeRight: + break; + case NodeType::Sibling: + case NodeType::ControlRight: + i += 1; + break; + } + + if (size != -1 && i < 0) + i = size - abs(i); + } + else if (isLeftNode(i)) + { + switch (type) + { + case NodeType::Self: + case NodeType::NodeLeft: + break; + case NodeType::Sibling: + case NodeType::ControlLeft: + i += 1; + break; + case NodeType::Opposite: + case NodeType::NodeRight: + i += 2; + break; + case NodeType::OppositeSibling: + case NodeType::ControlRight: + i += 3; + break; + } + + if (size != -1 && i >= size) + i -= size; + } + + return i; +} + void NodeEditContext::reset1Control(PageItem* currItem) -{ +{ + if ((m_ClRe < 0) || isNode(m_ClRe)) + return; + ScribusDoc* Doc = currItem->doc(); - if ((m_ClRe < 0) || (m_ClRe % 2 == 0)) - return; UndoManager* undoManager = UndoManager::instance(); // do no record anything else but the core reset points action @@ -401,13 +697,13 @@ void NodeEditContext::resetControl(PageItem* currItem) { ScribusDoc* Doc = currItem->doc(); - if (m_ClRe < 0) + if (m_ClRe < 0 || !isNode(m_ClRe)) return; UndoManager* undoManager = UndoManager::instance(); // do no record anything else but the core reset points action undoManager->setUndoEnabled(false); - + oldClip = new FPointArray(Doc->nodeEdit.m_isContourLine ? currItem->ContourLine.copy() : currItem->PoLine.copy()); m_oldItemX = currItem->xPos(); m_oldItemY = currItem->yPos(); @@ -458,8 +754,8 @@ } else { - Clip.setPoint(Doc->nodeEdit.m_ClRe + 1, np); - Clip.setPoint((Doc->nodeEdit.m_ClRe % 4 != 0 ? Doc->nodeEdit.m_ClRe + 3 : Doc->nodeEdit.m_ClRe - 1), np); + Clip.setPoint(indexOfNode(Doc->nodeEdit.m_ClRe, NodeType::ControlRight, Clip.size()), np); + Clip.setPoint(indexOfNode(Doc->nodeEdit.m_ClRe, NodeType::ControlLeft, Clip.size()), np); } if (!Doc->nodeEdit.m_isContourLine) { @@ -493,3 +789,7 @@ oldClip = nullptr; } +FPointArray NodeEditContext::clipFromItem(PageItem* currItem) +{ + return isContourLine() ? currItem->ContourLine : currItem->PoLine; +} Index: scribus/nodeeditcontext.h =================================================================== --- scribus/nodeeditcontext.h (Revision 26704) +++ scribus/nodeeditcontext.h (Arbeitskopie) @@ -39,6 +39,46 @@ class SCRIBUS_API NodeEditContext : public MassObservable { public: + enum SubMode + { + MOVE_POINT = 0, + ADD_POINT, + DEL_POINT, + SPLIT_PATH, + EDIT_POINT + }; + + enum NodeType + { + ControlLeft = 0, + NodeLeft, + NodeRight, + ControlRight, + Opposite, // opposite control/node index of input + Sibling, // sibling of node is control, sibling of control is node + OppositeSibling, // combination of opposite and sibling + Self + }; + + enum ControlMoveMode + { + Auto = 0, + Symmetric, + Asymmetric, + Independent + }; + + struct OppositeControl { + FPoint relativePos; + bool isValid {false}; + int controlIndex {-1}; + int nodeIndex {-1}; + double distance {0}; + double angle {0}; + bool sameAngle {false}; + bool sameLength {false}; + }; + NodeEditContext(); bool isContourLine() { return m_isContourLine; } @@ -51,17 +91,34 @@ void setSegP1(int i) { m_SegP1 = i; } int segP2() { return m_SegP2; } void setSegP2(int i) { m_SegP2 = i; } - bool edPoints() { return m_EdPoints; } - void setEdPoints(bool b) { m_EdPoints = b; } - bool moveSym() { return m_MoveSym; } - void setMoveSym(bool b) { m_MoveSym = b; } + ControlMoveMode moveMode() { return m_moveMode; } + void setMoveMode(ControlMoveMode b) { m_moveMode = b; } + double scale() { return m_scale; }; + void setScale(double scale) {m_scale = scale; } QList& selNode() { return m_SelNode; } bool hasNodeSelected() const; void deselect(); void selectNode(int i); + void deselectNode(int i); + void deselectNodeControls(); int selectionCount() const; + void getPoints(PageItem* currItem, int i, FPoint& ctrlLeft, FPoint& nodeLeft, FPoint& nodeRight, FPoint& ctrlRight); + FPoint getPoint(PageItem* currItem, int i, NodeType nodeType = NodeType::Self); + bool isSymetric(PageItem* currItem, int i = -1); + bool sameAngle(PageItem* currItem, int i = -1); + bool sameLength(PageItem* currItem, int i = -1); + + static bool isNode(int i) { return i % 2 == 0; } + static bool isLeftControl(int i); + static bool isLeftNode(int i); + static bool isRightNode(int i); + static bool isRightControl(int i); + static bool hasTwoNodes(int i, FPointArray clip); + static bool isSharpNode(int i, FPointArray clip); + static int indexOfNode(int i, NodeType type = NodeType::NodeRight, int size = -1); + void reset(); void setPreviewMode(bool mode); bool previewMode() { return m_preview; } @@ -69,17 +126,18 @@ void setSubMode(int i) { m_submode = i; } void reset1Control(PageItem* currItem); void resetControl(PageItem* currItem); + FPointArray clipFromItem(PageItem* currItem); FPointArray beginTransaction(PageItem* currItem); void finishTransaction(PageItem* currItem); ScOldNewState* finishTransaction1(PageItem* currItem); void finishTransaction2(PageItem* currItem, ScOldNewState* state); void moveClipPoint(PageItem *currItem, const FPoint& ip); + void equalizeControls(PageItem *currItem); FPointArray *oldClip { nullptr }; UndoTransaction nodeTransaction; + OppositeControl oppositeControl; - enum SubMode { MOVE_POINT = 0, ADD_POINT = 1, DEL_POINT = 2, SPLIT_PATH = 3 }; - protected: int m_submode { MOVE_POINT }; bool m_isContourLine { false }; @@ -88,11 +146,11 @@ int m_ClRe2 { -1 }; int m_SegP1 { -1 }; int m_SegP2 { -1 }; - bool m_EdPoints { true }; - bool m_MoveSym { false }; + ControlMoveMode m_moveMode { Auto }; QList m_SelNode; double m_oldItemX { 0.0 }; double m_oldItemY { 0.0 }; + double m_scale { 1.0 }; bool m_preview { false }; }; #endif Index: scribus/scribus.cpp =================================================================== --- scribus/scribus.cpp (Revision 26704) +++ scribus/scribus.cpp (Arbeitskopie) @@ -5825,11 +5825,11 @@ nodePalette->setDoc(doc, view); nodePalette->MoveN(); - nodePalette->HaveNode(false, false); + nodePalette->HaveNode(false); nodePalette->MoveNode->setChecked(true); nodePalette->show(); // qDebug() << "nodepalette show:" << nodePalette->geometry(); - connect(view, SIGNAL(HavePoint(bool,bool)), nodePalette, SLOT(HaveNode(bool,bool))); + connect(view, SIGNAL(HavePoint(bool)), nodePalette, SLOT(HaveNode(bool))); connect(view, SIGNAL(PolyStatus(int,uint)), nodePalette, SLOT(PolyStatus(int,uint))); doc->nodeEdit.reset(); appModeHelper->setFrameEditMode(true); @@ -5869,7 +5869,7 @@ void ScribusMainWindow::NoFrameEdit() { - disconnect(view, SIGNAL(HavePoint(bool, bool)), nodePalette, SLOT(HaveNode(bool, bool))); + disconnect(view, SIGNAL(HavePoint(bool)), nodePalette, SLOT(HaveNode(bool))); disconnect(view, SIGNAL(PolyStatus(int, uint)), nodePalette, SLOT(PolyStatus(int, uint))); actionManager->disconnectModeActions(); nodePalette->setDoc(nullptr, nullptr); Index: scribus/scribusview.cpp =================================================================== --- scribus/scribusview.cpp (Revision 26704) +++ scribus/scribusview.cpp (Arbeitskopie) @@ -1986,7 +1986,6 @@ MidButt = false; HaveSelRect = false; Magnify = false; - m_doc->nodeEdit.setEdPoints(true); DraggedGroup = false; //FIXME:av MoveGY = false; //FIXME:av MoveGX = false; Index: scribus/scribusview.h =================================================================== --- scribus/scribusview.h (Revision 26704) +++ scribus/scribusview.h (Arbeitskopie) @@ -369,7 +369,7 @@ void DelBM(PageItem *); void ChBMText(PageItem *); void LoadElem(QString, double, double, bool, bool, ScribusDoc *, ScribusView *); - void HavePoint(bool, bool); + void HavePoint(bool); void ClipPo(double, double); void PolyStatus(int, uint); void MousePos(double, double); Index: scribus/ui/nodeeditpalette.cpp =================================================================== --- scribus/ui/nodeeditpalette.cpp (Revision 26704) +++ scribus/ui/nodeeditpalette.cpp (Arbeitskopie) @@ -5,6 +5,7 @@ for which a new license (GPL+exception) is in place. */ +#include #include #include "nodeeditpalette.h" @@ -21,302 +22,109 @@ NodePalette::NodePalette( QWidget* parent) : ScrPaletteBase(parent, "nodePalette", false, Qt::WindowFlags()) { - QSize iconSize(22, 22); - QSize buttonSize(24, 24); - QSize maxButtonSize(16777215, buttonSize.height()); - QSizePolicy::Policy buttonSizePolicy = static_cast(QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag); + setupUi(this); - vboxLayout = new QVBoxLayout(this); - vboxLayout->setSpacing(6); - vboxLayout->setContentsMargins(6, 6, 6, 6); - - MoveNode = new QToolButton(this); - MoveNode->setIconSize(iconSize); - MoveNode->setMinimumSize(buttonSize); - MoveNode->setMaximumSize(maxButtonSize); - MoveNode->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); MoveNode->setCheckable(true); MoveNode->setChecked(true); - AddNode = new QToolButton(this); - AddNode->setIconSize(iconSize); - AddNode->setMinimumSize(buttonSize); - AddNode->setMaximumSize(maxButtonSize); - AddNode->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); AddNode->setEnabled(true); AddNode->setCheckable(true); - DeleteNode = new QToolButton(this); - DeleteNode->setIconSize(iconSize); - DeleteNode->setMinimumSize(buttonSize); - DeleteNode->setMaximumSize(maxButtonSize); - DeleteNode->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); DeleteNode->setEnabled(true); DeleteNode->setCheckable(true); - ResNode = new QToolButton(this); - ResNode->setIconSize(iconSize); - ResNode->setMinimumSize(buttonSize); - ResNode->setMaximumSize(maxButtonSize); - ResNode->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - ResNode->setEnabled(true); + EditControl->setCheckable(true); + EditControl->setChecked(true); - MoveControl = new QToolButton(this); - MoveControl->setIconSize(iconSize); - MoveControl->setMinimumSize(buttonSize); - MoveControl->setMaximumSize(maxButtonSize); - MoveControl->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - MoveControl->setCheckable(true); - - AsymMove = new QToolButton(this); - AsymMove->setIconSize(iconSize); - AsymMove->setMinimumSize(buttonSize); - AsymMove->setMaximumSize(maxButtonSize); - AsymMove->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - AsymMove->setEnabled(false); AsymMove->setCheckable(true); + AsymMove->setChecked(false); - SymMove = new QToolButton(this); - SymMove->setIconSize(iconSize); - SymMove->setMinimumSize(buttonSize); - SymMove->setMaximumSize(maxButtonSize); - SymMove->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - SymMove->setEnabled(false); SymMove->setCheckable(true); + SymMove->setChecked(false); - Res1Node = new QToolButton(this); - Res1Node->setIconSize(iconSize); - Res1Node->setMinimumSize(buttonSize); - Res1Node->setMaximumSize(maxButtonSize); - Res1Node->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - Res1Node->setEnabled(false); + IndependentMove->setCheckable(true); + IndependentMove->setChecked(false); - PolySplit = new QToolButton(this); PolySplit->setEnabled(false); PolySplit->setCheckable(true); - PolySplit->setIconSize(iconSize); - PolySplit->setMinimumSize(buttonSize); - PolySplit->setMaximumSize(maxButtonSize); - PolySplit->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - BezierClose = new QToolButton(this); BezierClose->setEnabled(false); - BezierClose->setIconSize(iconSize); - BezierClose->setMinimumSize(buttonSize); - BezierClose->setMaximumSize(maxButtonSize); - BezierClose->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - PolyMirrorH = new QToolButton(this); - PolyMirrorH->setIconSize(iconSize); - PolyMirrorH->setMinimumSize(buttonSize); - PolyMirrorH->setMaximumSize(maxButtonSize); - PolyMirrorH->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - - PolyMirrorV = new QToolButton(this); - PolyMirrorV->setIconSize(iconSize); - PolyMirrorV->setMinimumSize(buttonSize); - PolyMirrorV->setMaximumSize(maxButtonSize); - PolyMirrorV->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); - - PolyShearL = new QToolButton(this); - PolyShearL->setIconSize(iconSize); - PolyShearL->setMinimumSize(buttonSize); - PolyShearL->setMaximumSize(maxButtonSize); - PolyShearL->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); PolyShearL->setAutoRepeat(true); - - PolyShearR = new QToolButton(this); - PolyShearR->setIconSize(iconSize); - PolyShearR->setMinimumSize(buttonSize); - PolyShearR->setMaximumSize(maxButtonSize); - PolyShearR->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); PolyShearR->setAutoRepeat(true); - - PolyShearU = new QToolButton(this); - PolyShearU->setIconSize(iconSize); - PolyShearU->setMinimumSize(buttonSize); - PolyShearU->setMaximumSize(maxButtonSize); - PolyShearU->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); PolyShearU->setAutoRepeat(true); - - PolyShearD = new QToolButton(this); - PolyShearD->setIconSize(iconSize); - PolyShearD->setMinimumSize(buttonSize); - PolyShearD->setMaximumSize(maxButtonSize); - PolyShearD->setSizePolicy(QSizePolicy(buttonSizePolicy, QSizePolicy::Fixed)); PolyShearD->setAutoRepeat(true); - - RotateCCW = new QToolButton(this); - RotateCCW->setIconSize(iconSize); - RotateCCW->setMinimumSize(buttonSize); - RotateCCW->setMaximumSize(buttonSize); RotateCCW->setAutoRepeat(true); - - RotateCW = new QToolButton(this); - RotateCW->setIconSize(iconSize); - RotateCW->setMinimumSize(buttonSize); - RotateCW->setMaximumSize(buttonSize); RotateCW->setAutoRepeat(true); - RotVal = new QSpinBox(this); RotVal->setMinimum(1); RotVal->setMaximum(180); RotVal->setValue(1); RotVal->setSuffix( QString::fromUtf8(" °")); - Expand = new QToolButton(this); - Expand->setIconSize(iconSize); - Expand->setMinimumSize(buttonSize); - Expand->setMaximumSize(buttonSize); Expand->setAutoRepeat(true); - - Shrink = new QToolButton(this); - Shrink->setIconSize(iconSize); - Shrink->setMinimumSize(buttonSize); - Shrink->setMaximumSize(buttonSize); Shrink->setAutoRepeat(true); - scalePercentage = new QSpinBox(this); scalePercentage->setMinimum(1); scalePercentage->setMaximum(100); scalePercentage->setValue(10); - Enlarge = new QToolButton(this); - Enlarge->setIconSize(iconSize); - Enlarge->setMinimumSize(buttonSize); - Enlarge->setMaximumSize(buttonSize); Enlarge->setAutoRepeat(true); - - Reduce = new QToolButton(this); - Reduce->setIconSize(iconSize); - Reduce->setMinimumSize(buttonSize); - Reduce->setMaximumSize(buttonSize); Reduce->setAutoRepeat(true); - scaleDistance = new ScrSpinBox( 1, 16777215, this, 0); - scaleDistance->setMaximumSize(114, 16777215); // ScrSpinBox is bigger for 4px than expected + scaleDistance->setMaximumSize(114, 16777215); scaleDistance->setValues(-16777215, 16777215, 2, 30); - gridLayout = new QGridLayout(); - gridLayout->setSpacing(6); - gridLayout->setContentsMargins(0, 0, 0, 0); - gridLayout->addWidget(MoveNode, 0, 1, 1, 1); - gridLayout->addWidget(AddNode, 0, 2, 1, 1); - gridLayout->addWidget(DeleteNode, 0, 3, 1, 1); - gridLayout->addWidget(ResNode, 0, 4, 1, 1); - gridLayout->addWidget(MoveControl, 1, 1, 1, 1); - gridLayout->addWidget(AsymMove, 1, 2, 1, 1); - gridLayout->addWidget(SymMove, 1, 3, 1, 1); - gridLayout->addWidget(Res1Node, 1, 4, 1, 1); - gridLayout->addWidget(PolySplit, 2, 1, 1, 1); - gridLayout->addWidget(BezierClose, 2, 2, 1, 1); - gridLayout->addWidget(PolyMirrorH, 2, 3, 1, 1); - gridLayout->addWidget(PolyMirrorV, 2, 4, 1, 1); - gridLayout->addWidget(PolyShearL, 3, 1, 1, 1); - gridLayout->addWidget(PolyShearR, 3, 2, 1, 1); - gridLayout->addWidget(PolyShearU, 3, 3, 1, 1); - gridLayout->addWidget(PolyShearD, 3, 4, 1, 1); - vboxLayout->addLayout(gridLayout); - - gridLayout2 = new QGridLayout(); - gridLayout2->setSpacing(6); - gridLayout2->setContentsMargins(0, 0, 0, 0); - gridLayout2->addWidget(RotVal, 0, 0, 1, 4); - gridLayout2->addWidget(RotateCCW, 0, 4, 1, 1); - gridLayout2->addWidget(RotateCW, 0, 5, 1, 1); - gridLayout2->addWidget(scalePercentage, 1, 0, 1, 4); - gridLayout2->addWidget(Expand, 1, 4, 1, 1); - gridLayout2->addWidget(Shrink, 1, 5, 1, 1); - gridLayout2->addWidget(scaleDistance, 2, 0, 1, 4); - gridLayout2->addWidget(Enlarge, 2, 4, 1, 1); - gridLayout2->addWidget(Reduce, 2, 5, 1, 1); - vboxLayout->addLayout(gridLayout2); - - QSpacerItem* spacer = new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed ); - vboxLayout->addItem(spacer); - - AbsMode = new QGroupBox( "&Absolute Coordinates", this ); - AbsMode->setCheckable(true); - AbsMode->setChecked(false); - vboxLayout1 = new QVBoxLayout(AbsMode); - vboxLayout1->setSpacing(6); - vboxLayout1->setContentsMargins(9, 9, 9, 9); - absToCanvas = new QRadioButton( tr("to Canvas"), AbsMode); - vboxLayout1->addWidget(absToCanvas); - absToPage = new QRadioButton( tr("to Page"), AbsMode); - vboxLayout1->addWidget(absToPage); - absToCanvas->setChecked(true); - vboxLayout->addWidget(AbsMode); - - gridLayout3 = new QGridLayout(); - gridLayout3->setSpacing(6); - gridLayout3->setContentsMargins(0, 0, 0, 0); - gridLayout3->setColumnStretch(0, 0); - gridLayout3->setColumnStretch(1, 1); - - TextLabel1 = new QLabel(this); - gridLayout3->addWidget(TextLabel1, 0, 0, 1, 1); - - XSpin = new ScrSpinBox( 0, 16777215, this, 2 ); + XSpin->setMinimum(0); + XSpin->setMaximum(16777215); + XSpin->setNewUnit(2); XSpin->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed)); XSpin->setEnabled(false); - gridLayout3->addWidget(XSpin, 0, 1, 1, 1); - TextLabel2 = new QLabel(this); - gridLayout3->addWidget(TextLabel2, 1, 0, 1, 1); - - YSpin = new ScrSpinBox( 0, 16777215, this, 2 ); + YSpin->setMinimum(0); + YSpin->setMaximum(16777215); + YSpin->setNewUnit(2); YSpin->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed)); YSpin->setEnabled(false); - gridLayout3->addWidget(YSpin, 1, 1, 1, 1); - vboxLayout->addLayout(gridLayout3); TextLabel1->setBuddy(XSpin); TextLabel2->setBuddy(YSpin); - EditCont = new QCheckBox(this); EditCont->setChecked(false); - vboxLayout->addWidget(EditCont); - PreviewMode = new QCheckBox(this); PreviewMode->setChecked(false); - vboxLayout->addWidget(PreviewMode); - ResetCont = new QPushButton(this); ResetCont->setEnabled(false); - vboxLayout->addWidget(ResetCont); - ResetContClip = new QPushButton(this); ResetContClip->setEnabled(true); ResetContClip->hide(); - vboxLayout->addWidget(ResetContClip); - ResetShape2Clip = new QPushButton(this); ResetShape2Clip->setEnabled(true); ResetShape2Clip->hide(); - vboxLayout->addWidget(ResetShape2Clip); - resetDefaultButton = new QPushButton(this); resetDefaultButton->setEnabled(true); - vboxLayout->addWidget(resetDefaultButton); - hboxLayout = new QHBoxLayout(); - hboxLayout->setSpacing(6); - hboxLayout->setContentsMargins(0, 0, 0, 0); - editEditButton = new QPushButton(IconManager::instance().loadIcon("exit"), tr("OK"), this); editEditButton->setEnabled(true); editEditButton->setDefault(true); - hboxLayout->addWidget(editEditButton); - cancelEditButton = new QPushButton( tr("Cancel"), this); + cancelEditButton->setEnabled(true); - hboxLayout->addWidget(cancelEditButton); - vboxLayout->addLayout(hboxLayout); + QButtonGroup *btngpTools = new QButtonGroup(); + btngpTools->setExclusive(true); + btngpTools->addButton(MoveNode); + btngpTools->addButton(AddNode); + btngpTools->addButton(DeleteNode); + btngpTools->addButton(PolySplit); + btngpTools->addButton(BezierClose); + btngpTools->addButton(EditControl); + resize(QSize(170, 380).expandedTo(minimumSizeHint())); layout()->setSizeConstraint(QLayout::SetFixedSize); iconSetChange(); languageChange(); + PosOriginButton->setCurrentIndex(m_posOrigin); + connect(ScQApp, SIGNAL(iconSetChanged()), this, SLOT(iconSetChange())); } @@ -331,11 +139,10 @@ connect(MoveNode, SIGNAL(clicked()), this, SLOT(MoveN())); connect(AsymMove, SIGNAL(clicked()), this, SLOT(SetAsym())); connect(SymMove, SIGNAL(clicked()), this, SLOT(SetSym())); - connect(ResNode, SIGNAL(clicked()), this, SLOT(ResetControl())); - connect(Res1Node, SIGNAL(clicked()), this, SLOT(Reset1Control())); + connect(IndependentMove, SIGNAL(clicked()), this, SLOT(SetIndependentMove())); + connect(EditControl, SIGNAL(clicked()), this, SLOT(editControl())); connect(BezierClose, SIGNAL(clicked()), this, SLOT(CloseBezier())); connect(PolySplit, SIGNAL(clicked()), this, SLOT(SplitPoly())); - connect(MoveControl, SIGNAL(clicked()), this, SLOT(MoveK())); connect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); connect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); connect(PolyMirrorH, SIGNAL(clicked()), this, SLOT(MirrorH())); @@ -350,14 +157,12 @@ connect(Expand, SIGNAL(clicked()), this, SLOT(doExpand())); connect(Reduce, SIGNAL(clicked()), this, SLOT(doReduce())); connect(Enlarge, SIGNAL(clicked()), this, SLOT(doEnlarge())); - connect(AbsMode, SIGNAL(clicked()), this, SLOT(ToggleAbsMode())); - connect(absToCanvas, SIGNAL(clicked()), this, SLOT(ToggleAbsMode())); - connect(absToPage, SIGNAL(clicked()), this, SLOT(ToggleAbsMode())); - connect(EditCont, SIGNAL(clicked()), this, SLOT(ToggleConMode())); + connect(EditCont, SIGNAL(clicked()), this, SLOT(ToggleContourMode())); connect(ResetCont, SIGNAL(clicked()), this, SLOT(ResetContour())); connect(ResetContClip, SIGNAL(clicked()), this, SLOT(ResetContourToImageClip())); connect(ResetShape2Clip, SIGNAL(clicked()), this, SLOT(ResetShapeToImageClip())); connect(PreviewMode, SIGNAL(clicked()), this, SLOT(TogglePreview())); + connect(PosOriginButton, SIGNAL(currentIndexChanged(int)), this, SLOT(changePosOrigin(int))); } void NodePalette::disconnectSignals() @@ -371,11 +176,10 @@ disconnect(MoveNode, SIGNAL(clicked()), this, SLOT(MoveN())); disconnect(AsymMove, SIGNAL(clicked()), this, SLOT(SetAsym())); disconnect(SymMove, SIGNAL(clicked()), this, SLOT(SetSym())); - disconnect(ResNode, SIGNAL(clicked()), this, SLOT(ResetControl())); - disconnect(Res1Node, SIGNAL(clicked()), this, SLOT(Reset1Control())); + disconnect(IndependentMove, SIGNAL(clicked()), this, SLOT(SetIndependentMove())); + disconnect(EditControl, SIGNAL(clicked()), this, SLOT(editControl())); disconnect(BezierClose, SIGNAL(clicked()), this, SLOT(CloseBezier())); disconnect(PolySplit, SIGNAL(clicked()), this, SLOT(SplitPoly())); - disconnect(MoveControl, SIGNAL(clicked()), this, SLOT(MoveK())); disconnect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); disconnect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); disconnect(PolyMirrorH, SIGNAL(clicked()), this, SLOT(MirrorH())); @@ -394,8 +198,25 @@ disconnect(ResetContClip, SIGNAL(clicked()), this, SLOT(ResetContourToImageClip())); disconnect(ResetShape2Clip, SIGNAL(clicked()), this, SLOT(ResetShapeToImageClip())); disconnect(PreviewMode, SIGNAL(clicked()), this, SLOT(TogglePreview())); + disconnect(PosOriginButton, SIGNAL(currentIndexChanged(int)), this, SLOT(changePosOrigin(int))); } +void NodePalette::initPosOriginMenu() +{ + IconManager& im = IconManager::instance(); + QSignalBlocker sigPosOriginButton(PosOriginButton); + + int index = PosOriginButton->currentIndex(); + + PosOriginButton->clear(); + PosOriginButton->addAction(im.loadIcon("position-origin-canvas"), tr("Canvas"))->setData(PositionOrigin::Canvas); + PosOriginButton->addAction(im.loadIcon("position-origin-page"), tr("Page"))->setData(PositionOrigin::Page); + PosOriginButton->addAction(im.loadIcon("position-origin-item"), tr("Item"))->setData(PositionOrigin::Item); + + PosOriginButton->setCurrentIndex(index); + +} + void NodePalette::setDoc(ScribusDoc *dc, ScribusView *vi) { m_doc = dc; @@ -402,14 +223,15 @@ m_view = vi; unitChange(); - disconnect(EditCont, SIGNAL(clicked()), this, SLOT(ToggleConMode())); - disconnect(AbsMode, SIGNAL(clicked()), this, SLOT(ToggleAbsMode())); + disconnect(EditCont, SIGNAL(clicked()), this, SLOT(ToggleContourMode())); + disconnect(PosOriginButton, SIGNAL(currentIndexChanged(int)), this, SLOT(changePosOrigin(int))); if (m_doc != nullptr) { YSpin->setNewUnit(m_doc->unitIndex()); XSpin->setNewUnit(m_doc->unitIndex()); } - AbsMode->setChecked(false); + PosOriginButton->setCurrentIndex(Page); + EditCont->setChecked(false); if (m_doc == nullptr) disconnectSignals(); @@ -417,20 +239,11 @@ connectSignals(); } -void NodePalette::SplitPoly() -{ - if (m_doc == nullptr) - return; - MoveN(); - m_doc->nodeEdit.setSubMode(NodeEditContext::SPLIT_PATH); - PolySplit->setChecked(true); -} - void NodePalette::IsOpen() { if (m_doc == nullptr) return; - PolySplit->setChecked(false); + MoveNode->setChecked(true); BezierClose->setEnabled(true); PolySplit->setEnabled(true); EditCont->setEnabled(false); @@ -459,21 +272,6 @@ } } -void NodePalette::CloseBezier() -{ - if (m_doc == nullptr) - return; - MoveN(); - PageItem *currItem = m_doc->m_Selection->itemAt(0); - PageItem* newItem = m_doc->convertItemTo(currItem, PageItem::Polygon); - m_doc->m_Selection->clear(); - m_doc->m_Selection->addItem(newItem); - newItem->update(); - BezierClose->setEnabled(false); - PolySplit->setEnabled(true); - EditCont->setEnabled(true); -} - void NodePalette::doRotCCW() { if (m_doc == nullptr) @@ -558,20 +356,6 @@ m_doc->MirrorPolyV(m_doc->m_Selection->itemAt(0)); } -void NodePalette::ResetControl() -{ - if (m_doc == nullptr) - return; - m_doc->nodeEdit.resetControl(m_doc->m_Selection->itemAt(0)); -} - -void NodePalette::Reset1Control() -{ - if (m_doc == nullptr) - return; - m_doc->nodeEdit.reset1Control(m_doc->m_Selection->itemAt(0)); -} - void NodePalette::ResetContour() { if (m_doc == nullptr) @@ -629,9 +413,9 @@ PageItem *currItem = m_doc->m_Selection->itemAt(0); FPoint zp; FPoint np(XSpin->value() / m_doc->unitRatio(), YSpin->value() / m_doc->unitRatio()); - if (AbsMode->isChecked()) + if (m_posOrigin == Canvas || m_posOrigin == Page) { - if (absToCanvas->isChecked()) + if (m_posOrigin == Canvas) zp = FPoint(currItem->xPos(), currItem->yPos()); else zp = FPoint(currItem->xPos() - m_doc->currentPage()->xOffset(), currItem->yPos() - m_doc->currentPage()->yOffset()); @@ -648,43 +432,50 @@ void NodePalette::SetSym() { - if (m_doc != nullptr) - m_doc->nodeEdit.setMoveSym(true); - SymMove->setChecked(true); AsymMove->setChecked(false); + IndependentMove->setChecked(false); PolySplit->setChecked(false); + + if (m_doc == nullptr) + return; + + if (SymMove->isChecked()) + m_doc->nodeEdit.setMoveMode(NodeEditContext::Symmetric); + else + m_doc->nodeEdit.setMoveMode(NodeEditContext::Auto); } void NodePalette::SetAsym() { - if (m_doc != nullptr) - m_doc->nodeEdit.setMoveSym(false); SymMove->setChecked(false); - AsymMove->setChecked(true); + IndependentMove->setChecked(false); PolySplit->setChecked(false); + + if (m_doc == nullptr) + return; + + if (AsymMove->isChecked()) + m_doc->nodeEdit.setMoveMode(NodeEditContext::Asymmetric); + else + m_doc->nodeEdit.setMoveMode(NodeEditContext::Auto); } -void NodePalette::SetXY(double x, double y) +void NodePalette::SetIndependentMove() { + SymMove->setChecked(false); + AsymMove->setChecked(false); + PolySplit->setChecked(false); + if (m_doc == nullptr) return; - FPoint zp(0.0, 0.0); - disconnect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); - disconnect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); - if (AbsMode->isChecked()) - { - if (absToCanvas->isChecked()) - zp = FPoint(m_doc->m_Selection->itemAt(0)->xPos(), m_doc->m_Selection->itemAt(0)->yPos()); - else - zp = FPoint(m_doc->m_Selection->itemAt(0)->xPos() - m_doc->currentPage()->xOffset(), m_doc->m_Selection->itemAt(0)->yPos() - m_doc->currentPage()->yOffset()); - } - XSpin->setValue((x + zp.x()) * m_doc->unitRatio()); - YSpin->setValue((y + zp.y()) * m_doc->unitRatio()); - connect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); - connect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); + + if (IndependentMove->isChecked()) + m_doc->nodeEdit.setMoveMode(NodeEditContext::Independent); + else + m_doc->nodeEdit.setMoveMode(NodeEditContext::Auto); } -void NodePalette::ToggleAbsMode() +void NodePalette::SetXY(double x, double y) { if (m_doc == nullptr) return; @@ -691,35 +482,19 @@ FPoint zp(0.0, 0.0); disconnect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); disconnect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); - FPointArray Clip; - FPoint np(0.0, 0.0); - if (EditCont->isChecked()) - Clip = m_doc->m_Selection->itemAt(0)->ContourLine; - else - Clip = m_doc->m_Selection->itemAt(0)->PoLine; - if (m_doc->nodeEdit.selectionCount() != 0) - np = Clip.point(m_doc->nodeEdit.selNode().at(0)); - if (AbsMode->isChecked()) - { - XSpin->setMinimum(-16777215); - YSpin->setMinimum(-16777215); - if (absToCanvas->isChecked()) - zp = FPoint(m_doc->m_Selection->itemAt(0)->xPos(), m_doc->m_Selection->itemAt(0)->yPos()); - else - zp = FPoint(m_doc->m_Selection->itemAt(0)->xPos() - m_doc->currentPage()->xOffset(), m_doc->m_Selection->itemAt(0)->yPos() - m_doc->currentPage()->yOffset()); - } - else - { - XSpin->setMinimum(0); - YSpin->setMinimum(0); - } - XSpin->setValue((np.x() + zp.x()) * m_doc->unitRatio()); - YSpin->setValue((np.y() + zp.y()) * m_doc->unitRatio()); + + if (PosOriginButton->currentIndex() == Page) + zp = FPoint(m_doc->m_Selection->itemAt(0)->xPos() - m_doc->currentPage()->xOffset(), m_doc->m_Selection->itemAt(0)->yPos() - m_doc->currentPage()->yOffset()); + else if (PosOriginButton->currentIndex() == Canvas) + zp = FPoint(m_doc->m_Selection->itemAt(0)->xPos(), m_doc->m_Selection->itemAt(0)->yPos()); + + XSpin->setValue((x + zp.x()) * m_doc->unitRatio()); + YSpin->setValue((y + zp.y()) * m_doc->unitRatio()); connect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); connect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); } -void NodePalette::ToggleConMode() +void NodePalette::ToggleContourMode() { if (m_doc == nullptr) return; @@ -748,7 +523,7 @@ PolySplit->setEnabled(true); ResetCont->setEnabled(false); ResetContClip->setEnabled(false); - if (AbsMode->isChecked()) + if (m_posOrigin == Canvas | m_posOrigin == Page) { XSpin->setMinimum(-16777215); YSpin->setMinimum(-16777215); @@ -773,10 +548,52 @@ m_doc->regionsChanged()->update(QRectF()); } -void NodePalette::HaveNode(bool have, bool mov) +void NodePalette::changePosOrigin(int index) { + m_posOrigin = index; + if (m_doc == nullptr) return; + + FPoint zp(0.0, 0.0); + disconnect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); + disconnect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); + FPointArray Clip; + FPoint np(0.0, 0.0); + + if (EditCont->isChecked()) + Clip = m_doc->m_Selection->itemAt(0)->ContourLine; + else + Clip = m_doc->m_Selection->itemAt(0)->PoLine; + + if (m_doc->nodeEdit.selectionCount() != 0) + np = Clip.point(m_doc->nodeEdit.selNode().at(0)); + + if (m_posOrigin == Canvas || m_posOrigin == Page) + { + XSpin->setMinimum(-16777215); + YSpin->setMinimum(-16777215); + if (m_posOrigin == Canvas) + zp = FPoint(m_doc->m_Selection->itemAt(0)->xPos(), m_doc->m_Selection->itemAt(0)->yPos()); + else + zp = FPoint(m_doc->m_Selection->itemAt(0)->xPos() - m_doc->currentPage()->xOffset(), m_doc->m_Selection->itemAt(0)->yPos() - m_doc->currentPage()->yOffset()); + } + else + { + XSpin->setMinimum(0); + YSpin->setMinimum(0); + } + + XSpin->setValue((np.x() + zp.x()) * m_doc->unitRatio()); + YSpin->setValue((np.y() + zp.y()) * m_doc->unitRatio()); + connect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); + connect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(MovePoint())); +} + +void NodePalette::HaveNode(bool have) +{ + if (m_doc == nullptr) + return; bool setter = have; if (m_doc->nodeEdit.selectionCount() > 1) { @@ -788,35 +605,7 @@ XSpin->setEnabled(setter); YSpin->setEnabled(setter); } - if (setter) - { - if (m_doc->nodeEdit.edPoints()) - ResNode->setEnabled(setter); - else - Res1Node->setEnabled(setter); - } - else - { - ResNode->setEnabled(setter); - Res1Node->setEnabled(setter); - } - if (m_doc->nodeEdit.submode() == NodeEditContext::MOVE_POINT) - { - disconnect(AsymMove, SIGNAL(clicked()), this, SLOT(SetAsym())); - disconnect(SymMove, SIGNAL(clicked()), this, SLOT(SetSym())); - if (mov) - { - SymMove->setChecked(true); - AsymMove->setChecked(false); - } - else - { - AsymMove->setChecked(true); - SymMove->setChecked(false); - } - connect(AsymMove, SIGNAL(clicked()), this, SLOT(SetAsym())); - connect(SymMove, SIGNAL(clicked()), this, SLOT(SetSym())); - } + if (m_doc->nodeEdit.submode() == NodeEditContext::DEL_POINT) { uint cc; @@ -837,91 +626,106 @@ leaveEd = true; } if (leaveEd) - { MoveN(); - MoveControl->setEnabled(true); - } } } -void NodePalette::MoveK() +void NodePalette::MoveN() { if (m_doc == nullptr) return; + m_doc->nodeEdit.setSubMode(NodeEditContext::MOVE_POINT); - m_doc->nodeEdit.setEdPoints(false); m_doc->nodeEdit.setClre(-1); m_doc->nodeEdit.setClre2(-1); m_doc->nodeEdit.setSegP1(-1); m_doc->nodeEdit.setSegP2(-1); + if (m_doc->m_Selection->count() > 0) m_doc->m_Selection->itemAt(0)->update(); + SymMove->setEnabled(true); AsymMove->setEnabled(true); - Res1Node->setEnabled(false); - ResNode->setEnabled(false); - AddNode->setEnabled(false); - DeleteNode->setEnabled(false); - MoveNode->setChecked(false); - MoveControl->setChecked(true); - DeleteNode->setChecked(false); - AddNode->setChecked(false); - PolySplit->setChecked(false); + IndependentMove->setEnabled(true); + MoveNode->setChecked(true); } -void NodePalette::MoveN() +void NodePalette::AddN() { if (m_doc == nullptr) return; - m_doc->nodeEdit.setSubMode(NodeEditContext::MOVE_POINT); - m_doc->nodeEdit.setEdPoints(true); + + m_doc->nodeEdit.setSubMode(NodeEditContext::ADD_POINT); + SymMove->setEnabled(false); + AsymMove->setEnabled(false); + IndependentMove->setEnabled(false); + AddNode->setChecked(true); +} + +void NodePalette::DelN() +{ + if (m_doc == nullptr) + return; + + m_doc->nodeEdit.setSubMode(NodeEditContext::DEL_POINT); + SymMove->setEnabled(false); + AsymMove->setEnabled(false); + IndependentMove->setEnabled(false); + DeleteNode->setChecked(true); +} + +void NodePalette::SplitPoly() +{ + if (m_doc == nullptr) + return; + + m_doc->nodeEdit.setSubMode(NodeEditContext::SPLIT_PATH); m_doc->nodeEdit.setClre(-1); m_doc->nodeEdit.setClre2(-1); m_doc->nodeEdit.setSegP1(-1); m_doc->nodeEdit.setSegP2(-1); + if (m_doc->m_Selection->count() > 0) m_doc->m_Selection->itemAt(0)->update(); - ResNode->setEnabled(false); - AddNode->setEnabled(true); - DeleteNode->setEnabled(true); + SymMove->setEnabled(false); AsymMove->setEnabled(false); - Res1Node->setEnabled(false); - MoveNode->setChecked(true); - MoveControl->setChecked(false); - DeleteNode->setChecked(false); - AddNode->setChecked(false); - PolySplit->setChecked(false); + IndependentMove->setEnabled(false); + PolySplit->setChecked(true); } -void NodePalette::AddN() +void NodePalette::editControl() { if (m_doc == nullptr) return; - m_doc->nodeEdit.setSubMode(NodeEditContext::ADD_POINT); - m_doc->nodeEdit.setEdPoints(true); + + m_doc->nodeEdit.setSubMode(NodeEditContext::EDIT_POINT); + m_doc->nodeEdit.setClre(-1); + m_doc->nodeEdit.setClre2(-1); + m_doc->nodeEdit.setSegP1(-1); + m_doc->nodeEdit.setSegP2(-1); + SymMove->setEnabled(false); AsymMove->setEnabled(false); - ResNode->setEnabled(false); - Res1Node->setEnabled(false); - AddNode->setChecked(true); - DeleteNode->setChecked(false); - PolySplit->setChecked(false); + IndependentMove->setEnabled(false); + EditControl->setChecked(true); + } -void NodePalette::DelN() +void NodePalette::CloseBezier() { if (m_doc == nullptr) return; - m_doc->nodeEdit.setSubMode(NodeEditContext::DEL_POINT); - m_doc->nodeEdit.setEdPoints(true); - SymMove->setEnabled(false); - AsymMove->setEnabled(false); - ResNode->setEnabled(false); - Res1Node->setEnabled(false); - AddNode->setChecked(false); - DeleteNode->setChecked(true); - PolySplit->setChecked(false); + + MoveN(); + PageItem *currItem = m_doc->m_Selection->itemAt(0); + PageItem* newItem = m_doc->convertItemTo(currItem, PageItem::Polygon); + m_doc->m_Selection->clear(); + m_doc->m_Selection->addItem(newItem); + newItem->update(); + BezierClose->setEnabled(false); + PolySplit->setEnabled(true); + EditCont->setEnabled(true); } void NodePalette::closeEvent(QCloseEvent *ce) @@ -956,7 +760,7 @@ m_doc->nodeEdit.selNode().clear(); m_doc->nodeEdit.setPreviewMode(false); EditCont->setChecked(false); - ToggleConMode(); + ToggleContourMode(); PageItem *currItem = m_doc->m_Selection->itemAt(0); if (currItem && currItem->itemType() == PageItem::PathText) currItem->updatePolyClip(); @@ -979,7 +783,7 @@ m_doc->nodeEdit.selNode().clear(); m_doc->nodeEdit.setPreviewMode(false); EditCont->setChecked(false); - ToggleConMode(); + ToggleContourMode(); PageItem *currItem = m_doc->m_Selection->itemAt(0); // Calculate the difference of the current position and the original @@ -1069,14 +873,16 @@ { IconManager& im = IconManager::instance(); +//<<<<<<< .mine + initPosOriginMenu(); + MoveNode->setIcon(im.loadIcon("bezier-node-move")); AddNode->setIcon(im.loadIcon("bezier-node-add")); DeleteNode->setIcon(im.loadIcon("bezier-node-delete")); - ResNode->setIcon(im.loadIcon("bezier-control-reset-all")); - MoveControl->setIcon(im.loadIcon("bezier-control-move")); AsymMove->setIcon(im.loadIcon("bezier-control-asymetric")); SymMove->setIcon(im.loadIcon("bezier-control-symetric")); - Res1Node->setIcon(im.loadIcon("bezier-control-reset")); + IndependentMove->setIcon(im.loadIcon("bezier-control-independent")); + EditControl->setIcon(im.loadIcon("bezier-node-edit")); PolySplit->setIcon(im.loadIcon("bezier-split")); BezierClose->setIcon(im.loadIcon("bezier-close")); PolyMirrorH->setIcon(im.loadIcon("object-flip-horizontal")); @@ -1091,6 +897,13 @@ Shrink->setIcon(im.loadIcon("bezier-scale-down")); Enlarge->setIcon(im.loadIcon("bezier-scale-up")); Reduce->setIcon(im.loadIcon("bezier-scale-down")); + + EditCont->setIcon(im.loadIcon("path-contour-edit")); + PreviewMode->setIcon(im.loadIcon("path-node-visibility")); + ResetContClip->setIcon(im.loadIcon("path-contour-to-clip")); + ResetShape2Clip->setIcon(im.loadIcon("path-shape-to-clip")); + ResetCont->setIcon(im.loadIcon("path-contour-reset")); + resetDefaultButton->setIcon(im.loadIcon("path-reset-all")); } void NodePalette::languageChange() @@ -1098,28 +911,21 @@ setWindowTitle( tr( "Nodes" ) ); scalePercentage->setSuffix( tr(" %")); - AbsMode->setTitle( tr("&Absolute Coordinates")); - absToCanvas->setText( tr("to Canvas")); - absToPage->setText( tr("to Page")); - TextLabel1->setText( tr("&X-Pos:")); - TextLabel2->setText( tr("&Y-Pos:")); - PreviewMode->setText( tr("Hide Nodes")); - EditCont->setText( tr("Edit &Contour Line")); - ResetCont->setText( tr("&Reset Contour Line")); - ResetContClip->setText( tr("Set Contour to Image Clip")); - ResetShape2Clip->setText( tr("Set Shape to Image Clip")); + initPosOriginMenu(); + + PosOriginLabel->setText( tr("Origin:")); + TextLabel1->setText( tr("&X:")); + TextLabel2->setText( tr("&Y:")); editEditButton->setText( tr("OK")); cancelEditButton->setText( tr("Cancel")); - resetDefaultButton->setText( tr("Reset all edits")); -// editEditButton->setText( tr("&End Editing")); + resetDefaultButton->setToolTip( tr("Reset all edits")); MoveNode->setToolTip( tr("Move Nodes")); - MoveControl->setToolTip( tr("Move Control Points")); AddNode->setToolTip( tr("Add Nodes")); DeleteNode->setToolTip( tr("Delete Nodes")); - AsymMove->setToolTip( tr("Move Control Points Independently")); + AsymMove->setToolTip( tr("Move Control Points Asymetrical")); SymMove->setToolTip( tr("Move Control Points Symmetrical")); - ResNode->setToolTip( tr("Reset Control Points")); - Res1Node->setToolTip( tr("Reset this Control Point")); + IndependentMove->setToolTip( tr("Move Control Points Independently")); + EditControl->setToolTip( tr("Edit Control Points")); PolySplit->setToolTip( tr("Open a Polygon or Cuts a Bezier Curve")); BezierClose->setToolTip( tr("Close this Bezier Curve")); PolyMirrorH->setToolTip( tr("Mirror the Path Horizontally")); @@ -1137,11 +943,12 @@ RotVal->setToolTip( tr("Angle of Rotation")); scalePercentage->setToolTip( tr("% to Enlarge or Shrink By")); scaleDistance->setToolTip( tr("Value to Enlarge or Shrink By")); + PreviewMode->setToolTip( tr("Hide Nodes")); EditCont->setToolTip( tr("Activate Contour Line Editing Mode")); ResetCont->setToolTip( tr("Reset the Contour Line to the Original Shape of the Frame")); ResetContClip->setToolTip( tr("Reset the Contour Line to the Clipping Path of the Image")); ResetShape2Clip->setToolTip( tr("Set the Shape to the Clipping Path of the Image")); - AbsMode->setToolTip( "" + tr("When checked use coordinates relative to the page, otherwise coordinates are relative to the Object") + ""); + PosOriginButton->setToolTip( "" + tr("Use coordinates relative to the canvas, page, or to the Object") + ""); } void NodePalette::unitChange() Index: scribus/ui/nodeeditpalette.h =================================================================== --- scribus/ui/nodeeditpalette.h (Revision 26704) +++ scribus/ui/nodeeditpalette.h (Arbeitskopie) @@ -25,13 +25,13 @@ #include "scribusapi.h" #include "fpointarray.h" #include "scrpalettebase.h" -#include "scrspinbox.h" +#include "ui_nodeeditpalette.h" class ScribusDoc; class ScribusView; class PageItem; -class SCRIBUS_API NodePalette : public ScrPaletteBase +class SCRIBUS_API NodePalette : public ScrPaletteBase, public Ui::nodePalette { Q_OBJECT @@ -40,60 +40,19 @@ ~NodePalette() {}; void setDefaults(PageItem* currItem); - - QToolButton* MoveNode { nullptr }; - QToolButton* MoveControl { nullptr }; - QToolButton* AddNode { nullptr }; - QToolButton* DeleteNode { nullptr }; - QToolButton* AsymMove { nullptr }; - QToolButton* SymMove { nullptr }; - QToolButton* ResNode { nullptr }; - QToolButton* Res1Node { nullptr }; - QToolButton* PolySplit { nullptr }; - QToolButton* BezierClose { nullptr }; - QToolButton* PolyMirrorH { nullptr }; - QToolButton* PolyMirrorV { nullptr }; - QToolButton* PolyShearL { nullptr }; - QToolButton* PolyShearR { nullptr }; - QToolButton* PolyShearU { nullptr }; - QToolButton* PolyShearD { nullptr }; - QToolButton* RotateCCW { nullptr }; - QToolButton* RotateCW { nullptr }; - QToolButton* Expand { nullptr }; - QToolButton* Shrink { nullptr }; - QToolButton* Enlarge { nullptr }; - QToolButton* Reduce { nullptr }; - QCheckBox* PreviewMode { nullptr }; - QGroupBox* AbsMode { nullptr }; - QRadioButton* absToCanvas { nullptr }; - QRadioButton* absToPage { nullptr }; - QCheckBox* EditCont { nullptr }; - QLabel* TextLabel1 { nullptr }; - ScrSpinBox* YSpin { nullptr }; - QLabel* TextLabel2 { nullptr }; - ScrSpinBox* XSpin { nullptr }; - QSpinBox *RotVal { nullptr }; - QSpinBox *scalePercentage { nullptr }; - ScrSpinBox *scaleDistance { nullptr }; - QPushButton* ResetCont { nullptr }; - QPushButton* ResetContClip { nullptr }; - QPushButton* ResetShape2Clip { nullptr }; - QPushButton* editEditButton { nullptr }; - QPushButton* cancelEditButton { nullptr }; - QPushButton* resetDefaultButton { nullptr }; - void setDoc(ScribusDoc *dc, ScribusView *vi); ScribusDoc* currentDocument() const; + bool isSymetricMove() { return SymMove->isChecked(); }; + private slots: - void MoveK(); void AddN(); void DelN(); void MovePoint(); void SetSym(); void SetAsym(); - void ResetControl(); - void Reset1Control(); + void SetIndependentMove(); + void editControl(); void ResetContour(); void ResetContourToImageClip(); void ResetShapeToImageClip(); @@ -111,14 +70,14 @@ void ShearL(); void ShearU(); void ShearD(); - void ToggleAbsMode(); - void ToggleConMode(); + void ToggleContourMode(); void TogglePreview(); + void changePosOrigin(int index); public slots: void MoveN(); void SetXY(double x, double y); - void HaveNode(bool have, bool mov); + void HaveNode(bool have); void IsOpen(); void PolyStatus(int typ, uint size); void iconSetChange(); @@ -132,19 +91,21 @@ void reject() override; protected: + + enum PositionOrigin { + Canvas = 0, + Page, + Item + }; + void connectSignals(); void disconnectSignals(); + void initPosOriginMenu(); + void changeEvent(QEvent *e) override; void closeEvent(QCloseEvent *) override; - QVBoxLayout *vboxLayout { nullptr }; - QVBoxLayout *vboxLayout1 { nullptr }; - QHBoxLayout *hboxLayout { nullptr }; - QGridLayout *gridLayout { nullptr }; - QGridLayout *gridLayout2 { nullptr }; - QGridLayout *gridLayout3 { nullptr }; - ScribusDoc *m_doc { nullptr }; ScribusView *m_view { nullptr }; @@ -153,6 +114,7 @@ double m_yPos { 0.0 }; FPointArray m_itemPath; FPointArray m_itemContourPath; + int m_posOrigin { Page }; signals: void DocChanged(); Index: scribus/util_math.h =================================================================== --- scribus/util_math.h (Revision 26704) +++ scribus/util_math.h (Arbeitskopie) @@ -19,6 +19,7 @@ #include #include +#include "fpoint.h" #include "scribusapi.h" class FPoint; @@ -42,7 +43,7 @@ * @param t * @return */ -QList catmullToBezier(const QList& inputPoints, double t = 1); +QList SCRIBUS_API catmullToBezier(const QList& inputPoints, double t = 1); QPainterPath SCRIBUS_API regularPolygonPath(double w, double h, uint c, bool star, double factor, double rota, double factor2 = 0.0, double innerRot = 0.0, double factor3 = 0.0); QPainterPath SCRIBUS_API spiralPath(double spiralWidth, double spiralHeight, double spiralStartAngle, double spiralEndAngle, double spiralFactor); inline double SCRIBUS_API xy2Deg(double x, double y); @@ -51,6 +52,7 @@ inline double SCRIBUS_API square(double); inline double SCRIBUS_API distance(double, double); inline double SCRIBUS_API manhattanDistance(const QPointF& p1, const QPointF& p2); + /*! \brief Constrains an angle of rotation to 45 degree intervals Will make code simpler and reduce interval or provide as a parameter \param angle angle Angle in degrees @@ -58,6 +60,7 @@ \retval double Constrained angle */ double SCRIBUS_API constrainAngle(double angle, double constrain); +inline FPoint SCRIBUS_API getPointFromRotation(const FPoint &p1, double distance, double angle); /*! \brief Get the rotation angle (in radian) from a transformation matrix Will make code simpler and reduce interval or provide as a parameter \param matrix the transformation matrix @@ -92,6 +95,14 @@ return point.manhattanLength(); } +inline FPoint getPointFromRotation(const FPoint &p1, double distance, double angle) +{ + FPoint p2; + p2.setX(p1.x() + cosd(angle) * distance); + p2.setY(p1.y() + sind(angle) * distance); + return p2; +} + inline double xy2Deg(double x, double y) { return atan2(y,x) * (180.0/M_PI);