Index: resources/iconsets/1_7_0/1_7_0.xml
===================================================================
--- resources/iconsets/1_7_0/1_7_0.xml	(Revision 26678)
+++ resources/iconsets/1_7_0/1_7_0.xml	(Arbeitskopie)
@@ -205,29 +205,34 @@
     		<icon id="AppIcon2.png" file="scribus-icon.svg" />
     
     		<!-- Bezier & Vector Path-->
-    		<icon id="22/transform-shear-down.png" file="16/bezier-path-shear-down.svg" />
-		<icon id="22/transform-shear-left.png" file="16/bezier-path-shear-left.svg" />
-		<icon id="22/transform-shear-right.png" file="16/bezier-path-shear-right.svg" />
-		<icon id="22/transform-shear-up.png" file="16/bezier-path-shear-up.svg" />
-		<icon id="hmirror.png" file="16/object-flip-horizontal.svg" />
-		<icon id="vmirror.png" file="16/object-flip-vertical.svg" />
-		<icon id="AddNode.png" file="16/bezier-node-add.svg" />
-		<icon id="DeleteNode.png" file="16/bezier-node-delete.svg" />		
-		<icon id="Reset1Node.png" file="16/bezier-control-reset.svg" />
-		<icon id="ResetNode.png" file="16/bezier-controls-reset.svg" />
-		<icon id="MoveAsym.png" file="16/bezier-control-asymetric.svg" />
-		<icon id="MoveKontrol.png" file="16/bezier-control-move.svg" />
-		<icon id="MoveNode.png" file="16/bezier-node-move.svg" />
-		<icon id="MoveSym.png" file="16/bezier-control-symetric.svg" />
-		<icon id="PolyCut.png" file="16/bezier-split.svg" />
-		<icon id="BezierClose.png" file="16/bezier-close.svg" />
-		<icon id="expand.png" file="16/bezier-scale-up.svg" />
-		<icon id="crop.png" file="16/bezier-scale-down.svg" />
-		<icon id="pathexclusion.png" file="16/path-exclusion.svg" />
+    		<icon id="pathexclusion.png" file="16/path-exclusion.svg" />
 		<icon id="pathintersection.png" file="16/path-intersection.svg" />
 		<icon id="pathparts.png" file="16/path-combine.svg" />
 		<icon id="pathsubtraction.png" file="16/path-difference.svg" />
 		<icon id="pathunite.png" file="16/path-union.svg" />
+		<icon id="MoveKontrol.png" file="16/bezier-control-move.svg" />
+		<icon id="Reset1Node.png" file="16/bezier-control-reset.svg" />
+		<icon id="ResetNode.png" file="16/bezier-controls-reset.svg" />
+		<icon id="bezier-close" file="16/bezier-close.svg" />
+		<icon id="bezier-control-asymetric" file="16/bezier-control-asymetric.svg" />
+		<icon id="bezier-control-independent" file="16/bezier-control-independent.svg" />
+		<icon id="bezier-control-symetric" file="16/bezier-control-symetric.svg" />
+		<icon id="bezier-node-add" file="16/bezier-node-add.svg" />
+		<icon id="bezier-node-delete" file="16/bezier-node-delete.svg" />
+		<icon id="bezier-node-edit" file="16/bezier-node-edit.svg" />
+		<icon id="bezier-node-move" file="16/bezier-node-move.svg" />
+    		<icon id="bezier-path-shear-down" file="16/bezier-path-shear-down.svg" />
+		<icon id="bezier-path-shear-left" file="16/bezier-path-shear-left.svg" />
+		<icon id="bezier-path-shear-right" file="16/bezier-path-shear-right.svg" />
+		<icon id="bezier-path-shear-up" file="16/bezier-path-shear-up.svg" />
+		<icon id="bezier-scale-up" file="16/bezier-scale-up.svg" />
+		<icon id="bezier-scale-down" file="16/bezier-scale-down.svg" />
+		<icon id="bezier-split" file="16/bezier-split.svg" />
+		<icon id="object-flip-horizontal" file="16/object-flip-horizontal.svg" />
+		<icon id="object-flip-vertical" file="16/object-flip-vertical.svg" />
+		<icon id="position-origin-canvas" file="16/position-origin-canvas.svg" />
+		<icon id="position-origin-item" file="16/position-origin-item.svg" />
+		<icon id="position-origin-page" file="16/position-origin-page.svg" />
     
 		<!-- Color -->
 		<icon id="register.png" file="16/color-registration.svg" />
