View Issue Details

IDProjectCategoryView StatusLast Update
0015624ScribusMaster Pagespublic2026-08-29 11:48
Reporterlarsen Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
PlatformWindowsOSWindowsOS Version7
Product Version1.5.4 
Summary0015624: Guides are duplicated when editing in master page
DescriptionIt should be possible to set a guide in a master page and to move that guide afterwards.
Steps To Reproduce- Edit a master page and insert a guide
- Return to normal editing -> Guide is shown
- Edit master page again and move the guide
- Return to normal editing -> There are now two guides
Tags#please_test
PatchNo

Activities

ale

2019-03-29 16:01

manager   ~0046054

the solution is probably to disable the editing of the master page guides outside of the "edit master page" mode...

qirat

2026-08-29 11:47

reporter   ~0054371

I can still reproduce it in 1.7.4.svn. Here is a fix.

#Cause:
`applyMasterPage()` copied master standard guides into the normal page’s `GuideManagerCore` standard lists, so master and local guides had no ownership distinction.

#Issue:
Normal-page editing paths could therefore move/delete inherited guides; when the master was reapplied, the original master coordinates were copied back, causing duplicates.

#Fix:
Add separate inherited master-guide storage in `GuideManagerCore` (`m_horizontalMasterG` / `m_verticalMasterG`) and populate it through `setMasterPageGuides()`.

#Integration:
`horizontalsWithMaster()` / `verticalsWithMaster()` provide the combined view used by drawing, snapping and scripting queries, while normal edit operations continue to work only on the local standard lists.

#Result:
Master guides remain visible/snappable on normal pages but are no longer editable there, and reapplying a master updates the inherited set instead of duplicating guide coordinates.

#Compatibility:
`setMasterPageGuides(..., isLoading())` removes legacy copied master coordinates from local guide storage while loading older documents.
master-page-guides-inheritance-v1.3.patch (9,039 bytes)   
Index: scribus/guidemanagercore.h
===================================================================
--- scribus/guidemanagercore.h	(revision 27791)
+++ scribus/guidemanagercore.h	(working copy)
@@ -54,6 +54,8 @@
 
 	Guides horizontals(GuideType type) const;
 	Guides verticals(GuideType type) const;
+	Guides horizontalsWithMaster() const;
+	Guides verticalsWithMaster() const;
 	double horizontal(uint ix, GuideType type) const;
 	double vertical(uint ix, GuideType type) const;
 
@@ -65,6 +67,7 @@
 
 	void copy(GuideManagerCore *target) const;
 	void copy(GuideManagerCore *target, GuideType type) const;
+	void setMasterPageGuides(const GuideManagerCore& masterGuides, bool removeMatchingLocalGuides);
 
 	void drawPage(ScPainter *p, ScribusDoc *doc, double lineWidth) const;
 
@@ -125,6 +128,8 @@
 	ScPage* m_page {nullptr};
 	Guides m_horizontalStdG;
 	Guides m_verticalStdG;
+	Guides m_horizontalMasterG;
+	Guides m_verticalMasterG;
 	Guides m_horizontalAutoG;
 	Guides m_verticalAutoG;
 
