Index: resources/iconsets/1_7_0/1_7_0.xml
===================================================================
--- resources/iconsets/1_7_0/1_7_0.xml	(Revision 26366)
+++ resources/iconsets/1_7_0/1_7_0.xml	(Arbeitskopie)
@@ -138,8 +138,10 @@
 		<icon id="u_group.png" file="16/object-group.svg" /><!-- Outliner -->
 		<icon id="u_undo16.png" file="16/action-undo.svg" /><!-- Barcode -->
 		<icon id="ungroup.png" file="16/object-ungroup.svg" />
+		<icon id="add" file="16/action-add.svg" />
 		<icon id="collapse" file="16/action-chevron-right.svg" />
 		<icon id="context-menu" file="16/action-menu.svg" />
+		<icon id="delete" file="16/action-delete.svg" />
 		<icon id="delete-selected" file="16/action-delete-selected.svg" />
 		<icon id="erase-shadow-off" file="16/action-shadow-erase-off.svg" />
 		<icon id="erase-shadow-on" file="16/action-shadow-erase-on.svg" />
@@ -150,11 +152,9 @@
 		<icon id="reset-style-changes" file="16/action-reload.svg" /> <!-- 16/action-revert-changes.svg -->
 		<icon id="scale-height" file="16/action-scale-height.svg" />
 		<icon id="scale-width" file="16/action-scale-width.svg" />
+		<icon id="settings" file="16/properties-external-tools.svg" />
 		<icon id="swap" file="16/action-swap.svg" />
 		<icon id="toggle-object-coordination" file="16/object-xycoordination.svg" />
-		<icon id="context-menu" file="16/action-menu.svg" />
-		<icon id="scale-width" file="16/action-scale-width.svg" />
-		<icon id="scale-height" file="16/action-scale-height.svg" />
 		<icon id="whitespace-review-mode" file="16/action-whitespace-review.svg" />
 			
 		<!-- Alerts -->
Index: scribus/CMakeLists_Sources.txt
===================================================================
--- scribus/CMakeLists_Sources.txt	(Revision 26366)
+++ scribus/CMakeLists_Sources.txt	(Arbeitskopie)
@@ -114,6 +114,7 @@
 	nfttemplate.cpp
 	nodeeditcontext.cpp
 	notesstyles.cpp
+	opticalmarginlookup.cpp
 	pageitem.cpp
 	pageitem_arc.cpp
 	pageitem_group.cpp
@@ -381,6 +382,7 @@
 	ui/nodeeditpalette.cpp
 	ui/notesstyleseditor.cpp
 	ui/numformatcombo.cpp
+	ui/opticalmargineditor.cpp
 	ui/opticalmarginswidget.cpp
 	ui/outlinepalette.cpp
 	ui/outputpreview_pdf.cpp
Index: scribus/pageitem_textframe.cpp
===================================================================
--- scribus/pageitem_textframe.cpp	(Revision 26366)
+++ scribus/pageitem_textframe.cpp	(Arbeitskopie)
@@ -41,6 +41,7 @@
 #include "marks.h"
 #include "notesstyles.h"
 #include "numeration.h"
+#include "opticalmarginlookup.h"
 #include "pageitem.h"
 #include "pageitem_group.h"
 #include "pageitem_noteframe.h"
@@ -901,44 +912,58 @@
 
 
 	//defined but not used