@@ -271,6 +276,8 @@
 		<icon id="select_column.png" file="32/cursor-select-column.svg" /><!-- table -->
 		<icon id="select_row.png" file="32/cursor-select-row.svg" /><!-- table -->
 		<icon id="dragpix.png" file="32/cursor-drop-image.svg" />
+		<icon id="cursor-move" file="32/cursor-move.svg" />
+		<icon id="cursor-node-edit" file="32/cursor-node-edit.svg" />
 		
 		<!-- Drawable Shapes -->
 		<!--
Index: scribus/canvasmode.cpp
===================================================================
--- scribus/canvasmode.cpp	(Revision 26678)
+++ scribus/canvasmode.cpp	(Arbeitskopie)
@@ -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)
@@ -656,7 +659,7 @@
 			cursor = im.loadCursor("DrawFreeLine.png", 0, 31);
 			break;
 		case modeDrawCalligraphicLine:
-			cursor = im.loadCursor("drawcalligraphy.png", 4, 4);
+			cursor = im.loadCursor("drawcalligraphy.png");
 			break;
 		case modeImportObject:
 			cursor = im.loadCursor("dragpix.png");
@@ -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) /*&& (m_doc->nodeEdit.edPoints())*/)
 							{
 								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) /*&& (m_doc->nodeEdit.edPoints())*/)
 							{
 								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) /*&& (m_doc->nodeEdit.edPoints())*/)
 							{
 								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) /*&& (m_doc->nodeEdit.edPoints())*/)
 							{
 								QPolygonF poly;
 								m_doc->nodeEdit.beginTransaction(currItem);
@@ -1734,9 +1737,10 @@
 	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["test"]				= Qt::magenta;
 	QColor selectionAlpha		= m_color["frame-selection"];
 	selectionAlpha.setAlphaF(.05f);
@@ -1747,18 +1751,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 +1772,8 @@
 	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);
 
 	m_brush["frame-move"]				= Qt::NoBrush;
 	m_brush["selection"]				= Qt::NoBrush;
Index: scribus/canvasmode_nodeedit.cpp
===================================================================
--- scribus/canvasmode_nodeedit.cpp	(Revision 26678)
+++ 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,12 @@
 				p->scale(1, -1);
 			}
 		}
-	}	
+	}
 	const double scale = m_canvas->m_viewMode.scale;
 
 	// 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 +86,31 @@
 			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;
+
+	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 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);
+
+		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;
+		isActiveControl = m_doc->nodeEdit.clre() == i + 1 ? 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<int, int> CanvasMode_NodeEdit::selectedNodesList(FPointArray points)
+{
+	QMap<int, int> 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<FPointArray> *state = m_doc->nodeEdit.finishTransaction1(currItem);
+		ScOldNewState<FPointArray> *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,68 +947,12 @@
 			}
 		}
 	}
-	if ((m_doc->nodeEdit.submode() == NodeEditContext::DEL_POINT) && m_doc->nodeEdit.hasNodeSelected())
+
+	if ((m_doc->nodeEdit.submode() == NodeEditContext::DEL_POINT) && 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))
 	{
 		bool foundP = false;
@@ -856,7 +985,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 +1040,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,7 +1060,7 @@
 		m_rectangleSelect->prepare(m->globalPosition());
 		m_view->startGesture(m_rectangleSelect);
 	}
-	
+
 }
 
 