Index: scribus/guidemanagercore.cpp
===================================================================
--- scribus/guidemanagercore.cpp	(revision 27791)
+++ scribus/guidemanagercore.cpp	(working copy)
@@ -57,7 +57,7 @@
 	switch (type)
 	{
 		case Standard:
-			if (!m_horizontalStdG.contains(value))
+			if (!m_horizontalStdG.contains(value) && !m_horizontalMasterG.contains(value))
 			{
 				m_horizontalStdG.append(value);
 				if (UndoManager::undoEnabled())
@@ -80,7 +80,7 @@
 		case Standard:
 			for (auto guidePos : values)
 			{
-				if (!m_horizontalStdG.contains(guidePos))
+				if (!m_horizontalStdG.contains(guidePos) && !m_horizontalMasterG.contains(guidePos))
 					m_horizontalStdG.append(guidePos);
 			}
 			break;
@@ -97,7 +97,7 @@
 	switch (type)
 	{
 		case Standard:
-			if (!m_verticalStdG.contains(value))
+			if (!m_verticalStdG.contains(value) && !m_verticalMasterG.contains(value))
 			{
 				m_verticalStdG.append(value);
 				if (UndoManager::undoEnabled())
@@ -120,7 +120,7 @@
 		case Standard:
 			for (auto guidePos : values)
 			{
-				if (!m_verticalStdG.contains(guidePos))
+				if (!m_verticalStdG.contains(guidePos) && !m_verticalMasterG.contains(guidePos))
 					m_verticalStdG.append(guidePos);
 			}
 			break;
@@ -191,6 +191,28 @@
 			return m_verticalAutoG;
 	}
 	return m_verticalStdG;
+}
+
+Guides GuideManagerCore::horizontalsWithMaster() const
+{
+	Guides guides = m_horizontalStdG;
+	for (auto guidePos : m_horizontalMasterG)
+	{
+		if (!guides.contains(guidePos))
+			guides.append(guidePos);
+	}
+	return guides;
+}
+
+Guides GuideManagerCore::verticalsWithMaster() const
+{
+	Guides guides = m_verticalStdG;
+	for (auto guidePos : m_verticalMasterG)
+	{
+		if (!guides.contains(guidePos))
+			guides.append(guidePos);
+	}
+	return guides;
 }
 
 double GuideManagerCore::horizontal(uint ix, GuideType type) const
@@ -383,6 +405,8 @@
 	switch (type)
 	{
 		case Standard:
+			if (m_horizontalMasterG.contains(to))
+				break;
 			m_horizontalStdG.removeAt(m_horizontalStdG.indexOf(from));
 			m_horizontalStdG.append(to);
 			if (UndoManager::undoEnabled())
@@ -403,6 +427,8 @@
 	switch (type)
 	{
 		case Standard:
+			if (m_verticalMasterG.contains(to))
+				break;
 			m_verticalStdG.removeAt(m_verticalStdG.indexOf(from));
 			m_verticalStdG.append(to);
 			if (UndoManager::undoEnabled())
@@ -449,6 +475,22 @@
 	}
 }
 
+void GuideManagerCore::setMasterPageGuides(const GuideManagerCore& masterGuides, bool removeMatchingLocalGuides)
+{
+	m_horizontalMasterG = masterGuides.m_horizontalStdG;
+	m_verticalMasterG = masterGuides.m_verticalStdG;
+
+	if (!removeMatchingLocalGuides)
+		return;
+
+	// Older files stored inherited standard guides in the normal page too.
+	// Normalize those copies while the document is being loaded.
+	for (auto guidePos : m_horizontalMasterG)
+		m_horizontalStdG.removeAll(guidePos);
+	for (auto guidePos : m_verticalMasterG)
+		m_verticalStdG.removeAll(guidePos);
+}
+
 void GuideManagerCore::drawPage(ScPainter *p, ScribusDoc *doc, double lineWidth) const
 {
 	const GuideManager* guideManager = ScCore->primaryMainWindow()->guidePalette;
@@ -465,9 +507,9 @@
 
 	// all standard
 	p->setPen(color, lineWidth, Qt::DashDotLine, Qt::FlatCap, Qt::MiterJoin);
-	for (auto guide : m_verticalStdG)
+	for (auto guide : verticalsWithMaster())
 		p->drawLine(FPoint(guide, verticalFrom), FPoint(guide, verticalTo));
-	for (auto guide : m_horizontalStdG)
+	for (auto guide : horizontalsWithMaster())
 		p->drawLine(FPoint(horizontalFrom, guide), FPoint(horizontalTo, guide));
 
 	// highlight selected standards
@@ -568,6 +610,11 @@
 		if (guidePos < y && guidePos > closest)
 			closest = guidePos;
 	}
+	for (auto guidePos : m_horizontalMasterG)
+	{
+		if (guidePos < y && guidePos > closest)
+			closest = guidePos;
+	}
 
 	for (auto guidePos : m_horizontalAutoG)
 	{
@@ -591,6 +638,11 @@
 		if (guidePos > y && guidePos < closest)
 			closest = guidePos;
 	}
+	for (auto guidePos : m_horizontalMasterG)
+	{
+		if (guidePos > y && guidePos < closest)
+			closest = guidePos;
+	}
 
 	for (auto guidePos : m_horizontalAutoG)
 	{
@@ -614,6 +666,11 @@
 		if (guidePos < x && guidePos > closest)
 			closest = guidePos;
 	}
+	for (auto guidePos : m_verticalMasterG)
+	{
+		if (guidePos < x && guidePos > closest)
+			closest = guidePos;
+	}
 
 	for (auto guidePos : m_verticalAutoG)
 	{
@@ -633,6 +690,11 @@
 {
 	double closest = m_page->width();
 	for (auto guidePos : m_verticalStdG)
+	{
+		if (guidePos > x && guidePos < closest)
+			closest = guidePos;
+	}
+	for (auto guidePos : m_verticalMasterG)
 	{
 		if (guidePos > x && guidePos < closest)
 			closest = guidePos;
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp	(revision 27791)
+++ scribus/scribusdoc.cpp	(working copy)
@@ -4875,14 +4875,16 @@
 		if (currItem->OwnPage == MpNr)
 			Ap->FromMaster.append(currItem);
 	}
+	// Standard guides are inherited from the master page. Keep them separate
+	// from the page's own guides so they stay synchronized and read-only here.
+	Ap->guides.setMasterPageGuides(Mp->guides, isLoading());
+
 	if (!isLoading())
 	{
 		// PV - apply auto guides from MP only if there are no auto guides
 		// on original page
-		if (Ap->guides.horizontalAutoCount() != 0 || Ap->guides.verticalAutoCount() != 0)
-			Mp->guides.copy(&Ap->guides, GuideManagerCore::Standard);
-		else
-			Mp->guides.copy(&Ap->guides);
+		if (Ap->guides.horizontalAutoCount() == 0 && Ap->guides.verticalAutoCount() == 0)
+			Mp->guides.copy(&Ap->guides, GuideManagerCore::Auto);
 
 		Ap->initialMargins.setTop(Mp->Margins.top());
 		Ap->initialMargins.setBottom(Mp->Margins.bottom());
@@ -5342,7 +5344,9 @@
 			++lp;
 		targetPage->LeftPg = lp;
 	}
-	sourcePage->guides.copy(&targetPage->guides);
+	targetPage->guides.addHorizontals(sourcePage->guides.horizontalsWithMaster(), GuideManagerCore::Standard);
+	targetPage->guides.addVerticals(sourcePage->guides.verticalsWithMaster(), GuideManagerCore::Standard);
+	sourcePage->guides.copy(&targetPage->guides, GuideManagerCore::Auto);
 	int docItemsOldCount = DocItems.count();
 	int masterItemsOldCount = MasterItems.count();
 	Selection tempSelection(this, false);
@@ -14733,7 +14737,7 @@
 	int gyM = -1;
 	const ScPage* page = (refPage == nullptr) ? currentPage() : refPage;
 	QMap<double, uint> tmpGuidesSel;
-	Guides tmpGuides = page->guides.horizontals(GuideManagerCore::Standard);
+	Guides tmpGuides = page->guides.horizontalsWithMaster();
 	Guides::iterator it;
 	double viewScale = m_View->scale();
 	const double snappingDistance = prefsData().guidesPrefs.guideRad / viewScale;
@@ -14754,7 +14758,7 @@
 		*yout = tmpGuides[gyM] + page->yOffset();
 	}
 	tmpGuidesSel.clear();
-	tmpGuides = page->guides.verticals(GuideManagerCore::Standard);
+	tmpGuides = page->guides.verticalsWithMaster();
 	for (it = tmpGuides.begin(); it != tmpGuides.end(); ++it, ++xg)
 	{
 		if (fabs((*it) + page->xOffset() - xin) < snappingDistance)
Index: scribus/plugins/scriptplugin/cmdpage.cpp
===================================================================
--- scribus/plugins/scriptplugin/cmdpage.cpp	(revision 27791)
+++ scribus/plugins/scriptplugin/cmdpage.cpp	(working copy)
@@ -317,7 +317,7 @@
 {
 	if (!checkHaveDocument())
 		return nullptr;
-	Guides g = ScCore->primaryMainWindow()->doc->currentPage()->guides.horizontals(GuideManagerCore::Standard);
+	Guides g = ScCore->primaryMainWindow()->doc->currentPage()->guides.horizontalsWithMaster();
 	int n = g.count();//ScCore->primaryMainWindow()->doc->currentPage->YGuides.count();
 	if (n == 0)
 		return Py_BuildValue("[]");
@@ -367,7 +367,7 @@
 {
 	if (!checkHaveDocument())
 		return nullptr;
-	Guides g = ScCore->primaryMainWindow()->doc->currentPage()->guides.verticals(GuideManagerCore::Standard);
+	Guides g = ScCore->primaryMainWindow()->doc->currentPage()->guides.verticalsWithMaster();
 	int n = g.count();//ScCore->primaryMainWindow()->doc->currentPage->XGuides.count();
 	if (n == 0)
 		return Py_BuildValue("[]");

Issue History

Date Modified Username Field Change
2019-03-29 12:10 larsen New Issue
2019-03-29 16:01 ale Note Added: 0046054
2026-08-29 11:47 qirat Note Added: 0054371
2026-08-29 11:47 qirat File Added: master-page-guides-inheritance-v1.3.patch
2026-08-29 11:48 qirat Tag Attached: #please_test