Index: scribus/pageitem.cpp =================================================================== --- scribus/pageitem.cpp (revision 27703) +++ scribus/pageitem.cpp (working copy) @@ -6998,7 +6998,19 @@ return; } - int pos = is->getInt("POS"); + // Paragraph-style undo states used to be anchored only by raw text + // positions. Numbered/bulleted-list marker characters can be inserted or + // removed while applying paragraph styles, so those positions may shift + // before undo/redo is replayed. Prefer the stored paragraph index and + // resolve it against the current story; keep POS as a fallback for older + // undo states. + int pos = qBound(0, is->getInt("POS"), itemText.length()); + if (is->contains("PARA")) + { + const int maxPara = static_cast(itemText.nrOfParagraphs()); + const int para = qBound(0, is->getInt("PARA"), maxPara); + pos = itemText.endOfParagraph(static_cast(para)); + } if (isUndo) { itemText.eraseStyle(pos, is->getNewState()); Index: scribus/pageitem_textframe.cpp =================================================================== --- scribus/pageitem_textframe.cpp (revision 27703) +++ scribus/pageitem_textframe.cpp (working copy) @@ -24,8 +24,10 @@ #include "pageitem_textframe.h" #include +#include #include #include +#include #include #include #include @@ -76,6 +78,65 @@ using namespace std; +namespace +{ + struct NumberedListMarkerMetrics + { + double width { 0.0 }; + double suffixAnchor { 0.0 }; + double boxWidth { 0.0 }; + double alignShift { 0.0 }; + }; + + QString numberedListMarkerAlignmentKey(const ParagraphStyle& style) + { + return QString("%1\x1f%2\x1f%3\x1f%4\x1f%5") + .arg(style.numName()) + .arg(style.numLevel()) + .arg(style.numFormat()) + .arg(style.numPrefix()) + .arg(style.numSuffix()); + } + + double numberedListMarkerClusterWidth(const GlyphCluster& cluster) + { + double width = 0.0; + for (const GlyphLayout& glyph : cluster.glyphs()) + width += glyph.xadvance * cluster.scaleH(); + return width; + } + + NumberedListMarkerMetrics numberedListMarkerMetrics(const QList& glyphClusters, int markerStart, int markerEnd, int suffixLength) + { + NumberedListMarkerMetrics metrics; + QVector glyphOrigins; + int glyphCount = 0; + + for (int i = markerStart; i < markerEnd; ++i) + glyphCount += glyphClusters[i].glyphs().count(); + glyphOrigins.reserve(glyphCount); + + for (int i = markerStart; i < markerEnd; ++i) + { + const GlyphCluster& cluster = glyphClusters[i]; + for (const GlyphLayout& glyph : cluster.glyphs()) + { + glyphOrigins.append(metrics.width + (glyph.xoffset * cluster.scaleH())); + metrics.width += glyph.xadvance * cluster.scaleH(); + } + } + + metrics.suffixAnchor = metrics.width; + if (suffixLength > 0 && !glyphOrigins.isEmpty()) + { + const int suffixGlyphIndex = qMax(0, glyphOrigins.count() - suffixLength); + metrics.suffixAnchor = glyphOrigins.at(suffixGlyphIndex); + } + + return metrics; + } +} + PageItem_TextFrame::PageItem_TextFrame(ScribusDoc *pa, double x, double y, double w, double h, double w2, const QString& fill, const QString& outline) : PageItem(pa, PageItem::TextFrame, x, y, w, h, w2, fill, outline) { @@ -1330,6 +1391,77 @@ ShapedTextFeed shapedText(&itemText, firstInFrame(), context); QList glyphClusters; // = textShaper.shape(); + QHash numberedListMarkerMetricsByPos; + bool hasAlignedNumberedListMarkers = false; + for (int pos = 0; pos < itLen; ++pos) + { + if (!itemText.isBlockStart(pos)) + continue; + const ParagraphStyle& blockStyle = itemText.paragraphStyle(pos); + if (blockStyle.hasNum() && blockStyle.numAlignment() != ParagraphStyle::NumLeftAligned) + { + hasAlignedNumberedListMarkers = true; + break; + } + } + if (hasAlignedNumberedListMarkers) + { + for (int clusterIndex = 0; shapedText.haveMoreText(clusterIndex, glyphClusters); ++clusterIndex) + { + } + + QHash maxMarkerWidthForList; + QHash maxSuffixAnchorForList; + QHash markerListKey; + for (int clusterIndex = 0; clusterIndex < glyphClusters.count();) + { + const int markerPos = glyphClusters[clusterIndex].firstChar(); + const ParagraphStyle& blockStyle = itemText.paragraphStyle(markerPos); + if (!itemText.isBlockStart(markerPos) || !blockStyle.hasNum() || blockStyle.numAlignment() == ParagraphStyle::NumLeftAligned) + { + ++clusterIndex; + continue; + } + + int markerEnd = clusterIndex; + while (markerEnd < glyphClusters.count() && glyphClusters[markerEnd].firstChar() == markerPos) + ++markerEnd; + + NumberedListMarkerMetrics metrics = numberedListMarkerMetrics(glyphClusters, clusterIndex, markerEnd, blockStyle.numSuffix().length()); + const QString listKey = numberedListMarkerAlignmentKey(blockStyle); + markerListKey.insert(markerPos, listKey); + numberedListMarkerMetricsByPos.insert(markerPos, metrics); + maxMarkerWidthForList[listKey] = qMax(maxMarkerWidthForList.value(listKey, 0.0), metrics.width); + maxSuffixAnchorForList[listKey] = qMax(maxSuffixAnchorForList.value(listKey, 0.0), metrics.suffixAnchor); + clusterIndex = markerEnd; + } + + QHash markerBoxWidthForList; + for (auto it = markerListKey.cbegin(); it != markerListKey.cend(); ++it) + { + const int markerPos = it.key(); + const QString& listKey = it.value(); + const ParagraphStyle& blockStyle = itemText.paragraphStyle(markerPos); + NumberedListMarkerMetrics metrics = numberedListMarkerMetricsByPos.value(markerPos); + if (blockStyle.numAlignment() == ParagraphStyle::NumSuffixAligned) + metrics.alignShift = qMax(0.0, maxSuffixAnchorForList.value(listKey, metrics.suffixAnchor) - metrics.suffixAnchor); + markerBoxWidthForList[listKey] = qMax(markerBoxWidthForList.value(listKey, 0.0), metrics.width + metrics.alignShift); + numberedListMarkerMetricsByPos.insert(markerPos, metrics); + } + + for (auto it = markerListKey.cbegin(); it != markerListKey.cend(); ++it) + { + const int markerPos = it.key(); + const QString& listKey = it.value(); + const ParagraphStyle& blockStyle = itemText.paragraphStyle(markerPos); + NumberedListMarkerMetrics metrics = numberedListMarkerMetricsByPos.value(markerPos); + if (blockStyle.numAlignment() == ParagraphStyle::NumSuffixAligned) + metrics.boxWidth = markerBoxWidthForList.value(listKey, metrics.width + metrics.alignShift); + else + metrics.boxWidth = maxMarkerWidthForList.value(listKey, metrics.width); + numberedListMarkerMetricsByPos.insert(markerPos, metrics); + } + } // std::sort(glyphClusters.begin(), glyphClusters.end(), logicalGlyphRunComp); LineControl current(m_width, m_height, m_textDistanceMargins, lineCorr, m_Doc, context, columnWidth(), m_columnGap); @@ -1826,6 +1958,8 @@ break; effectWidth += glyph.width(); } + if (BulNumMode && style.hasNum() && numberedListMarkerMetricsByPos.contains(a)) + effectWidth = numberedListMarkerMetricsByPos.value(a).boxWidth; if (style.direction() == ParagraphStyle::RTL) { @@ -2440,7 +2574,34 @@ } if ((DropCmode || BulNumMode) && !outs) { - current.xPos += style.parEffectOffset(); + double parEffectExtraWidth = style.parEffectOffset(); + double markerAlignShift = 0.0; + if (BulNumMode && style.hasNum() && numberedListMarkerMetricsByPos.contains(a)) + { + const bool lastMarkerCluster = (i + 1 >= glyphClusters.count()) || (glyphClusters[i + 1].firstChar() != a); + if (lastMarkerCluster) + { + double markerWidth = 0.0; + for (int j = 0; j < current.glyphs.size(); ++j) + { + const GlyphCluster& currentGlyph = current.glyphs[j]; + if (currentGlyph.firstChar() == a) + markerWidth += numberedListMarkerClusterWidth(currentGlyph); + } + + const NumberedListMarkerMetrics markerMetrics = numberedListMarkerMetricsByPos.value(a); + const double markerBoxWidth = markerMetrics.boxWidth; + const double markerAlignPad = qMax(0.0, markerBoxWidth - markerWidth); + parEffectExtraWidth += markerAlignPad; + if (style.numAlignment() == ParagraphStyle::NumRightAligned) + markerAlignShift = markerAlignPad; + else if (style.numAlignment() == ParagraphStyle::NumCentered) + markerAlignShift = markerAlignPad / 2.0; + else if (style.numAlignment() == ParagraphStyle::NumSuffixAligned) + markerAlignShift = markerMetrics.alignShift; + } + } + current.xPos += parEffectExtraWidth; // for bulleted lists, make sure offset is applied only after last bullet char // for numbered lists, make sure that offset is applied only after the suffix // loop over previous current.glyphs and set their extraWidth to 0.0 @@ -2454,14 +2615,23 @@ } } // set the offset for Drop Cap, Bullet & Number List - current.glyphs[currentIndex].extraWidth += style.parEffectOffset(); + current.glyphs[currentIndex].extraWidth += parEffectExtraWidth; + if (markerAlignShift != 0.0) + { + for (int j = 0; j < current.glyphs.size(); ++j) + { + GlyphCluster& currentGlyph = current.glyphs[j]; + if (currentGlyph.firstChar() == a) + currentGlyph.xoffset += markerAlignShift; + } + } // RTL: the line is reversed at render time, so trailing extraWidth lands on // the marker's OUTER (right) edge, not between the marker and the text. Shift // the marker glyph to the right of its advance box so the reserved offset // falls on the inner (left) side, next to the text. Drop caps and bullet / // numbered-list markers share this offset mechanism. if (style.direction() == ParagraphStyle::RTL && (DropCmode || BulNumMode)) - current.glyphs[currentIndex].xoffset += style.parEffectOffset(); + current.glyphs[currentIndex].xoffset += parEffectExtraWidth; if (DropCmode) { Index: scribus/plugins/fileloader/scribus150format/scribus150format.cpp =================================================================== --- scribus/plugins/fileloader/scribus150format/scribus150format.cpp (revision 27703) +++ scribus/plugins/fileloader/scribus150format/scribus150format.cpp (working copy) @@ -3163,6 +3163,10 @@ if (attrs.hasAttribute(NumerationFormat)) newStyle.setNumFormat(attrs.valueAsInt(NumerationFormat)); + static const QString NumerationAlignment("NumerationAlignment"); + if (attrs.hasAttribute(NumerationAlignment)) + newStyle.setNumAlignment(static_cast(attrs.valueAsInt(NumerationAlignment))); + static const QString NumerationLevel("NumerationLevel"); if (attrs.hasAttribute(NumerationLevel)) newStyle.setNumLevel(attrs.valueAsInt(NumerationLevel)); @@ -5515,6 +5519,8 @@ pstyle.setNumName(attrs.valueAsString("NumerationName")); if (attrs.hasAttribute("NumerationFormat")) pstyle.setNumFormat(attrs.valueAsInt("NumerationFormat")); + if (attrs.hasAttribute("NumerationAlignment")) + pstyle.setNumAlignment(static_cast(attrs.valueAsInt("NumerationAlignment"))); if (attrs.hasAttribute("NumerationLevel")) pstyle.setNumLevel(attrs.valueAsInt("NumerationLevel")); if (attrs.hasAttribute("NumerationStart")) Index: scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp =================================================================== --- scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp (revision 27703) +++ scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp (working copy) @@ -856,6 +856,8 @@ docu.writeAttribute("Numeration", static_cast(style.hasNum())); if ( ! style.isInhNumFormat()) docu.writeAttribute("NumerationFormat", style.numFormat()); + if ( ! style.isInhNumAlignment()) + docu.writeAttribute("NumerationAlignment", static_cast(style.numAlignment())); if ( ! style.isInhNumName()) docu.writeAttribute("NumerationName", style.numName()); if ( ! style.isInhNumLevel()) Index: scribus/plugins/fileloader/scribus170format/scribus170format.cpp =================================================================== --- scribus/plugins/fileloader/scribus170format/scribus170format.cpp (revision 27703) +++ scribus/plugins/fileloader/scribus170format/scribus170format.cpp (working copy) @@ -3171,6 +3171,10 @@ if (attrs.hasAttribute(NumerationFormat)) newStyle.setNumFormat(attrs.valueAsInt(NumerationFormat)); + static const QString NumerationAlignment("NumerationAlignment"); + if (attrs.hasAttribute(NumerationAlignment)) + newStyle.setNumAlignment(static_cast(attrs.valueAsInt(NumerationAlignment))); + static const QString NumerationLevel("NumerationLevel"); if (attrs.hasAttribute(NumerationLevel)) newStyle.setNumLevel(attrs.valueAsInt(NumerationLevel)); @@ -5585,6 +5589,8 @@ pstyle.setNumName(attrs.valueAsString("NumerationName")); if (attrs.hasAttribute("NumerationFormat")) pstyle.setNumFormat(attrs.valueAsInt("NumerationFormat")); + if (attrs.hasAttribute("NumerationAlignment")) + pstyle.setNumAlignment(static_cast(attrs.valueAsInt("NumerationAlignment"))); if (attrs.hasAttribute("NumerationLevel")) pstyle.setNumLevel(attrs.valueAsInt("NumerationLevel")); if (attrs.hasAttribute("NumerationStart")) Index: scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp =================================================================== --- scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp (revision 27703) +++ scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp (working copy) @@ -858,6 +858,8 @@ docu.writeAttribute("Numeration", static_cast(style.hasNum())); if (!style.isInhNumFormat()) docu.writeAttribute("NumerationFormat", style.numFormat()); + if (!style.isInhNumAlignment()) + docu.writeAttribute("NumerationAlignment", static_cast(style.numAlignment())); if (!style.isInhNumName()) docu.writeAttribute("NumerationName", style.numName()); if (!style.isInhNumLevel()) Index: scribus/plugins/fileloader/scribus171format/scribus171format.cpp =================================================================== --- scribus/plugins/fileloader/scribus171format/scribus171format.cpp (revision 27703) +++ scribus/plugins/fileloader/scribus171format/scribus171format.cpp (working copy) @@ -3679,6 +3679,10 @@ if (attrs.hasAttribute(NumerationFormat)) newStyle.setNumFormat(attrs.valueAsInt(NumerationFormat)); + static const QString NumerationAlignment("NumerationAlignment"); + if (attrs.hasAttribute(NumerationAlignment)) + newStyle.setNumAlignment(static_cast(attrs.valueAsInt(NumerationAlignment))); + static const QString NumerationLevel("NumerationLevel"); if (attrs.hasAttribute(NumerationLevel)) newStyle.setNumLevel(attrs.valueAsInt(NumerationLevel)); @@ -6709,6 +6713,8 @@ pstyle.setNumName(attrs.valueAsString("NumerationName")); if (attrs.hasAttribute("NumerationFormat")) pstyle.setNumFormat(attrs.valueAsInt("NumerationFormat")); + if (attrs.hasAttribute("NumerationAlignment")) + pstyle.setNumAlignment(static_cast(attrs.valueAsInt("NumerationAlignment"))); if (attrs.hasAttribute("NumerationLevel")) pstyle.setNumLevel(attrs.valueAsInt("NumerationLevel")); if (attrs.hasAttribute("NumerationStart")) Index: scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp =================================================================== --- scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp (revision 27703) +++ scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp (working copy) @@ -860,6 +860,8 @@ docu.writeAttribute("Numeration", static_cast(style.hasNum())); if (!style.isInhNumFormat()) docu.writeAttribute("NumerationFormat", style.numFormat()); + if (!style.isInhNumAlignment()) + docu.writeAttribute("NumerationAlignment", static_cast(style.numAlignment())); if (!style.isInhNumName()) docu.writeAttribute("NumerationName", style.numName()); if (!style.isInhNumLevel()) Index: scribus/scribusdoc.cpp =================================================================== --- scribus/scribusdoc.cpp (revision 27703) +++ scribus/scribusdoc.cpp (working copy) @@ -9771,6 +9771,7 @@ auto *is = new ScOldNewState(Um::SetStyle); is->set("SET_PARASTYLE"); is->set("POS", pos); + is->set("PARA", static_cast(currItem->itemText.nrOfParagraph(pos))); is->setStates(currItem->itemText.paragraphStyle(pos), newStyle); m_undoManager->action(currItem, is); } @@ -9784,6 +9785,7 @@ auto *is = new ScOldNewState(Um::SetStyle); is->set("SET_PARASTYLE"); is->set("POS", stop); + is->set("PARA", static_cast(currItem->itemText.nrOfParagraph(stop))); is->setStates(currItem->itemText.paragraphStyle(stop), newStyle2); m_undoManager->action(currItem, is); } @@ -9956,6 +9958,7 @@ auto *is = new ScOldNewState(Um::SetStyle); is->set("APPLY_PARASTYLE"); is->set("POS", pos); + is->set("PARA", static_cast(currItem->itemText.nrOfParagraph(pos))); is->setStates(currItem->itemText.paragraphStyle(pos), newStyle); m_undoManager->action(currItem, is); } @@ -9967,6 +9970,7 @@ auto *is = new ScOldNewState(Um::SetStyle); is->set("APPLY_PARASTYLE"); is->set("POS", stop); + is->set("PARA", static_cast(currItem->itemText.nrOfParagraph(stop))); is->setStates(currItem->itemText.paragraphStyle(stop), newStyle); m_undoManager->action(currItem, is); } Index: scribus/styles/paragraphstyle.attrdefs.cxx =================================================================== --- scribus/styles/paragraphstyle.attrdefs.cxx (revision 27703) +++ scribus/styles/paragraphstyle.attrdefs.cxx (working copy) @@ -47,6 +47,7 @@ ATTRDEF(bool, hasNum, HasNum, false) ATTRDEF(QString, numName, NumName, "") ATTRDEF(int, numFormat, NumFormat, 0) +ATTRDEF(ParagraphStyle::NumAlignment, numAlignment, NumAlignment, ParagraphStyle::NumLeftAligned) ATTRDEF(QString, numPrefix, NumPrefix, "") ATTRDEF(QString, numSuffix, NumSuffix, ".") ATTRDEF(int, numLevel, NumLevel, 0) Index: scribus/styles/paragraphstyle.cpp =================================================================== --- scribus/styles/paragraphstyle.cpp (revision 27703) +++ scribus/styles/paragraphstyle.cpp (working copy) @@ -266,6 +266,11 @@ return QString::number(static_cast(val)); } +static QString toXMLString(ParagraphStyle::NumAlignment val) +{ + return QString::number(static_cast(val)); +} + static QString toXMLString(const QList & ) { return "dummy"; @@ -356,6 +361,12 @@ return parseEnum(str); } +template<> +ParagraphStyle::NumAlignment parse(const Xml_string& str) +{ + return parseEnum(str); +} + using Tablist = QList; Index: scribus/styles/paragraphstyle.h =================================================================== --- scribus/styles/paragraphstyle.h (revision 27703) +++ scribus/styles/paragraphstyle.h (working copy) @@ -50,6 +50,14 @@ RTL = 1 }; + enum NumAlignment + { + NumLeftAligned = 0, + NumCentered = 1, + NumRightAligned = 2, + NumSuffixAligned = 3 + }; + enum OpticalMarginType { OM_None = 0, Index: scribus/ui/propertywidget_pareffect.cpp =================================================================== --- scribus/ui/propertywidget_pareffect.cpp (revision 27703) +++ scribus/ui/propertywidget_pareffect.cpp (working copy) @@ -19,6 +19,7 @@ #include "scribusapp.h" #include "scribusdoc.h" #include "selection.h" +#include "styles/paragraphstyle.h" #include "util.h" PropertyWidget_ParEffect::PropertyWidget_ParEffect(QWidget *parent) : QFrame(parent) @@ -31,6 +32,7 @@ if (m_doc) peCharStyleCombo->updateStyleList(); fillBulletStrEditCombo(); + fillNumAlignmentCombo(); numStart->setMinimum(1); numStart->setMaximum(9999); @@ -185,6 +187,10 @@ stackedWidget->setVisible(true); peGroup->setVisible(true); } + + const bool isNumberedList = (id == 2); + numAlignmentLabel->setVisible(isNumberedList); + numAlignmentCombo->setVisible(isNumberedList); } void PropertyWidget_ParEffect::fillBulletStrEditCombo() @@ -198,6 +204,21 @@ bulletStrEdit->setEditText(QChar(0x2022)); } +void PropertyWidget_ParEffect::fillNumAlignmentCombo() +{ + QSignalBlocker sb(numAlignmentCombo); + const int currentData = numAlignmentCombo->currentData().toInt(); + numAlignmentCombo->clear(); + numAlignmentCombo->addItem(tr("Left"), static_cast(ParagraphStyle::NumLeftAligned)); + numAlignmentCombo->addItem(tr("Center"), static_cast(ParagraphStyle::NumCentered)); + numAlignmentCombo->addItem(tr("Right"), static_cast(ParagraphStyle::NumRightAligned)); + numAlignmentCombo->addItem(tr("Suffix"), static_cast(ParagraphStyle::NumSuffixAligned)); + int index = numAlignmentCombo->findData(currentData); + if (index < 0) + index = 0; + numAlignmentCombo->setCurrentIndex(index); +} + void PropertyWidget_ParEffect::fillPECombo() { QSignalBlocker sb(peCombo); @@ -229,8 +250,8 @@ QSignalBlocker blocker7(numPrefix); QSignalBlocker blocker8(numSuffix); QSignalBlocker blocker9(numStart); + QSignalBlocker blockerD(numAlignmentCombo); QSignalBlocker blockerA(peOffset); - QSignalBlocker blockerB(peIndent); QSignalBlocker blockerC(peCharStyleCombo); if (newPStyle.hasDropCap()) @@ -266,10 +287,13 @@ numPrefix->setText(newPStyle.numPrefix()); numSuffix->setText(newPStyle.numSuffix()); numStart->setValue(newPStyle.numStart()); + int numAlignmentIndex = numAlignmentCombo->findData(static_cast(newPStyle.numAlignment())); + if (numAlignmentIndex < 0) + numAlignmentIndex = 0; + numAlignmentCombo->setCurrentIndex(numAlignmentIndex); numFormatCombo->setCurrentFormat((NumFormat) newPStyle.numFormat()); peOffset->setValue(newPStyle.parEffectOffset() * m_unitRatio); - peIndent->setChecked(newPStyle.parEffectIndent()); showCharStyle(newPStyle.peCharStyleName()); if (oldPeComboIndex != peCombo->currentIndex()) @@ -284,11 +308,11 @@ connect(numComboBox, SIGNAL(textActivated(QString)), this, SLOT(handleNumName(QString)), Qt::UniqueConnection); connect(numLevelSpin, SIGNAL(valueChanged(int)), this, SLOT(handleNumLevel(int)), Qt::UniqueConnection); connect(numFormatCombo, SIGNAL(activated(int)), this, SLOT(handleNumFormat(int)), Qt::UniqueConnection); + connect(numAlignmentCombo, SIGNAL(activated(int)), this, SLOT(handleNumAlignment(int)), Qt::UniqueConnection); connect(numPrefix, SIGNAL(textChanged(QString)), this, SLOT(handleNumPrefix(QString)), Qt::UniqueConnection); connect(numSuffix, SIGNAL(textChanged(QString)), this, SLOT(handleNumSuffix(QString)), Qt::UniqueConnection); connect(numStart, SIGNAL(valueChanged(int)), this, SLOT(handleNumStart(int)), Qt::UniqueConnection); connect(peOffset, SIGNAL(valueChanged(double)), this, SLOT(handlePEOffset(double)), Qt::UniqueConnection); - connect(peIndent, SIGNAL(toggled(bool)), this, SLOT(handlePEIndent(bool)), Qt::UniqueConnection); connect(peCharStyleCombo, SIGNAL(newStyle(QString)), this, SLOT(handlePECharStyle(QString)), Qt::UniqueConnection); } @@ -300,11 +324,11 @@ disconnect(numComboBox, SIGNAL(textActivated(QString)), this, SLOT(handleNumName(QString))); disconnect(numLevelSpin, SIGNAL(valueChanged(int)), this, SLOT(handleNumLevel(int))); disconnect(numFormatCombo, SIGNAL(activated(int)), this, SLOT(handleNumFormat(int))); + disconnect(numAlignmentCombo, SIGNAL(activated(int)), this, SLOT(handleNumAlignment(int))); disconnect(numPrefix, SIGNAL(textChanged(QString)), this, SLOT(handleNumPrefix(QString))); disconnect(numSuffix, SIGNAL(textChanged(QString)), this, SLOT(handleNumSuffix(QString))); disconnect(numStart, SIGNAL(valueChanged(int)), this, SLOT(handleNumStart(int))); disconnect(peOffset, SIGNAL(valueChanged(double)), this, SLOT(handlePEOffset(double))); - disconnect(peIndent, SIGNAL(toggled(bool)), this, SLOT(handlePEIndent(bool))); disconnect(peCharStyleCombo, SIGNAL(newStyle(QString)), this, SLOT(handlePECharStyle(QString))); } @@ -387,6 +411,7 @@ newStyle.setHasNum(true); newStyle.setNumName(numComboBox->currentText()); newStyle.setNumFormat(numFormatCombo->currentFormat()); + newStyle.setNumAlignment(static_cast(numAlignmentCombo->currentData().toInt())); newStyle.setNumLevel(numLevelSpin->value() - 1); newStyle.setNumStart(numStart->value()); newStyle.setNumPrefix(numPrefix->text()); @@ -404,7 +429,6 @@ newStyle.setHasNum(false); } newStyle.setParEffectOffset(peOffset->value() / m_unitRatio); - newStyle.setParEffectIndent(peIndent->isChecked()); setType(peCombo->currentData().toInt()); @@ -519,30 +543,30 @@ handleChanges(m_item, newStyle); } -void PropertyWidget_ParEffect::handleNumStart(int start) +void PropertyWidget_ParEffect::handleNumAlignment(int) { if (!m_doc || !m_item) return; ParagraphStyle newStyle; - newStyle.setNumStart(start); + newStyle.setNumAlignment(static_cast(numAlignmentCombo->currentData().toInt())); handleChanges(m_item, newStyle); } -void PropertyWidget_ParEffect::handlePEOffset(double offset) +void PropertyWidget_ParEffect::handleNumStart(int start) { if (!m_doc || !m_item) return; ParagraphStyle newStyle; - newStyle.setParEffectOffset(offset / m_unitRatio); + newStyle.setNumStart(start); handleChanges(m_item, newStyle); } -void PropertyWidget_ParEffect::handlePEIndent(bool indent) +void PropertyWidget_ParEffect::handlePEOffset(double offset) { if (!m_doc || !m_item) return; ParagraphStyle newStyle; - newStyle.setParEffectIndent(indent); + newStyle.setParEffectOffset(offset / m_unitRatio); handleChanges(m_item, newStyle); } @@ -587,6 +611,7 @@ void PropertyWidget_ParEffect::languageChange() { fillPECombo(); + fillNumAlignmentCombo(); retranslateUi(this); } Index: scribus/ui/propertywidget_pareffect.h =================================================================== --- scribus/ui/propertywidget_pareffect.h (revision 27703) +++ scribus/ui/propertywidget_pareffect.h (working copy) @@ -64,9 +64,9 @@ void handleNumLevel(int); void handleNumPrefix(const QString&); void handleNumSuffix(const QString&); + void handleNumAlignment(int); void handleNumStart(int); void handlePEOffset(double); - void handlePEIndent(bool); void handlePECharStyle(const QString&); private slots: @@ -78,6 +78,7 @@ void closeEnhanced(bool show = false); void setType(int id); void fillBulletStrEditCombo(); + void fillNumAlignmentCombo(); void fillPECombo(); signals: Index: scribus/ui/propertywidget_pareffectbase.ui =================================================================== --- scribus/ui/propertywidget_pareffectbase.ui (revision 27703) +++ scribus/ui/propertywidget_pareffectbase.ui (working copy) @@ -371,6 +371,7 @@ + @@ -439,9 +440,25 @@ - + + + Align the generated list marker inside its marker area + - Auto-Indent + Marker alignment: + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + numAlignmentCombo + + + + + + + Use Suffix to align suffixes such as dots or parentheses in 1., 10., 100. @@ -557,7 +574,7 @@ numPrefix numSuffix peOffset - peIndent + numAlignmentCombo peCharStyleCombo dropCapLines bulletStrEdit Index: scribus/ui/smpstylewidget.cpp =================================================================== --- scribus/ui/smpstylewidget.cpp (revision 27703) +++ scribus/ui/smpstylewidget.cpp (working copy) @@ -6,6 +6,7 @@ */ #include +#include #include "iconmanager.h" @@ -13,6 +14,7 @@ #include "smpstylewidget.h" #include "scribus.h" #include "scribusapp.h" +#include "styles/paragraphstyle.h" #include "units.h" #include "util.h" #include "ui/charselectenhanced.h" @@ -70,6 +72,7 @@ numSuffix->setMaxLength(5); numSuffix->setMaximumWidth(QFontMetrics(numSuffix->font()).averageCharWidth() * 7); fillNumRestartCombo(); + fillNumAlignmentCombo(); dropCapLines->setMinimum(2); dropCapLines->setMaximum(99); @@ -152,6 +155,7 @@ int oldNumRestartIndex = numRestartCombo->currentIndex(); bool numRestartComboBlocked = numRestartCombo->blockSignals(true); fillNumRestartCombo(); + fillNumAlignmentCombo(); numRestartCombo->setCurrentIndex(oldNumRestartIndex); numRestartCombo->blockSignals(numRestartComboBlocked); @@ -303,8 +307,6 @@ parEffectOffset->setValue(pstyle->parEffectOffset() * unitRatio, pstyle->isInhParEffectOffset()); parEffectOffset->setParentValue(parent->parEffectOffset() * unitRatio); - parEffectIndentBox->setChecked(pstyle->parEffectIndent(),pstyle->isInhParEffectIndent()); - parEffectIndentBox->setParentValue(parent->parEffectIndent()); dropCapLines->setValue(pstyle->dropCapLines(), pstyle->isInhDropCapLines()); dropCapLines->setParentValue(parent->dropCapLines()); bulletStrEdit->setEditText(pstyle->bulletStr()); @@ -320,6 +322,8 @@ numComboBox->setParentItem(0); numFormatCombo->setCurrentFormat((NumFormat) pstyle->numFormat()); numFormatCombo->setParentFormat((NumFormat) parent->numFormat()); + numAlignmentCombo->setCurrentItemByData(static_cast(pstyle->numAlignment()), pstyle->isInhNumAlignment()); + numAlignmentCombo->setParentItem(numAlignmentCombo->getItemIndexForData(static_cast(parent->numAlignment()))); numLevelSpin->setValue(pstyle->numLevel() +1, pstyle->isInhNumLevel()); NumStruct * numS = m_Doc->numerations.value(pstyle->numName()); if (numS) @@ -356,7 +360,6 @@ maxGlyphExtSpin->setValue(pstyle->maxGlyphExtension() * 100.0); maxConsecutiveCountSpinBox->setValue(pstyle->hyphenConsecutiveLines()); parEffectOffset->setValue(pstyle->parEffectOffset() * unitRatio); - parEffectIndentBox->setChecked(pstyle->parEffectIndent()); parentParEffectsButton->hide(); disconnect(parentParEffectsButton, SIGNAL(clicked()), this, SLOT(slotParentParEffects())); @@ -369,6 +372,7 @@ numComboBox->setCurrentItem(numComboBox->findText(numName)); numNewLineEdit->clear(); numFormatCombo->setCurrentFormat((NumFormat) pstyle->numFormat()); + numAlignmentCombo->setCurrentItemByData(static_cast(pstyle->numAlignment())); numLevelSpin->setValue(pstyle->numLevel()+1); NumStruct * numS = m_Doc->numerations.value(pstyle->numName()); if (numS) @@ -981,6 +985,21 @@ numComboBox->setCurrentItem(0); } +void SMPStyleWidget::fillNumAlignmentCombo() +{ + QSignalBlocker sb(numAlignmentCombo); + int currentData = numAlignmentCombo->currentData().toInt(); + numAlignmentCombo->clear(); + numAlignmentCombo->addItem(tr("Left"), static_cast(ParagraphStyle::NumLeftAligned)); + numAlignmentCombo->addItem(tr("Center"), static_cast(ParagraphStyle::NumCentered)); + numAlignmentCombo->addItem(tr("Right"), static_cast(ParagraphStyle::NumRightAligned)); + numAlignmentCombo->addItem(tr("Suffix"), static_cast(ParagraphStyle::NumSuffixAligned)); + int index = numAlignmentCombo->findData(currentData); + if (index < 0) + index = 0; + numAlignmentCombo->setCurrentIndex(index); +} + void SMPStyleWidget::fillNumRestartCombo() { numRestartCombo->clear(); @@ -1013,6 +1032,10 @@ stackedWidget->setVisible(true); peGroup->setVisible(true); + const bool isNumberedList = (id == 3); + numAlignmentLabel->setVisible(isNumberedList); + numAlignmentCombo->setVisible(isNumberedList); + if (id == 2) // Bullet List { if (bulletStrEdit->currentText().isEmpty()) @@ -1029,6 +1052,8 @@ stackedWidget->setVisible(false); peGroup->setVisible(false); peCombo->setCurrentIndex(0); + numAlignmentLabel->setVisible(false); + numAlignmentCombo->setVisible(false); } } @@ -1095,6 +1120,16 @@ void SMPStyleWidget::showNumeration(const QList &pstyles, const QList &cstyles, int unitIndex) { + ParagraphStyle::NumAlignment alignment = pstyles[0]->numAlignment(); + for (int i = 0; i < pstyles.count(); ++i) + { + if (alignment != pstyles[i]->numAlignment()) + { + alignment = ParagraphStyle::NumLeftAligned; + break; + } + } + numAlignmentCombo->setCurrentItemByData(static_cast(alignment)); QString prefix = pstyles[0]->numPrefix(); for (int i = 0; i < pstyles.count(); ++i) Index: scribus/ui/smpstylewidget.h =================================================================== --- scribus/ui/smpstylewidget.h (revision 27703) +++ scribus/ui/smpstylewidget.h (working copy) @@ -50,6 +50,7 @@ void fillBulletStrEditCombo(); void fillNumerationsCombo(); + void fillNumAlignmentCombo(); void fillNumRestartCombo(); void fillPECombo(); void setParagraphEffect(int); Index: scribus/ui/smpstylewidget.ui =================================================================== --- scribus/ui/smpstylewidget.ui (revision 27703) +++ scribus/ui/smpstylewidget.ui (working copy) @@ -1476,6 +1476,7 @@ + @@ -1546,44 +1547,41 @@ - - - - 0 - 0 - - - - - - - true - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Hang Paragraph Effect before paragraph indent - - - Auto-Indent - - - - - + + + + 0 + 0 + + + + Align the generated list marker inside its marker area + + + Marker alignment: + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Use Suffix to align suffixes such as dots or parentheses in 1., 10., 100. + + + + + @@ -1792,7 +1790,7 @@ parentParEffectsButton dropCapLines parEffectOffset - parEffectIndentBox + numAlignmentCombo parEffectCharStyleCombo numPrefix numSuffix Index: scribus/ui/smtextstyles.cpp =================================================================== --- scribus/ui/smtextstyles.cpp (revision 27703) +++ scribus/ui/smtextstyles.cpp (working copy) @@ -511,12 +511,12 @@ connect(m_pwidget->peCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotPargraphEffects(int))); connect(m_pwidget->dropCapLines, SIGNAL(valueChanged(int)), this, SLOT(slotDropCapLines(int))); connect(m_pwidget->parEffectOffset, SIGNAL(valueChanged(double)), this, SLOT(slotParEffectOffset())); - connect(m_pwidget->parEffectIndentBox, SIGNAL(toggled(bool)), this, SLOT(slotParEffectIndent(bool))); connect(m_pwidget->parEffectCharStyleCombo, SIGNAL(activated(int)), this, SLOT(slotParEffectCharStyle(int))); connect(m_pwidget->bulletStrEdit, SIGNAL(editTextChanged(QString)), this, SLOT(slotBulletStr(QString))); connect(m_pwidget->numComboBox, SIGNAL(textActivated(QString)), this, SLOT(slotNumName(QString))); connect(m_pwidget->numLevelSpin, SIGNAL(valueChanged(int)), this, SLOT(slotNumLevel(int))); connect(m_pwidget->numFormatCombo, SIGNAL(activated(int)), this, SLOT(slotNumFormat(int))); + connect(m_pwidget->numAlignmentCombo, SIGNAL(activated(int)), this, SLOT(slotNumAlignment(int))); connect(m_pwidget->numStartSpin, SIGNAL(valueChanged(int)), this, SLOT(slotNumStart(int))); connect(m_pwidget->numRestartCombo, SIGNAL(activated(int)), this, SLOT(slotNumRestart(int))); connect(m_pwidget->numRestartOtherBox, SIGNAL(toggled(bool)), this, SLOT(slotNumOther(bool))); @@ -606,11 +606,11 @@ disconnect(m_pwidget->peCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotPargraphEffects(int))); disconnect(m_pwidget->dropCapLines, SIGNAL(valueChanged(int)), this, SLOT(slotDropCapLines(int))); disconnect(m_pwidget->parEffectOffset, SIGNAL(valueChanged(double)), this, SLOT(slotParEffectOffset())); - disconnect(m_pwidget->parEffectIndentBox, SIGNAL(toggled(bool)), this, SLOT(slotParEffectIndent(bool))); disconnect(m_pwidget->parEffectCharStyleCombo, SIGNAL(activated(int)), this, SLOT(slotParEffectCharStyle(int))); disconnect(m_pwidget->bulletStrEdit, SIGNAL(editTextChanged(QString)), this, SLOT(slotBulletStr(QString))); disconnect(m_pwidget->numComboBox, SIGNAL(textActivated(QString)), this, SLOT(slotNumName(QString))); disconnect(m_pwidget->numFormatCombo, SIGNAL(activated(int)), this, SLOT(slotNumFormat(int))); + disconnect(m_pwidget->numAlignmentCombo, SIGNAL(activated(int)), this, SLOT(slotNumAlignment(int))); disconnect(m_pwidget->numLevelSpin, SIGNAL(valueChanged(int)), this, SLOT(slotNumLevel(int))); disconnect(m_pwidget->numStartSpin, SIGNAL(valueChanged(int)), this, SLOT(slotNumStart(int))); disconnect(m_pwidget->numRestartCombo, SIGNAL(activated(int)), this, SLOT(slotNumRestart(int))); @@ -953,20 +953,6 @@ slotSelectionDirty(); } -void SMParagraphStyle::slotParEffectIndent(bool isOn) -{ - if (m_pwidget->parEffectIndentBox->useParentValue()) - for (int i = 0; i < m_selection.count(); ++i) - m_selection[i]->resetParEffectIndent(); - else - { - for (int i = 0; i < m_selection.count(); ++i) - m_selection[i]->setParEffectIndent(isOn); - } - - slotSelectionDirty(); -} - void SMParagraphStyle::slotParEffectCharStyle(int index) { QString name; @@ -1084,6 +1070,23 @@ } slotSelectionDirty(); +} + +void SMParagraphStyle::slotNumAlignment(int) +{ + if (m_pwidget->numAlignmentCombo->useParentValue()) + { + for (int i = 0; i < m_selection.count(); ++i) + m_selection[i]->resetNumAlignment(); + } + else + { + ParagraphStyle::NumAlignment alignment = static_cast(m_pwidget->numAlignmentCombo->currentData().toInt()); + for (int i = 0; i < m_selection.count(); ++i) + m_selection[i]->setNumAlignment(alignment); + } + + slotSelectionDirty(); } void SMParagraphStyle::slotNumLevel(int level) Index: scribus/ui/smtextstyles.h =================================================================== --- scribus/ui/smtextstyles.h (revision 27703) +++ scribus/ui/smtextstyles.h (working copy) @@ -77,13 +77,13 @@ void slotPargraphEffects(int index); void slotDropCapLines(int lines); void slotParEffectOffset(); - void slotParEffectIndent(bool); void slotParEffectCharStyle(int); void slotBulletStr(const QString &str); void slotNumName(const QString &str); void slotNumNew(); void slotSelectionDirty(); void slotNumFormat(int); + void slotNumAlignment(int); void slotNumLevel(int level); void slotNumPrefix(const QString &str); void slotNumSuffix(const QString &str); Index: scribus/ui/stylemanager.cpp =================================================================== --- scribus/ui/stylemanager.cpp (revision 27703) +++ scribus/ui/stylemanager.cpp (working copy) @@ -181,6 +181,35 @@ } } +void StyleManager::startup() +{ + setFontSize(); + if (!m_doc && !isModal()) + { + storeVisibility(false); + hide(); + emit paletteShown(false); + return; + } + + ScrPaletteBase::startup(); +} + +void StyleManager::setPaletteShown(bool visible) +{ + if (visible && !m_doc && !isModal()) + { + storeVisibility(false); + hide(); + emit paletteShown(false); + return; + } + + ScrPaletteBase::setPaletteShown(visible); + if (!visible) + emit paletteShown(false); +} + template ItemType* StyleManager::item() { @@ -254,6 +283,8 @@ deleteUnusedButton->setEnabled(hasDoc); m_rightClickPopup->setEnabled(hasDoc); m_newPopup->setEnabled(hasDoc); + if (!hasDoc && !isModal()) + setPaletteShown(false); if (m_doc && (m_doc != oldDoc) && this->isVisible()) connect(m_doc->m_Selection, SIGNAL(selectionChanged()), this, SLOT(slotDocSelectionChanged())); Index: scribus/ui/stylemanager.h =================================================================== --- scribus/ui/stylemanager.h (revision 27703) +++ scribus/ui/stylemanager.h (working copy) @@ -49,10 +49,12 @@ * document, and recreates the tree and associated shortcut actions. */ void reloadStyles(); + void startup(); QMap keyMap(); public slots: + void setPaletteShown(bool visible) override; void setDoc(ScribusDoc *doc); void languageChange(); void unitChange();