@@ -965,6 +1075,7 @@
 			itemPos.translate(currItem->width(), 0);
 			itemPos.scale(-1, 1);
 		}
+
 		if (currItem->imageFlippedV())
 		{
 			itemPos.translate(0, currItem->height());
@@ -971,38 +1082,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("DelPoint.png", 1, 1));
-				if (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH)
-					m_view->setCursor(IconManager::instance().loadCursor("Split.png", 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_view->setCursor(IconManager::instance().loadCursor("DelPoint.png", 1, 1));
+					else if (m_doc->nodeEdit.submode() == NodeEditContext::SPLIT_PATH)
+						m_view->setCursor(IconManager::instance().loadCursor("Split.png", 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 +1137,7 @@
 			Bez.moveTo(a1);
 			Bez.cubicTo(a2, a3, a4);
 			double len = Bez.length();
+
 			if (len > 0.0)
 			{
 				double delta = 2.0 / len;
@@ -1031,7 +1154,9 @@
 							m_view->setCursor(IconManager::instance().loadCursor("Split.png", 1, 1));
 						else
 							m_view->setCursor(QCursor(Qt::ArrowCursor));
+
 						m_doc->nodeEdit.setClre2(poi);
+						state.hoveredOver = PathSegment;
 						return true;
 					}
 				}
@@ -1044,6 +1169,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 +1178,7 @@
 		m_view->startGesture(m_rectangleSelect);
 		return;
 	}
+
 	FPoint npf;
 	double newX = m->position().x();
 	double newY = m->position().y();
@@ -1059,6 +1186,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 +1197,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 +1246,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 +1330,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 26678)
+++ scribus/canvasmode_nodeedit.h	(Arbeitskopie)
@@ -19,6 +19,7 @@
 #define CANVAS_MODE_NODEEDIT_H
 
 #include "canvasmode.h"
+#include "nodeeditcontext.h"
 
 #include <QTransform>
 #include <QRect>
@@ -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<int, int> 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 26678)
+++ 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<int>(EndInd)) && (m_ClRe % 2 == 0))
+
+		// update control of node
+		if (isNode(m_ClRe) && (m_ClRe + 1 < static_cast<int>(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<int>(EndInd)) && (m_ClRe != static_cast<int>(StartInd)))
+
+		// update right node with control
+		if (isLeftNode(m_ClRe) && (m_ClRe + 3 < static_cast<int>(EndInd)) && (m_ClRe != static_cast<int>(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<int>(EndInd)) && (m_ClRe != static_cast<int>(StartInd)))
+
+		// update left node with control
+		if (isRightNode(m_ClRe) && (m_ClRe + 3 < static_cast<int>(EndInd)) && (m_ClRe != static_cast<int>(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<int>(StartInd)) || (m_ClRe == static_cast<int>(EndInd - 2))) &&
 			((currItem->itemType() == PageItem::Polygon)
 			|| (currItem->itemType() == PageItem::Group)
@@ -275,7 +313,7 @@
 		{
 			if (m_ClRe == static_cast<int>(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<int>(StartInd + 1)) || (m_ClRe == static_cast<int>(EndInd - 1))) &&
-			((currItem->itemType() == PageItem::Polygon)
+
+		bool firstLastControl = ((m_ClRe == static_cast<int>(StartInd + 1)) || (m_ClRe == static_cast<int>(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<int>(StartInd + 1)) && (m_ClRe != static_cast<int>(EndInd - 1));
+
+		// update control if there is an opposite control
+		if (firstLastControl || anyControl)
 		{
-			uint kon = 0;
-			if (m_ClRe == static_cast<int>(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<int>(StartInd + 1)) && (m_ClRe != static_cast<int>(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 26678)
+++ scribus/nodeeditcontext.h	(Arbeitskopie)
@@ -39,6 +39,46 @@
 class SCRIBUS_API NodeEditContext : public MassObservable<QPointF>
 {
 	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<int>& 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<FPointArray>* finishTransaction1(PageItem* currItem);
 		void finishTransaction2(PageItem* currItem, ScOldNewState<FPointArray>* 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<int> 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 26678)
+++ 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/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp	(Revision 26678)
+++ scribus/scribusdoc.cpp	(Arbeitskopie)
@@ -8329,6 +8329,9 @@
 	for (int i = 0; i < selectedItemCount; ++i)
 	{
 		PageItem* currItem = itemSelection->itemAt(i);
+
+		int oldType = currItem->gradientType();
+
 		currItem->setGradientType(typ);
 		switch (currItem->gradientType())
 		{
@@ -8391,6 +8394,12 @@
 			currItem->updateGradientVectors();
 		if (currItem->gradientType() == Gradient_Conical)
 			currItem->createConicalMesh();
+
+		// 17332: Conical gradient and mesh gradient are sharing the same meshGradientArray.
+		// We have to reset the array for mesh gradient to avoid a resue of the "fake" colors of the conical gradient
+		if (currItem->gradientType() == Gradient_Mesh && oldType == Gradient_Conical)
+			currItem->createGradientMesh(2, 2);
+
 		currItem->update();
 	}
 
Index: scribus/scribusview.cpp
===================================================================
--- scribus/scribusview.cpp	(Revision 26678)
+++ 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 26678)
+++ 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/colorpicker/colorpicker_gradient_properties.cpp
===================================================================
--- scribus/ui/colorpicker/colorpicker_gradient_properties.cpp	(Revision 26678)
+++ scribus/ui/colorpicker/colorpicker_gradient_properties.cpp	(Arbeitskopie)
@@ -373,11 +373,11 @@
 void ColorPickerGradientProperties::iconSetChange()
 {
 	IconManager& im = IconManager::instance();
-	editPoints->setIcon(im.loadIcon("MoveNode.png"));
+	editPoints->setIcon(im.loadIcon("bezier-node-move"));
 	editControlPoints->setIcon(im.loadIcon("MoveKontrol.png"));
 	resetControlPoint->setIcon(im.loadIcon("Reset1Node.png"));
 	resetAllControlPoints->setIcon(im.loadIcon("ResetNode.png"));
-	editPPoint->setIcon(im.loadIcon("MoveNode.png"));
+	editPPoint->setIcon(im.loadIcon("bezier-node-move"));
 	editPControlPoints->setIcon(im.loadIcon("MoveKontrol.png"));
 	resetPControlPoint->setIcon(im.loadIcon("Reset1Node.png"));
 	resetAllPControlPoints->setIcon(im.loadIcon("ResetNode.png"));
Index: scribus/ui/nodeeditpalette.cpp
===================================================================
--- scribus/ui/nodeeditpalette.cpp	(Revision 26678)
+++ scribus/ui/nodeeditpalette.cpp	(Arbeitskopie)
@@ -5,6 +5,7 @@
 for which a new license (GPL+exception) is in place.
 */
 
+#include <QButtonGroup>
 #include <QEvent>
 
 #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::Policy>(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("22/exit.png"), 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,28 +873,29 @@
 {
 	IconManager& im = IconManager::instance();
 
-	MoveNode->setIcon(im.loadIcon("MoveNode.png"));
-	AddNode->setIcon(im.loadIcon("AddNode.png"));
-	DeleteNode->setIcon(im.loadIcon("DeleteNode.png"));
-	ResNode->setIcon(im.loadIcon("ResetNode.png"));
-	MoveControl->setIcon(im.loadIcon("MoveKontrol.png"));
-	AsymMove->setIcon(im.loadIcon("MoveAsym.png"));
-	SymMove->setIcon(im.loadIcon("MoveSym.png"));
-	Res1Node->setIcon(im.loadIcon("Reset1Node.png"));
-	PolySplit->setIcon(im.loadIcon("PolyCut.png"));
-	BezierClose->setIcon(im.loadIcon("BezierClose.png"));
-	PolyMirrorH->setIcon(im.loadIcon("hmirror.png"));
-	PolyMirrorV->setIcon(im.loadIcon("vmirror.png"));
-	PolyShearL->setIcon(im.loadIcon("22/transform-shear-left.png"));
-	PolyShearR->setIcon(im.loadIcon("22/transform-shear-right.png"));
-	PolyShearU->setIcon(im.loadIcon("22/transform-shear-up.png"));
-	PolyShearD->setIcon(im.loadIcon("22/transform-shear-down.png"));
+	initPosOriginMenu();
+
+	MoveNode->setIcon(im.loadIcon("bezier-node-move"));
+	AddNode->setIcon(im.loadIcon("bezier-node-add"));
+	DeleteNode->setIcon(im.loadIcon("bezier-node-delete"));
+	AsymMove->setIcon(im.loadIcon("bezier-control-asymetric"));
+	SymMove->setIcon(im.loadIcon("bezier-control-symetric"));
+	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"));
+	PolyMirrorV->setIcon(im.loadIcon("object-flip-vertical"));
+	PolyShearL->setIcon(im.loadIcon("bezier-path-shear-left"));
+	PolyShearR->setIcon(im.loadIcon("bezier-path-shear-right"));
+	PolyShearU->setIcon(im.loadIcon("bezier-path-shear-up"));
+	PolyShearD->setIcon(im.loadIcon("bezier-path-shear-down"));
 	RotateCCW->setIcon(im.loadIcon("rotate_ccw.png"));
 	RotateCW->setIcon(im.loadIcon("rotate_cw.png"));
-	Expand->setIcon(im.loadIcon("expand.png"));
-	Shrink->setIcon(im.loadIcon("crop.png"));
-	Enlarge->setIcon(im.loadIcon("expand.png"));
-	Reduce->setIcon(im.loadIcon("crop.png"));
+	Expand->setIcon(im.loadIcon("bezier-scale-up"));
+	Shrink->setIcon(im.loadIcon("bezier-scale-down"));
+	Enlarge->setIcon(im.loadIcon("bezier-scale-up"));
+	Reduce->setIcon(im.loadIcon("bezier-scale-down"));
 }
 
 void NodePalette::languageChange()
@@ -1098,11 +903,11 @@
 	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:"));
+	initPosOriginMenu();
+
+	PosOriginLabel->setText( tr("Origin:"));
+	TextLabel1->setText( tr("&X:"));
+	TextLabel2->setText( tr("&Y:"));
 	PreviewMode->setText( tr("Hide Nodes"));
 	EditCont->setText( tr("Edit &Contour Line"));
 	ResetCont->setText( tr("&Reset Contour Line"));
@@ -1113,13 +918,12 @@
 	resetDefaultButton->setText( tr("Reset all edits"));
 //	editEditButton->setText( tr("&End Editing"));
 	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"));
@@ -1141,7 +945,7 @@
 	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(  "<qt>" + tr("When checked use coordinates relative to the page, otherwise coordinates are relative to the Object") + "</qt>");
+	PosOriginButton->setToolTip(  "<qt>" + tr("Use coordinates relative to the canvas, page, or to the Object") + "</qt>");
 }
 
 void NodePalette::unitChange()
Index: scribus/ui/nodeeditpalette.h
===================================================================
--- scribus/ui/nodeeditpalette.h	(Revision 26678)
+++ 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 26678)
+++ scribus/util_math.h	(Arbeitskopie)
@@ -19,6 +19,7 @@
 #include <QPainterPath>
 #include <QLineF>
 
+#include "fpoint.h"
 #include "scribusapi.h"
 
 class FPoint;
@@ -42,7 +43,7 @@
  * @param t
  * @return
  */
-QList<QPointF> catmullToBezier(const QList<QPointF>& inputPoints, double t = 1);
+QList<QPointF> SCRIBUS_API catmullToBezier(const QList<QPointF>& 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);