-	///// calculate how much the first char should stick out to the left
-	//double opticalLeftMargin(const StoryText& itemText)
-	//{
-	//	int b = line.firstChar;
-	//	while (b < line.lastChar && (itemText.flags(b) & ScLayout_SuppressSpace))
-	//		   ++b;
-	//
-	//	double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
-	//	QChar chr = itemText.text(b);
-	//	double leftCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0);
-	//	if (QString("'´`").indexOf(chr) >= 0
-	//		|| chr == QChar(0x2018) // quote 6
-	//		|| chr == QChar(0x2019) // quote 9
-	//		|| chr == QChar(0x201a) // lower quote 9
-	//		|| chr == QChar(0x201b) // upper reversed 9 6
-	//		|| chr == QChar(0x2039) // single guillemet <
-	//		|| chr == QChar(0x203a) // single guillemet >
-	//		)
-	//		leftCorr *= -0.7;
-	//	else if (QString("\"").indexOf(chr) >= 0
-	//			 || chr == QChar(0x00ab) // guillemet <<
-	//			 || chr == QChar(0x00bb) // guillemet >>
-	//			 || chr == QChar(0x201c) // quote 66
-	//			 || chr == QChar(0x201d) // quote 99
-	//			 || chr == QChar(0x201e) // lower quote 99
-	//			 || chr == QChar(0x201f) // upper reversed 99
-	//			 )
-	//		leftCorr *= -0.5;
-	//	else {
-	//		leftCorr = itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0, chr);
-	//		leftCorr -= itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0);
-	////				double leftCorr2 = itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0, chr);
-	////				leftCorr2 -= itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0);
-	////				leftCorr = qMin(leftCorr, leftCorr2);
-	//	}
-	//	return leftCorr;
-	//}
+	/// calculate how much the first char should stick out to the left
+	double opticalLeftMargin(const StoryText& itemText)
+	{
+		int b = 0;
+		while (b < lineData.lastCluster && (itemText.flags(b) & ScLayout_SuppressSpace))
+			   ++b;
 
+		if (b < lineData.lastCluster)
+		{
+			const CharStyle& style = glyphs[b].style();
+			const ScFace& font = style.font();
+			double chs = style.fontSize() * (style.scaleH() / 1000.0);
+			QChar chr = itemText.text(glyphs[b].firstChar());
+			double leftCorr = font.glyphBBox(font.char2CMap(chr.unicode()), chs / 10.0).width;
+
+			leftCorr *= OpticalMarginLookup::instance().offset(chr).first;
+
+// 			if (QString("'´`").indexOf(chr) >= 0
+// 					|| chr == QChar(0x2018) // quote 6
+// 					|| chr == QChar(0x2019) // quote 9
+// 					|| chr == QChar(0x201a) // lower quote 9
+// 					|| chr == QChar(0x201b) // upper reversed 9 6
+// 					|| chr == QChar(0x2039) // single guillemet <
+// 					|| chr == QChar(0x203a) // single guillemet >
+// 					)
+// 				leftCorr *= 0.7;
+// 			else if (QString("\"").indexOf(chr) >= 0
+// 					 || chr == QChar(0x00ab) // guillemet <<
+// 					 || chr == QChar(0x00bb) // guillemet >>
+// 					 || chr == QChar(0x201c) // quote 66
+// 					 || chr == QChar(0x201d) // quote 99
+// 					 || chr == QChar(0x201e) // lower quote 99
+// 					 || chr == QChar(0x201f) // upper reversed 99
+// 					 )
+// 				leftCorr *= 0.5;
+// 			else {
+// #if 0
+// 				leftCorr = itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0, chr);
+// 				leftCorr -= itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0);
+// 				//				double leftCorr2 = itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0, chr);
+// 				//				leftCorr2 -= itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0);
+// 				//				leftCorr = qMin(leftCorr, leftCorr2);
+// #else
+// 				leftCorr = 0;
+// #endif
+// 			}
+
+			return leftCorr;
+		}
+		return 0.0;
+	}
+
 	/// calculate how much the last char should stick out to the right
 	double opticalRightMargin(const StoryText& itemText)
 	{
@@ -956,41 +981,46 @@
 			QChar chr = itemText.text(glyphs[b].lastChar());
 			double rightCorr;
 			if (glyphs[b].hasFlag(ScLayout_SoftHyphenVisible))
-				rightCorr = font.hyphenWidth(style, chs / 10.0);
+				rightCorr = font.hyphenWidth(style, chs / 10.0) * 0.5;
 			else
+			{
 				rightCorr = font.glyphBBox(font.char2CMap(chr.unicode()), chs / 10.0).width;
-			if (glyphs[b].hasFlag(ScLayout_SoftHyphenVisible)
-				|| QString("-,.`´'~").indexOf(chr) >= 0
-				|| chr == QChar(0x2010)
-				|| chr == QChar(0x2018)
-				|| chr == QChar(0x2019)
-				|| chr == QChar(0x201a)
-				|| chr == QChar(0x201b)
-				|| chr == QChar(0x2039)
-				|| chr == QChar(0x203a)
-				|| chr == QChar(0x2032) // PRIME
-				)
-				rightCorr *= 0.7;
-			else if (QString(";:\"").indexOf(chr) >= 0
-					 || chr == QChar(0x00ab)
-					 || chr == QChar(0x00bb)
-					 || chr == QChar(0x201c)
-					 || chr == QChar(0x201d)
-					 || chr == QChar(0x201e)
-					 || chr == QChar(0x201f)
-					 || chr == QChar(0x2013) // EN DASH
-					 || chr == QChar(0x2033) // double prime
-					 )
-				rightCorr *= 0.5;
-			else {
-#if 0
-				// FIXME HOST: is the kerning with "." a really reliable way to check this?
-				rightCorr = chStyle.font().realCharWidth(chr, chs / 10.0);
-				rightCorr -= chStyle.font().charWidth(chr, chs / 10.0, QChar('.'));
-#else
-				rightCorr = 0;
-#endif
+				rightCorr *= OpticalMarginLookup::instance().offset(chr).second;
 			}
+
+
+// 			if (glyphs[b].hasFlag(ScLayout_SoftHyphenVisible)
+// 				|| QString("-,.`´'~").indexOf(chr) >= 0
+// 				|| chr == QChar(0x2010) // Hyphen
+// 				|| chr == QChar(0x2018) // quote 6
+// 				|| chr == QChar(0x2019) // quote 9
+// 				|| chr == QChar(0x201a)
+// 				|| chr == QChar(0x201b)
+// 				|| chr == QChar(0x2039)
+// 				|| chr == QChar(0x203a)
+// 				|| chr == QChar(0x2032) // PRIME
+// 				)
+// 				rightCorr *= 0.7;
+// 			else if (QString(";:\"").indexOf(chr) >= 0
+// 					 || chr == QChar(0x00ab)
+// 					 || chr == QChar(0x00bb)
+// 					 || chr == QChar(0x201c)
+// 					 || chr == QChar(0x201d)
+// 					 || chr == QChar(0x201e)
+// 					 || chr == QChar(0x201f)
+// 					 || chr == QChar(0x2013) // EN DASH
+// 					 || chr == QChar(0x2033) // double prime
+// 					 )
+// 				rightCorr *= 0.5;
+// 			else {
+// #if 0
+// 				// FIXME HOST: is the kerning with "." a really reliable way to check this?
+// 				rightCorr = chStyle.font().realCharWidth(chr, chs / 10.0);
+// 				rightCorr -= chStyle.font().charWidth(chr, chs / 10.0, QChar('.'));
+// #else
+// 				rightCorr = 0;
+// #endif
+// 			}
 			return rightCorr;
 		}
 		return 0.0;
@@ -2438,6 +2468,11 @@
 					{
 						if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 							current.lineData.width += current.opticalRightMargin(itemText);
+						if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+						{
+							current.lineData.width += current.opticalLeftMargin(itemText);
+							current.lineData.x -= current.opticalLeftMargin(itemText);
+						}
 
 						OFs = 0;
 						if (style.alignment() == ParagraphStyle::RightAligned)
@@ -2467,6 +2502,9 @@
 						{
 							if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 								current.lineData.naturalWidth += current.opticalRightMargin(itemText);
+							if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+								current.lineData.naturalWidth += current.opticalLeftMargin(itemText);
+
 							double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing() / 2.0 - current.lineData.x;
 							if (current.lineData.naturalWidth > optiWidth)
 								current.lineData.width = qMax(current.lineData.width - current.maxShrink, optiWidth);
@@ -2553,6 +2591,11 @@
 						// Justification
 						if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 							current.lineData.width += current.opticalRightMargin(itemText);
+						if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+						{
+							current.lineData.width += current.opticalLeftMargin(itemText);
+							current.lineData.x -= current.opticalLeftMargin(itemText);
+						}
 						// #12565: Right alignment of hyphens
 						// The additional character width has already been taken into account
 						// above via the line break position, so it's not necessary to increase
@@ -2579,6 +2622,9 @@
 						{
 							if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 								current.lineData.naturalWidth += current.opticalRightMargin(itemText);
+							if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+								current.lineData.naturalWidth += current.opticalLeftMargin(itemText);
+
 							current.indentLine(style, OFs);
 						}
 						current.xPos = current.lineData.x + current.lineData.width;
@@ -2841,6 +2887,11 @@
 
 			if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 				current.lineData.width += current.opticalRightMargin(itemText);
+			if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+			{
+				current.lineData.width += current.opticalLeftMargin(itemText);
+				current.lineData.x -= current.opticalLeftMargin(itemText);
+			}
 
 			OFs = 0;
 			if (style.alignment() == ParagraphStyle::RightAligned)
@@ -2869,6 +2920,9 @@
 			{
 				if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 					current.lineData.naturalWidth += current.opticalRightMargin(itemText);
+				if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+					current.lineData.naturalWidth -= current.opticalLeftMargin(itemText);
+
 				current.indentLine(style, OFs);
 			}
 			if (current.glyphs[0].hasFlag(ScLayout_DropCap))
Index: scribus/plugins/fileloader/scribus170format/scribus170format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus170format/scribus170format.cpp	(Revision 26366)
+++ scribus/plugins/fileloader/scribus170format/scribus170format.cpp	(Arbeitskopie)
@@ -2499,6 +2499,7 @@
 		//->Prefs m_Doc->papColor = QColor(attrs.valueAsString("PAGEC"));
 
 	m_Doc->setMarginColored(attrs.valueAsBool("RANDF", false));
+	m_Doc->setOpticalMarginGroups(attrs.valueAsString("opticalMarginGroups"));
 
 	readCMSSettings(doc, attrs);
 	readDocumentInfo(doc, attrs);
Index: scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp
===================================================================
--- scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp	(Revision 26366)
+++ scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp	(Arbeitskopie)
@@ -519,6 +519,7 @@
 	docu.writeAttribute("calligraphicPenAngle", m_Doc->itemToolPrefs().calligraphicPenAngle);
 	docu.writeAttribute("calligraphicPenWidth", m_Doc->itemToolPrefs().calligraphicPenWidth);
 	docu.writeAttribute("calligraphicPenStyle", m_Doc->itemToolPrefs().calligraphicPenStyle);
+	docu.writeAttribute("opticalMarginGroups", m_Doc->opticalMarginGroups());
 
 	writeCheckerProfiles(docu);
 	writeJavascripts(docu);
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp	(Revision 26366)
+++ scribus/scribusdoc.cpp	(Arbeitskopie)
@@ -200,6 +200,7 @@
 ScribusDoc::ScribusDoc() : UndoObject( tr("Document")), Observable<ScribusDoc>(nullptr),
 	m_appPrefsData(PrefsManager::instance().appPrefs),
 	m_docPrefsData(PrefsManager::instance().appPrefs),
+	m_opticalMarginLookup(OpticalMarginLookup::instance()),
 	m_undoManager(UndoManager::instance()),
 	m_automaticTextFrames(false),
 	m_guardedObject(this),
@@ -236,6 +237,7 @@
 ScribusDoc::ScribusDoc(const QString& docName, int unitindex, const PageSize& pagesize, const MarginStruct& margins, const DocPagesSetup& pagesSetup) : UndoObject( tr("Document")),
 	m_appPrefsData(PrefsManager::instance().appPrefs),
 	m_docPrefsData(PrefsManager::instance().appPrefs),
+	m_opticalMarginLookup(OpticalMarginLookup::instance()),
 	m_undoManager(UndoManager::instance()),
 	m_docUnitRatio(unitGetRatioFromIndex(m_appPrefsData.docSetupPrefs.docUnitIndex)),
 	m_automaticTextFrames(pagesSetup.autoTextFrames),
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h	(Revision 26366)
+++ scribus/scribusdoc.h	(Arbeitskopie)
@@ -49,6 +49,7 @@
 #include "nodeeditcontext.h"
 #include "notesstyles.h"
 #include "observable.h"
+#include "opticalmarginlookup.h"
 #include "pageitem.h"
 #include "pageitem_group.h"
 #include "pageitem_latexframe.h"
@@ -242,6 +243,8 @@
 	const ApplicationPrefs& prefsData() const { return m_docPrefsData; }
 	void setNewPrefs(const ApplicationPrefs& prefsData, const ApplicationPrefs& oldPrefsData, bool resizePages, bool resizeMasterPages, bool resizePageMargins, bool resizeMasterPageMargins);
 
+	void setOpticalMarginGroups(const QString &groups) { m_opticalMarginLookup.fromString(groups);}
+	const QString opticalMarginGroups() { return m_opticalMarginLookup.toString();}
 	// Add, delete and move pages
 	
 	ScPage* addPage(int pageNumber, const QString& masterPageName = QString(), bool addAutoFrame = false);
@@ -1301,6 +1304,7 @@
 	QFileDevice::Permissions m_docFilePermissions {QFileDevice::ReadOwner|QFileDevice::WriteOwner};
 	ApplicationPrefs& m_appPrefsData;
 	ApplicationPrefs m_docPrefsData;
+	OpticalMarginLookup& m_opticalMarginLookup;
 	UndoManager * const m_undoManager;
 	bool m_loading {false};
 	bool m_modified {false};
Index: scribus/ui/opticalmarginswidget.cpp
===================================================================
--- scribus/ui/opticalmarginswidget.cpp	(Revision 26366)
+++ scribus/ui/opticalmarginswidget.cpp	(Arbeitskopie)
@@ -8,9 +8,11 @@
 #include <QHBoxLayout>
 
 #include "opticalmarginswidget.h"
+#include "opticalmarginlookup.h"
 #include "iconmanager.h"
 #include "scribus.h"
 #include "scribusapp.h"
+#include "ui/opticalmargineditor.h"
 
 OpticalMarginsWidget::OpticalMarginsWidget(QWidget* parent) : FormWidget(parent)
 {
@@ -21,7 +23,10 @@
 	rightButton->setCheckable(true);
 	parentButton = new QToolButton();
 	parentButton->hide(); // only used for style manager
+	settingsButton = new QToolButton();
 
+	editor = new OpticalMarginEditor();
+
 	QHBoxLayout* mainLayout = new QHBoxLayout();
 	mainLayout->setSpacing(4);
 	mainLayout->setContentsMargins(0, 0, 0, 0);
@@ -29,6 +34,7 @@
 	mainLayout->addWidget(leftButton);
 	mainLayout->addWidget(rightButton);
 	mainLayout->addSpacerItem(new QSpacerItem(4, 0, QSizePolicy::Fixed));
+	mainLayout->addWidget(settingsButton);
 	mainLayout->addWidget(parentButton);
 	mainLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
 
@@ -40,6 +46,8 @@
 	connect(ScQApp, SIGNAL(iconSetChanged()), this, SLOT(iconSetChange()));
 	connect(rightButton, SIGNAL(clicked()), this, SIGNAL(opticalMarginChanged()));
 	connect(leftButton, SIGNAL(clicked()), this, SIGNAL(opticalMarginChanged()));
+	connect(settingsButton, SIGNAL(clicked()), this, SLOT(showOpticalMarginEditor()));
+	connect(editor, SIGNAL(marginGroupChanged()), this, SIGNAL(opticalMarginChanged()));
 }
 
 int OpticalMarginsWidget::opticalMargin()
@@ -91,6 +99,7 @@
 	IconManager &im = IconManager::instance();
 	leftButton->setIcon(im.loadIcon("paragraph-optical-margin-left"));
 	rightButton->setIcon(im.loadIcon("paragraph-optical-margin-right"));
+	settingsButton->setIcon(im.loadIcon("settings"));
 }
 
 void OpticalMarginsWidget::changeEvent(QEvent *e)
@@ -109,4 +118,11 @@
 
 	leftButton->setToolTip( tr("Optical character offset on left side"));
 	rightButton->setToolTip( tr("Optical character offset on right side"));
+	settingsButton->setToolTip( tr("Edit offset of optical margins"));
 }
+
+void OpticalMarginsWidget::showOpticalMarginEditor()
+{
+	editor->setOpticalMarginGroup(OpticalMarginLookup::instance().opticalMarginGroups());
+	editor->exec();
+}
Index: scribus/ui/opticalmarginswidget.h
===================================================================
--- scribus/ui/opticalmarginswidget.h	(Revision 26366)
+++ scribus/ui/opticalmarginswidget.h	(Arbeitskopie)
@@ -13,6 +13,7 @@
 class ParagraphStyle;
 class ScribusDoc;
 class ScribusMainWindow;
+class OpticalMarginEditor;
 
 class OpticalMarginsWidget : public FormWidget
 {
@@ -25,6 +26,7 @@
 	QToolButton *leftButton = {nullptr};
 	QToolButton *rightButton = {nullptr};
 	QToolButton *parentButton = {nullptr};
+	QToolButton *settingsButton = {nullptr};
 
 	int opticalMargin();
 	void setOpticalMargin(int omt);
@@ -33,10 +35,13 @@
 
 	void changeEvent(QEvent *e) override;
 
+	OpticalMarginEditor * editor;
+
 public slots:
 
 	void iconSetChange();
 	void languageChange();
+	void showOpticalMarginEditor();
 
 signals:
 	void opticalMarginChanged();
