diff --git a/scribus/numeration.h b/scribus/numeration.h index 88857e0429..a3bad3aed5 100644 --- a/scribus/numeration.h +++ b/scribus/numeration.h @@ -77,6 +77,7 @@ struct NumStruct QString m_name; QList m_nums; QList m_counters; + QList m_maxCounters; // highest value m_counters ever reached, per level int m_lastlevel { -1 }; }; diff --git a/scribus/pageitem_textframe.cpp b/scribus/pageitem_textframe.cpp index 1c5b95c586..c95f693b0a 100644 --- a/scribus/pageitem_textframe.cpp +++ b/scribus/pageitem_textframe.cpp @@ -1075,6 +1075,152 @@ double calculateLineSpacing (const ParagraphStyle &style, PageItem *item) return style.lineSpacing(); } +static QString numListKey(const ParagraphStyle& style) +{ + return style.numName() + QLatin1Char('\x1f') + + QString::number(style.numFormat()) + QLatin1Char('\x1f') + + style.numPrefix() + QLatin1Char('\x1f') + + style.numSuffix() + QLatin1Char('\x1f') + + QString::number(style.numLevel()); +} +// Build the text a given count would produce for this list level. +// Pure string formatting — no document access, no shaping. +static QString candidateMarkerString(const ParagraphStyle& style, int count) +{ + Numeration num; + num.numFormat = static_cast(style.numFormat()); + QString result = style.numPrefix(); + result += num.numString(count); + result += style.numSuffix(); + return result; +} + +// Shape one or more short candidate strings through the real font/kerning +// path and return the widest rendered result. The candidates are synthetic +// (not real document text), so this never depends on itemText or frame chains. +static double shapeCandidateWidths(PageItem* item, const ParagraphStyle& style, const QStringList& candidates) +{ + StoryText probe(item->doc()); + for (const QString& candidate : candidates) + { + if (probe.length() > 0) + probe.insertChars(SpecialChars::PARSEP); + int pos = probe.length(); + probe.insertChars(candidate); + probe.applyStyle(pos, style); + probe.applyCharStyle(pos, candidate.length(), style.charStyle()); + } + + QList glyphClusters; + ShapedTextFeed feed(&probe, 0, item); + for (int i = 0; feed.haveMoreText(i, glyphClusters); ++i) + ; + + double maxWidth = 0.0, current = 0.0; + int prevA = -1; + for (const auto& glyph : as_const(glyphClusters)) + { + int a = glyph.firstChar(); + if (probe.isBlockStart(a) && a != prevA) + { + prevA = a; + maxWidth = qMax(maxWidth, current); + current = 0.0; + } + current += glyph.width(); + } + return qMax(maxWidth, current); +} +static double maxParagraphEffectWidthLegacyScan(PageItem* item, const QString& targetListKey) +{ + // Fallback only: used when counter data isn't available yet + // (e.g. numbering hasn't run for this list this pass). + ShapedTextFeed shapedText(&item->itemText, 0, item); + + QList glyphClusters; + for (int j = 0; shapedText.haveMoreText(j, glyphClusters); ++j) + ; + + double maxParEffectWidth = 0.0; + int prevA = -1; + + for (int j = 0; j < glyphClusters.count(); ++j) + { + int a = glyphClusters[j].firstChar(); + if (item->itemText.isBlockStart(a) && a != prevA) + { + prevA = a; + const ParagraphStyle& pStyle = item->itemText.paragraphStyle(a); + if (pStyle.hasNum() && numListKey(pStyle) == targetListKey) + { + double effectWidth = 0.0; + for (int k = j; k < glyphClusters.count(); ++k) + { + const auto& glyph = glyphClusters[k]; + if (glyph.firstChar() != a) + break; + effectWidth += glyph.width(); + } + + double totalWidth = pStyle.parEffectOffset() + effectWidth; + if (totalWidth > maxParEffectWidth) + maxParEffectWidth = totalWidth; + } + } + } + return maxParEffectWidth; +} + +static double maxParagraphEffectWidth(PageItem* item, const QString& targetListKey, const ParagraphStyle& style) +{ + QHash& sharedCache = item->itemText.maxParEffectWidthCache(); + auto cacheIt = sharedCache.constFind(targetListKey); + if (cacheIt != sharedCache.constEnd()) + return cacheIt.value(); + + ScribusDoc* doc = item->doc(); + NumStruct* numS = doc ? doc->numerations.value(style.numName(), nullptr) : nullptr; + int level = style.numLevel(); + + double result; + if (!numS || level < 0 || level >= numS->m_maxCounters.count()) + { + result = maxParagraphEffectWidthLegacyScan(item, targetListKey); + } + else + { + int maxCount = qMax(1, numS->m_maxCounters.at(level)); + auto fmt = static_cast(style.numFormat()); + + QStringList candidates; + if (fmt == Type_1_2_3 || fmt == Type_1_2_3_ar) + { + candidates << candidateMarkerString(style, maxCount); + } + else + { + int longestLen = -1; + for (int n = 1; n <= maxCount; ++n) + { + QString candidate = candidateMarkerString(style, n); + if (candidate.length() > longestLen) + { + longestLen = candidate.length(); + candidates.clear(); + candidates << candidate; + } + else if (candidate.length() == longestLen) + { + candidates << candidate; + } + } + } + result = style.parEffectOffset() + shapeCandidateWidths(item, style, candidates); + } + + sharedCache.insert(targetListKey, result); + return result; +} // This assumes that layout() ran on the previous page and set the incomplete* vars // It also clears the incomplete* vars, and changes the starting position for this frame @@ -1391,8 +1537,8 @@ void PageItem_TextFrame::layout() setMaxY(-1); double maxYAsc = 0.0, maxYDesc = 0.0; int regionMinY = 0, regionMaxY= 0; + QHash cachedMaxParEffectWidthByList; - double autoLeftIndent = 0.0; for (int i = 0; shapedText.haveMoreText(i, glyphClusters); ++i) { int currentIndex = i - current.lineData.firstCluster; @@ -1425,16 +1571,6 @@ void PageItem_TextFrame::layout() BulNumMode = false; if (itemText.isBlockStart(a)) { - if (currentIndex > 0) - { - int prevA = current.glyphs[currentIndex - 1].firstChar(); - if (a != prevA) - autoLeftIndent = 0.0; - } - else - { - autoLeftIndent = 0.0; - } style = itemText.paragraphStyle(a); if (style.hasBullet() || style.hasNum()) { @@ -1807,7 +1943,7 @@ void PageItem_TextFrame::layout() else { // LTR: Original behavior - current.leftIndent = style.leftMargin() + autoLeftIndent; + current.leftIndent = style.leftMargin(); if (itemText.isBlockStart(a)) { current.leftIndent += style.firstIndent(); @@ -1816,33 +1952,34 @@ void PageItem_TextFrame::layout() if (BulNumMode || DropCmode) { - if (style.parEffectIndent()) + double effectWidth = 0.0; + for (int j = i; shapedText.haveMoreText(j, glyphClusters); ++j) { - double effectWidth = 0.0; - for (int j = i; shapedText.haveMoreText(j, glyphClusters); ++j) - { - const auto & glyph = glyphClusters[j]; - if (glyph.firstChar() != a) - break; - effectWidth += glyph.width(); - } + const auto& glyph = glyphClusters[j]; + if (glyph.firstChar() != a) + break; + effectWidth += glyph.width(); + } + double indentAdjust = 0.0; + if (style.suffixAlignment() == ParagraphStyle::SuffixAlign_Right || + style.suffixAlignment() == ParagraphStyle::SuffixAlign_Center) + { + const QString listKey = numListKey(style); + if (!cachedMaxParEffectWidthByList.contains(listKey)) + cachedMaxParEffectWidthByList[listKey] = maxParagraphEffectWidth(this, listKey,style); - if (style.direction() == ParagraphStyle::RTL) - { - current.rightIndent -= style.parEffectOffset() + effectWidth; - if (current.rightIndent < 0.0) - current.rightIndent = 0.0; - } + double maxParEffectWidth = cachedMaxParEffectWidthByList.value(listKey); + + if (style.suffixAlignment() == ParagraphStyle::SuffixAlign_Right) + indentAdjust = style.parEffectOffset() + (effectWidth - maxParEffectWidth); else - { - current.leftIndent -= style.parEffectOffset() + effectWidth; - if (current.leftIndent < 0.0) - { - autoLeftIndent = abs(current.leftIndent); - current.leftIndent = 0.0; - } - } + indentAdjust = style.parEffectOffset() + (effectWidth - maxParEffectWidth) / 2.0; } + + if (style.direction() == ParagraphStyle::RTL) + current.rightIndent -= indentAdjust; + else + current.leftIndent -= indentAdjust; } // RTL drop-cap follow-lines: Constrain the available line width // from the right margin to prevent text overlapping the right-aligned drop cap. @@ -4937,6 +5074,7 @@ bool PageItem_TextFrame::checkKeyIsShortcut(QKeyEvent *k) void PageItem_TextFrame::updateBulletsNum() { + itemText.blockSignals(true); for (int index = 0; index < itemText.length(); ++index) { Mark* mark = itemText.mark(index); @@ -5032,7 +5170,7 @@ void PageItem_TextFrame::updateBulletsNum() } } - + itemText.blockSignals(false); m_Doc->updateNumbers(); } diff --git a/scribus/plugins/fileloader/scribus150format/scribus150format.cpp b/scribus/plugins/fileloader/scribus150format/scribus150format.cpp index 424ddcfbcc..763a573bad 100644 --- a/scribus/plugins/fileloader/scribus150format/scribus150format.cpp +++ b/scribus/plugins/fileloader/scribus150format/scribus150format.cpp @@ -3123,10 +3123,6 @@ void Scribus150Format::readParagraphStyle(ScribusDoc *doc, ScXmlStreamReader& re if (attrs.hasAttribute(ParagraphEffectOffset)) newStyle.setParEffectOffset(attrs.valueAsDouble(ParagraphEffectOffset)); - static const QString ParagraphEffectIndent("ParagraphEffectIndent"); - if (attrs.hasAttribute(ParagraphEffectIndent)) - newStyle.setParEffectIndent(attrs.valueAsDouble(ParagraphEffectIndent)); - static const QString DROP("DROP"); if (attrs.hasAttribute(DROP)) newStyle.setHasDropCap(static_cast(attrs.valueAsInt(DROP))); @@ -5497,8 +5493,6 @@ PageItem* Scribus150Format::pasteItem(ScribusDoc *doc, const ScXmlStreamAttribut pstyle.setPeCharStyleName(attrs.valueAsString("ParagraphEffectCharStyle")); if (attrs.hasAttribute("ParagraphEffectOffset")) pstyle.setParEffectOffset(attrs.valueAsDouble("ParagraphEffectOffset")); - if (attrs.hasAttribute("ParagraphEffectIndent")) - pstyle.setParEffectIndent(attrs.valueAsDouble("ParagraphEffectIndent")); if (attrs.hasAttribute("DROP")) pstyle.setHasDropCap(static_cast(attrs.valueAsInt("DROP"))); if (attrs.hasAttribute("DROPLIN")) diff --git a/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp b/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp index a6e7b4baaa..ffebaef127 100644 --- a/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp +++ b/scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp @@ -842,8 +842,6 @@ void Scribus150Format::putPStyle(ScXmlStreamWriter & docu, const ParagraphStyle docu.writeAttribute("ParagraphEffectCharStyle", style.peCharStyleName()); if ( ! style.isInhParEffectOffset()) docu.writeAttribute("ParagraphEffectOffset", style.parEffectOffset()); - if ( ! style.isInhParEffectIndent()) - docu.writeAttribute("ParagraphEffectIndent", static_cast(style.parEffectIndent())); if ( ! style.isInhHasDropCap()) docu.writeAttribute("DROP", static_cast(style.hasDropCap())); if ( ! style.isInhDropCapLines()) diff --git a/scribus/plugins/fileloader/scribus170format/scribus170format.cpp b/scribus/plugins/fileloader/scribus170format/scribus170format.cpp index c18650807f..a08b063961 100644 --- a/scribus/plugins/fileloader/scribus170format/scribus170format.cpp +++ b/scribus/plugins/fileloader/scribus170format/scribus170format.cpp @@ -3131,10 +3131,6 @@ void Scribus170Format::readParagraphStyle(ScribusDoc *doc, ScXmlStreamReader& re if (attrs.hasAttribute(ParagraphEffectOffset)) newStyle.setParEffectOffset(attrs.valueAsDouble(ParagraphEffectOffset)); - static const QString ParagraphEffectIndent("ParagraphEffectIndent"); - if (attrs.hasAttribute(ParagraphEffectIndent)) - newStyle.setParEffectIndent(attrs.valueAsDouble(ParagraphEffectIndent)); - static const QString DROP("DROP"); if (attrs.hasAttribute(DROP)) newStyle.setHasDropCap(static_cast(attrs.valueAsInt(DROP))); @@ -5567,8 +5563,6 @@ PageItem* Scribus170Format::pasteItem(ScribusDoc *doc, const ScXmlStreamAttribut pstyle.setPeCharStyleName(attrs.valueAsString("ParagraphEffectCharStyle")); if (attrs.hasAttribute("ParagraphEffectOffset")) pstyle.setParEffectOffset(attrs.valueAsDouble("ParagraphEffectOffset")); - if (attrs.hasAttribute("ParagraphEffectIndent")) - pstyle.setParEffectIndent(attrs.valueAsDouble("ParagraphEffectIndent")); if (attrs.hasAttribute("DROP")) pstyle.setHasDropCap(static_cast(attrs.valueAsInt("DROP"))); if (attrs.hasAttribute("DROPLIN")) diff --git a/scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp b/scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp index 3b7a5ec1ca..1e8c88068e 100644 --- a/scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp +++ b/scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp @@ -844,8 +844,6 @@ void Scribus170Format::putPStyle(ScXmlStreamWriter & docu, const ParagraphStyle docu.writeAttribute("ParagraphEffectCharStyle", style.peCharStyleName()); if (!style.isInhParEffectOffset()) docu.writeAttribute("ParagraphEffectOffset", style.parEffectOffset()); - if (!style.isInhParEffectIndent()) - docu.writeAttribute("ParagraphEffectIndent", static_cast(style.parEffectIndent())); if (!style.isInhHasDropCap()) docu.writeAttribute("DROP", static_cast(style.hasDropCap())); if (!style.isInhDropCapLines()) diff --git a/scribus/plugins/fileloader/scribus171format/scribus171format.cpp b/scribus/plugins/fileloader/scribus171format/scribus171format.cpp index 6c96651fbf..a1372df7fb 100644 --- a/scribus/plugins/fileloader/scribus171format/scribus171format.cpp +++ b/scribus/plugins/fileloader/scribus171format/scribus171format.cpp @@ -3635,10 +3635,6 @@ void Scribus171Format::readParagraphStyle(ScribusDoc *doc, ScXmlStreamReader& re if (attrs.hasAttribute(ParagraphEffectOffset)) newStyle.setParEffectOffset(attrs.valueAsDouble(ParagraphEffectOffset)); - static const QString ParagraphEffectIndent("ParagraphEffectIndent"); - if (attrs.hasAttribute(ParagraphEffectIndent)) - newStyle.setParEffectIndent(attrs.valueAsDouble(ParagraphEffectIndent)); - //Remove uppercase in 1.8 format if (attrs.hasAttribute("DROP")) newStyle.setHasDropCap(static_cast(attrs.valueAsInt("DROP"))); @@ -3695,6 +3691,10 @@ void Scribus171Format::readParagraphStyle(ScribusDoc *doc, ScXmlStreamReader& re if (attrs.hasAttribute(NumerationSuffix)) newStyle.setNumSuffix(attrs.valueAsString(NumerationSuffix)); + static const QString SuffixAlignment("SuffixAlignment"); + if (attrs.hasAttribute(SuffixAlignment)) + newStyle.setSuffixAlignment(static_cast(attrs.valueAsInt(SuffixAlignment))); + static const QString NumerationRestart("NumerationRestart"); if (attrs.hasAttribute(NumerationRestart)) newStyle.setNumRestart(attrs.valueAsInt(NumerationRestart)); @@ -6679,8 +6679,6 @@ PageItem* Scribus171Format::pasteItem(ScribusDoc *doc, const ScXmlStreamAttribut pstyle.setPeCharStyleName(attrs.valueAsString("ParagraphEffectCharStyle")); if (attrs.hasAttribute("ParagraphEffectOffset")) pstyle.setParEffectOffset(attrs.valueAsDouble("ParagraphEffectOffset")); - if (attrs.hasAttribute("ParagraphEffectIndent")) - pstyle.setParEffectIndent(attrs.valueAsDouble("ParagraphEffectIndent")); //Remove uppercase in 1.8 if (attrs.hasAttribute("DROP")) pstyle.setHasDropCap(static_cast(attrs.valueAsInt("DROP"))); @@ -6717,6 +6715,8 @@ PageItem* Scribus171Format::pasteItem(ScribusDoc *doc, const ScXmlStreamAttribut pstyle.setNumPrefix(attrs.valueAsString("NumerationPrefix")); if (attrs.hasAttribute("NumerationSuffix")) pstyle.setNumSuffix(attrs.valueAsString("NumerationSuffix")); + if (attrs.hasAttribute("SuffixAlignment")) + pstyle.setSuffixAlignment(static_cast(attrs.valueAsInt("SuffixAlignment"))); if (attrs.hasAttribute("NumerationRestart")) { NumerationRange numRange = (NumerationRange) attrs.valueAsInt("NumerationRestart"); diff --git a/scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp b/scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp index ae959bec6f..2608bc355f 100644 --- a/scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp +++ b/scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp @@ -846,8 +846,6 @@ void Scribus171Format::putPStyle(ScXmlStreamWriter & docu, const ParagraphStyle docu.writeAttribute("ParagraphEffectCharStyle", style.peCharStyleName()); if (!style.isInhParEffectOffset()) docu.writeAttribute("ParagraphEffectOffset", style.parEffectOffset()); - if (!style.isInhParEffectIndent()) - docu.writeAttribute("ParagraphEffectIndent", static_cast(style.parEffectIndent())); if (!style.isInhHasDropCap()) docu.writeAttribute("HasDropCap", static_cast(style.hasDropCap())); if (!style.isInhDropCapLines()) @@ -868,6 +866,8 @@ void Scribus171Format::putPStyle(ScXmlStreamWriter & docu, const ParagraphStyle docu.writeAttribute("NumerationPrefix", style.numPrefix()); if (!style.isInhNumSuffix()) docu.writeAttribute("NumerationSuffix", style.numSuffix()); + if (!style.isInhSuffixAlignment()) + docu.writeAttribute("SuffixAlignment", style.suffixAlignment()); if (!style.isInhNumStart()) docu.writeAttribute("NumerationStart", style.numStart()); if (!style.isInhNumRestart()) diff --git a/scribus/scribusdoc.cpp b/scribus/scribusdoc.cpp index c55f7634fe..6442091bd9 100644 --- a/scribus/scribusdoc.cpp +++ b/scribus/scribusdoc.cpp @@ -17731,6 +17731,11 @@ void ScribusDoc::setNumerationCounter(const QString& numName, int level, int num numS->m_counters.insert(level, number); else numS->m_counters.replace(level, number); + + while (numS->m_maxCounters.count() <= level) + numS->m_maxCounters.append(0); + if (number > numS->m_maxCounters.at(level)) + numS->m_maxCounters.replace(level, number); } int ScribusDoc::updateLocalNums(StoryText& itemText) @@ -17738,7 +17743,7 @@ int ScribusDoc::updateLocalNums(StoryText& itemText) int firstInvalidChar = -1; QVector nums; QList counters; - + itemText.blockSignals(true); for (int pos = 0; pos < itemText.length(); ++pos) { if (pos != 0 && itemText.text(pos - 1) != SpecialChars::PARSEP) @@ -17818,6 +17823,7 @@ int ScribusDoc::updateLocalNums(StoryText& itemText) firstInvalidChar = pos; } } + itemText.blockSignals(false); return firstInvalidChar; } @@ -17901,7 +17907,6 @@ void ScribusDoc::updateNumbers(bool updateNumerations) if (item->itemText.length() <= 0) continue; int firstInvalidChar1 = -1; - while (pos < item->itemText.length()) { if ((pos == 0) || (item->itemText.text(pos - 1) == SpecialChars::PARSEP)) @@ -17957,7 +17962,6 @@ void ScribusDoc::updateNumbers(bool updateNumerations) pos = item->itemText.nextParagraph(pos) + 1; } } - // Update local numbering int firstInvalidChar2 = updateLocalNums(item->itemText); diff --git a/scribus/styles/paragraphstyle.attrdefs.cxx b/scribus/styles/paragraphstyle.attrdefs.cxx index 238e71a5cf..bbd0c05251 100644 --- a/scribus/styles/paragraphstyle.attrdefs.cxx +++ b/scribus/styles/paragraphstyle.attrdefs.cxx @@ -40,7 +40,6 @@ ATTRDEF(bool, keepTogether, KeepTogether, false) ATTRDEF(bool, hasDropCap, HasDropCap, false) ATTRDEF(int, dropCapLines, DropCapLines, 2) ATTRDEF(double, parEffectOffset, ParEffectOffset, 0.0) -ATTRDEF(bool, parEffectIndent, ParEffectIndent, false) ATTRDEF(QString, peCharStyleName, PeCharStyleName,"") ATTRDEF(bool, hasBullet, HasBullet, false) ATTRDEF(QString, bulletStr, BulletStr, QString(QChar(0x2022))) @@ -54,6 +53,7 @@ ATTRDEF(int, numStart, NumStart, 1) ATTRDEF(int, numRestart, NumRestart, 0) ATTRDEF(bool, numOther, NumOther, false) ATTRDEF(bool, numHigher, NumHigher, true) +ATTRDEF(ParagraphStyle::SuffixAlignment, suffixAlignment, SuffixAlignment, ParagraphStyle::SuffixAlign_Left) ATTRDEF(QString, backgroundColor, BackgroundColor, "None") ATTRDEF(double, backgroundShade, BackgroundShade, 100) ATTRDEF(int, hyphenConsecutiveLines, HyphenConsecutiveLines, 2) diff --git a/scribus/styles/paragraphstyle.cpp b/scribus/styles/paragraphstyle.cpp index f182104f34..9384ef24e5 100644 --- a/scribus/styles/paragraphstyle.cpp +++ b/scribus/styles/paragraphstyle.cpp @@ -208,6 +208,14 @@ void ParagraphStyle::setStyle(const ParagraphStyle & other) #undef ATTRDEF } +ParagraphStyle::SuffixAlignment ParagraphStyle::flipSuffixAlignmentForRTL(SuffixAlignment align) const +{ + if (align == ParagraphStyle::SuffixAlign_Left) + return ParagraphStyle::SuffixAlign_Right; + if (align == ParagraphStyle::SuffixAlign_Right) + return ParagraphStyle::SuffixAlign_Left; + return align; +} void ParagraphStyle::getNamedResources(ResourceCollection& lists) const { @@ -261,6 +269,11 @@ static QString toXMLString(ParagraphStyle::AlignmentType val) return QString::number(static_cast(val)); } +static QString toXMLString(ParagraphStyle::SuffixAlignment val) +{ + return QString::number(static_cast(val)); +} + static QString toXMLString(ParagraphStyle::DirectionType val) { return QString::number(static_cast(val)); @@ -344,6 +357,12 @@ ParagraphStyle::AlignmentType parse(const Xml_str return parseEnum(str); } +template<> +ParagraphStyle::SuffixAlignment parse(const Xml_string& str) +{ + return parseEnum(str); +} + template<> ParagraphStyle::DirectionType parse(const Xml_string& str) { diff --git a/scribus/styles/paragraphstyle.h b/scribus/styles/paragraphstyle.h index 4e5bac2a12..2f83037918 100644 --- a/scribus/styles/paragraphstyle.h +++ b/scribus/styles/paragraphstyle.h @@ -76,6 +76,13 @@ public: CenterTab = 4 }; + enum SuffixAlignment + { + SuffixAlign_Left = 0, + SuffixAlign_Center = 1, + SuffixAlign_Right = 2 + }; + struct TabRecord { qreal tabPosition {0.0}; @@ -113,6 +120,7 @@ public: void eraseStyle(const ParagraphStyle& other); void setStyle(const ParagraphStyle& other); void erase() override { eraseStyle(*this); } + ParagraphStyle::SuffixAlignment flipSuffixAlignmentForRTL(ParagraphStyle::SuffixAlignment align) const; StyleContext* charStyleContext() { return & m_cstyleContext; } const StyleContext* charStyleContext() const { return & m_cstyleContext; } diff --git a/scribus/text/sctext_shared.cpp b/scribus/text/sctext_shared.cpp index d984c79019..03ecc35b12 100644 --- a/scribus/text/sctext_shared.cpp +++ b/scribus/text/sctext_shared.cpp @@ -68,6 +68,9 @@ void ScText_Shared::clear() if (marksCount > 0) marksCountChanged = true; marksCount = 0; + maxParEffectWidthCache.clear(); + cachedPlainText.clear(); + maxParEffectWidthCache.clear(); } ScText_Shared& ScText_Shared::operator= (const ScText_Shared& other) diff --git a/scribus/text/sctext_shared.h b/scribus/text/sctext_shared.h index d16bd8267a..d22c0f7316 100644 --- a/scribus/text/sctext_shared.h +++ b/scribus/text/sctext_shared.h @@ -2,6 +2,7 @@ #define SCTEXT_SHARED_H #include +#include #include #include #include @@ -35,6 +36,13 @@ public: ParagraphStyle trailingStyle; CharStyle orphanedCharStyle; + /// max list-marker width per list key, shared by every frame in the chain; + /// cleared whenever text or styles change + QHash maxParEffectWidthCache; + + mutable QString cachedPlainText; + mutable bool plainTextValid = false; + void clear(); /** diff --git a/scribus/text/storytext.cpp b/scribus/text/storytext.cpp index 4214bb583e..58793910a0 100644 --- a/scribus/text/storytext.cpp +++ b/scribus/text/storytext.cpp @@ -27,7 +27,6 @@ pageitem.cpp - description //FIXME: this include must go to sctextstruct.h ! #include #include //added to make Fedora-5 happy - #include "notesstyles.h" #include "scribusdoc.h" #include "sctext_shared.h" @@ -699,6 +698,7 @@ void StoryText::removeChars(int pos, uint len) d->selFirst = 0; d->selLast = -1; } + d->plainTextValid = false; invalidate(pos, length()); } @@ -773,6 +773,7 @@ void StoryText::insertChars(int pos, const QString& txt, bool applyNeighbourStyl d->len = d->count(); if ((d->selLast >= d->selFirst) && (d->selFirst <= pos) && (pos <= d->selLast)) d->selLast += txt.length(); + d->plainTextValid = false; invalidate(pos, pos + txt.length()); } @@ -833,6 +834,7 @@ void StoryText::insertCharsWithSoftHyphens(int pos, const QString& txt, bool app d->len = d->count(); if ((d->selLast >= d->selFirst) && (d->selFirst <= pos) && (pos <= d->selLast)) d->selLast += inserted; + d->plainTextValid = false; invalidate(pos, pos + inserted); } @@ -860,7 +862,7 @@ void StoryText::replaceChar(int pos, QChar ch) if (oldMarksCount != d->marksCount) d->marksCountChanged = true; - + d->plainTextValid = false; invalidate(pos, pos + 1); } @@ -1023,6 +1025,8 @@ QString StoryText::plainText() const { if (length() <= 0) return QString(); + if (d->plainTextValid) + return d->cachedPlainText; QChar ch; QString result; @@ -1037,7 +1041,8 @@ QString StoryText::plainText() const ch = QLatin1Char('\n'); result += ch; } - + d->cachedPlainText = result; + d->plainTextValid = true; return result; } #if 0 @@ -1391,6 +1396,11 @@ void StoryText::clearFlag(int pos, LayoutFlags flags) d->at(pos)->setEffects(~(flags & ScStyle_NonUserStyles) & d->at(pos)->effects().value); } +QHash &StoryText::maxParEffectWidthCache() +{ + return d->maxParEffectWidthCache; +} + const CharStyle & StoryText::charStyle() const { @@ -2261,6 +2271,10 @@ void StoryText::invalidate(int firstItem, int endItem) if (par) par->charStyleContext()->invalidate(); } + // a list marker's max width can depend on any character in the story, + // so any edit can change it; drop the whole cache to stay safe + d->maxParEffectWidthCache.clear(); + if (!signalsBlocked()) emit changed(firstItem, endItem); } diff --git a/scribus/text/storytext.h b/scribus/text/storytext.h index 7920d56aba..9aaf6effed 100644 --- a/scribus/text/storytext.h +++ b/scribus/text/storytext.h @@ -29,6 +29,7 @@ pageitem.cpp - description #include #include #include +#include #include #include "itextsource.h" @@ -290,6 +291,10 @@ public: void setFlag(int pos, LayoutFlags flag) override; void clearFlag(int pos, LayoutFlags flag) override; + /// cache of max list-marker width per list key; shared across every + /// frame referencing this story, invalidated on any edit + QHash& maxParEffectWidthCache(); + // when physical view doesn't match logical view any more: /// call this if the shape of an embedded object changes (redos layout) diff --git a/scribus/ui/propertywidget_pareffect.cpp b/scribus/ui/propertywidget_pareffect.cpp index 0e6ef1e520..1a3701ea52 100644 --- a/scribus/ui/propertywidget_pareffect.cpp +++ b/scribus/ui/propertywidget_pareffect.cpp @@ -45,6 +45,10 @@ PropertyWidget_ParEffect::PropertyWidget_ParEffect(QWidget *parent) : QFrame(par peCombo->setCurrentIndex(0); setType(peCombo->currentData().toInt()); + suffixAlignmentCombo->addItem(tr("Left"), ParagraphStyle::SuffixAlign_Left); + suffixAlignmentCombo->addItem(tr("Center"), ParagraphStyle::SuffixAlign_Center); + suffixAlignmentCombo->addItem(tr("Right"), ParagraphStyle::SuffixAlign_Right); + iconSetChange(); connect(ScQApp, SIGNAL(iconSetChanged()), this, SLOT(iconSetChange())); @@ -185,6 +189,9 @@ void PropertyWidget_ParEffect::setType(int id) stackedWidget->setVisible(true); peGroup->setVisible(true); } + bool isNumberedList = (id == 2); + suffixAlignmentLabel->setVisible(isNumberedList); + suffixAlignmentCombo->setVisible(isNumberedList); } void PropertyWidget_ParEffect::fillBulletStrEditCombo() @@ -230,8 +237,8 @@ void PropertyWidget_ParEffect::updateStyle(const ParagraphStyle& newPStyle) QSignalBlocker blocker8(numSuffix); QSignalBlocker blocker9(numStart); QSignalBlocker blockerA(peOffset); - QSignalBlocker blockerB(peIndent); QSignalBlocker blockerC(peCharStyleCombo); + QSignalBlocker blockerD(suffixAlignmentCombo); if (newPStyle.hasDropCap()) { @@ -269,9 +276,16 @@ void PropertyWidget_ParEffect::updateStyle(const ParagraphStyle& newPStyle) numFormatCombo->setCurrentFormat((NumFormat) newPStyle.numFormat()); peOffset->setValue(newPStyle.parEffectOffset() * m_unitRatio); - peIndent->setChecked(newPStyle.parEffectIndent()); showCharStyle(newPStyle.peCharStyleName()); + ParagraphStyle::SuffixAlignment displayAlign = newPStyle.suffixAlignment(); + if (newPStyle.direction() == ParagraphStyle::RTL) + displayAlign = newPStyle.flipSuffixAlignmentForRTL(displayAlign); + + int idx = suffixAlignmentCombo->findData(static_cast(displayAlign)); + if (idx >= 0) + suffixAlignmentCombo->setCurrentIndex(idx); + if (oldPeComboIndex != peCombo->currentIndex()) emit needsRelayout(); } @@ -288,7 +302,7 @@ void PropertyWidget_ParEffect::connectSignals() 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(suffixAlignmentCombo, SIGNAL(activated(int)), this, SLOT(handleSuffixAlignment(int)), Qt::UniqueConnection); connect(peCharStyleCombo, SIGNAL(newStyle(QString)), this, SLOT(handlePECharStyle(QString)), Qt::UniqueConnection); } @@ -304,7 +318,7 @@ void PropertyWidget_ParEffect::disconnectSignals() 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(suffixAlignmentCombo, SIGNAL(activated(int)), this, SLOT(handleSuffixAlignment(int))); disconnect(peCharStyleCombo, SIGNAL(newStyle(QString)), this, SLOT(handlePECharStyle(QString))); } @@ -403,8 +417,6 @@ void PropertyWidget_ParEffect::handleParEffectUse() newStyle.setHasBullet(false); newStyle.setHasNum(false); } - newStyle.setParEffectOffset(peOffset->value() / m_unitRatio); - newStyle.setParEffectIndent(peIndent->isChecked()); setType(peCombo->currentData().toInt()); @@ -537,12 +549,15 @@ void PropertyWidget_ParEffect::handlePEOffset(double offset) handleChanges(m_item, newStyle); } -void PropertyWidget_ParEffect::handlePEIndent(bool indent) +void PropertyWidget_ParEffect::handleSuffixAlignment(int index) { if (!m_doc || !m_item) return; ParagraphStyle newStyle; - newStyle.setParEffectIndent(indent); + auto align = static_cast(suffixAlignmentCombo->itemData(index).toInt()); + if (m_item->currentStyle().direction() == ParagraphStyle::RTL) + align = newStyle.flipSuffixAlignmentForRTL(align); + newStyle.setSuffixAlignment(align); handleChanges(m_item, newStyle); } diff --git a/scribus/ui/propertywidget_pareffect.h b/scribus/ui/propertywidget_pareffect.h index 62729f7c28..54d2aeab46 100644 --- a/scribus/ui/propertywidget_pareffect.h +++ b/scribus/ui/propertywidget_pareffect.h @@ -66,7 +66,7 @@ public slots: void handleNumSuffix(const QString&); void handleNumStart(int); void handlePEOffset(double); - void handlePEIndent(bool); + void handleSuffixAlignment(int); void handlePECharStyle(const QString&); private slots: diff --git a/scribus/ui/propertywidget_pareffectbase.ui b/scribus/ui/propertywidget_pareffectbase.ui index 1a2670a01a..fa21acf2e1 100644 --- a/scribus/ui/propertywidget_pareffectbase.ui +++ b/scribus/ui/propertywidget_pareffectbase.ui @@ -438,10 +438,17 @@ - - + + - Auto-Indent + Suffix Align: + + + + + + + Alignment of suffix characters in numbered lists @@ -556,8 +563,8 @@ numStart numPrefix numSuffix - peOffset - peIndent +peOffset + suffixAlignmentCombo peCharStyleCombo dropCapLines bulletStrEdit diff --git a/scribus/ui/smpstylewidget.cpp b/scribus/ui/smpstylewidget.cpp index 12fde44283..d5e0fc6261 100644 --- a/scribus/ui/smpstylewidget.cpp +++ b/scribus/ui/smpstylewidget.cpp @@ -25,7 +25,6 @@ static bool isEqual(double a, double b) return al == bl; } - SMPStyleWidget::SMPStyleWidget(ScribusDoc* doc, StyleSet *cstyles) : m_Doc(doc), m_cstyles(cstyles) @@ -74,6 +73,7 @@ SMPStyleWidget::SMPStyleWidget(ScribusDoc* doc, StyleSet *cstyles) : dropCapLines->setMaximum(99); fillPECombo(); + fillSuffixAlignmentCombo(); connect(peCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(handleParEffectUse(int))); connect(parentParEffectsButton, SIGNAL(clicked()), this, SLOT(slotParentParEffects())); @@ -156,7 +156,7 @@ void SMPStyleWidget::languageChange() numRestartCombo->blockSignals(numRestartComboBlocked); fillPECombo(); - + fillSuffixAlignmentCombo(); backgroundColor->colorButton->setPersistentToolTip( tr("Background color of selected text")); backgroundColor->setText(tr("Background")); } @@ -303,8 +303,19 @@ void SMPStyleWidget::show(ParagraphStyle *pstyle, QList &pstyles parEffectOffset->setValue(pstyle->parEffectOffset() * unitRatio, pstyle->isInhParEffectOffset()); parEffectOffset->setParentValue(parent->parEffectOffset() * unitRatio); - parEffectIndentBox->setChecked(pstyle->parEffectIndent(),pstyle->isInhParEffectIndent()); - parEffectIndentBox->setParentValue(parent->parEffectIndent()); + + ParagraphStyle::SuffixAlignment displayAlign = pstyle->suffixAlignment(); + if (pstyle->direction() == ParagraphStyle::RTL) + displayAlign = pstyle->flipSuffixAlignmentForRTL(displayAlign); + + ParagraphStyle::SuffixAlignment parentDisplayAlign = parent->suffixAlignment(); + if (parent->direction() == ParagraphStyle::RTL) + parentDisplayAlign = pstyle->flipSuffixAlignmentForRTL(parentDisplayAlign); + + int suffixAlignIndex = suffixAlignmentCombo->findData(static_cast(displayAlign)); + suffixAlignmentCombo->setCurrentItem(suffixAlignIndex, pstyle->isInhSuffixAlignment()); + suffixAlignmentCombo->setParentItem(suffixAlignmentCombo->findData(static_cast(parentDisplayAlign))); + dropCapLines->setValue(pstyle->dropCapLines(), pstyle->isInhDropCapLines()); dropCapLines->setParentValue(parent->dropCapLines()); bulletStrEdit->setEditText(pstyle->bulletStr()); @@ -356,10 +367,13 @@ void SMPStyleWidget::show(ParagraphStyle *pstyle, QList &pstyles 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())); + ParagraphStyle::SuffixAlignment displayAlign = pstyle->suffixAlignment(); + if (pstyle->direction() == ParagraphStyle::RTL) + displayAlign = pstyle->flipSuffixAlignmentForRTL(displayAlign); + + int suffixAlignIndex = suffixAlignmentCombo->findData(static_cast(displayAlign)); + suffixAlignmentCombo->setCurrentItem((suffixAlignIndex >= 0) ? suffixAlignIndex : 0); dropCapLines->setValue(pstyle->dropCapLines()); bulletStrEdit->setEditText(pstyle->bulletStr()); setWidgetBoldFont(bulletCharLabel, false); @@ -1000,6 +1014,17 @@ void SMPStyleWidget::fillPECombo() peCombo->setCurrentIndex(currIndex); } +void SMPStyleWidget::fillSuffixAlignmentCombo() +{ + QSignalBlocker sb(suffixAlignmentCombo); + int currIndex = suffixAlignmentCombo->currentIndex(); + suffixAlignmentCombo->clear(); + suffixAlignmentCombo->addItem(tr("Left"), ParagraphStyle::SuffixAlign_Left); + suffixAlignmentCombo->addItem(tr("Center"), ParagraphStyle::SuffixAlign_Center); + suffixAlignmentCombo->addItem(tr("Right"), ParagraphStyle::SuffixAlign_Right); + suffixAlignmentCombo->setCurrentIndex(currIndex); +} + void SMPStyleWidget::setParagraphEffect(int index) { QSignalBlocker sigPECombo(peCombo); @@ -1030,6 +1055,9 @@ void SMPStyleWidget::setParagraphEffect(int index) peGroup->setVisible(false); peCombo->setCurrentIndex(0); } + bool isNumberedList = (id == 3); + suffixAlignmentLabel->setVisible(isNumberedList); + suffixAlignmentCombo->setVisible(isNumberedList); } void SMPStyleWidget::showDropCap(const QList &pstyles, const QList &cstyles, int unitIndex) diff --git a/scribus/ui/smpstylewidget.h b/scribus/ui/smpstylewidget.h index c985d7033b..4cb5c88bd9 100644 --- a/scribus/ui/smpstylewidget.h +++ b/scribus/ui/smpstylewidget.h @@ -52,6 +52,7 @@ private: void fillNumerationsCombo(); void fillNumRestartCombo(); void fillPECombo(); + void fillSuffixAlignmentCombo(); void setParagraphEffect(int); void showColors(const QList &cstyles); void showLineSpacing(const QList &pstyles); diff --git a/scribus/ui/smpstylewidget.ui b/scribus/ui/smpstylewidget.ui index 8a6d90e316..f625519568 100644 --- a/scribus/ui/smpstylewidget.ui +++ b/scribus/ui/smpstylewidget.ui @@ -29,7 +29,7 @@ - 0 + 1 @@ -181,7 +181,7 @@ - + 0 @@ -280,7 +280,7 @@ A value of 0 means unlimited hyphenations. 4 - + 0 @@ -326,7 +326,7 @@ A value of 0 means unlimited hyphenations. - + 0 @@ -379,7 +379,7 @@ A value of 0 means unlimited hyphenations. - + 0 @@ -389,7 +389,7 @@ A value of 0 means unlimited hyphenations. - + true @@ -419,7 +419,7 @@ A value of 0 means unlimited hyphenations. - + 0 @@ -459,7 +459,7 @@ A value of 0 means unlimited hyphenations. - + 0 @@ -469,7 +469,7 @@ A value of 0 means unlimited hyphenations. - + true @@ -597,7 +597,7 @@ A value of 0 means unlimited hyphenations. 16 - + 0 @@ -673,7 +673,7 @@ A value of 0 means unlimited hyphenations. 16 - + 0 @@ -710,7 +710,7 @@ A value of 0 means unlimited hyphenations. - + 0 @@ -804,7 +804,7 @@ A value of 0 means unlimited hyphenations. 16 - + 0 @@ -844,7 +844,7 @@ A value of 0 means unlimited hyphenations. - + 0 @@ -1021,7 +1021,7 @@ A value of 0 means unlimited hyphenations. - + 0 @@ -1441,7 +1441,7 @@ A value of 0 means unlimited hyphenations. - + 0 @@ -1451,10 +1451,7 @@ A value of 0 means unlimited hyphenations. New Set: - - FormWidget::LabelPosition::Left - - + false @@ -1476,6 +1473,20 @@ A value of 0 means unlimited hyphenations. + + + + Alignment of suffix characters in numbered lists + + + + + + + Suffix Align: + + + @@ -1506,7 +1517,7 @@ A value of 0 means unlimited hyphenations. 16 - + 0 @@ -1545,46 +1556,6 @@ A value of 0 means unlimited hyphenations. - - - - - 0 - 0 - - - - - - - true - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Hang Paragraph Effect before paragraph indent - - - Auto-Indent - - - - - - @@ -1606,7 +1577,7 @@ A value of 0 means unlimited hyphenations. 16 - + 0 @@ -1792,7 +1763,6 @@ A value of 0 means unlimited hyphenations. parentParEffectsButton dropCapLines parEffectOffset - parEffectIndentBox parEffectCharStyleCombo numPrefix numSuffix diff --git a/scribus/ui/smtextstyles.cpp b/scribus/ui/smtextstyles.cpp index b021322dd6..390365f537 100644 --- a/scribus/ui/smtextstyles.cpp +++ b/scribus/ui/smtextstyles.cpp @@ -37,7 +37,6 @@ for which a new license (GPL+exception) is in place. #include "units.h" #include "util.h" - SMParagraphStyle::SMParagraphStyle(SMCharacterStyle* cstyleItem): m_cstyleItem(cstyleItem) { @@ -511,7 +510,7 @@ void SMParagraphStyle::setupConnections() 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->suffixAlignmentCombo, SIGNAL(activated(int)), this, SLOT(slotSuffixAlignment(int))); 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))); @@ -606,8 +605,7 @@ void SMParagraphStyle::removeConnections() 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->suffixAlignmentCombo, SIGNAL(activated(int)), this, SLOT(slotSuffixAlignment(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))); @@ -953,17 +951,25 @@ void SMParagraphStyle::slotParEffectOffset() slotSelectionDirty(); } -void SMParagraphStyle::slotParEffectIndent(bool isOn) +void SMParagraphStyle::slotSuffixAlignment(int index) { - if (m_pwidget->parEffectIndentBox->useParentValue()) + if (m_pwidget->suffixAlignmentCombo->useParentValue()) + { for (int i = 0; i < m_selection.count(); ++i) - m_selection[i]->resetParEffectIndent(); - else + m_selection[i]->resetSuffixAlignment(); + } + else { + auto align = static_cast(m_pwidget->suffixAlignmentCombo->itemData(index).toInt()); for (int i = 0; i < m_selection.count(); ++i) - m_selection[i]->setParEffectIndent(isOn); + { + ParagraphStyle::SuffixAlignment styleAlign = align; + if (m_selection[i]->direction() == ParagraphStyle::RTL) + styleAlign = m_selection[i]->flipSuffixAlignmentForRTL(styleAlign); + m_selection[i]->setSuffixAlignment(styleAlign); + } } - + slotSelectionDirty(); } diff --git a/scribus/ui/smtextstyles.h b/scribus/ui/smtextstyles.h index 3dd02356a0..087870f222 100644 --- a/scribus/ui/smtextstyles.h +++ b/scribus/ui/smtextstyles.h @@ -77,7 +77,7 @@ private slots: void slotPargraphEffects(int index); void slotDropCapLines(int lines); void slotParEffectOffset(); - void slotParEffectIndent(bool); + void slotSuffixAlignment(int); void slotParEffectCharStyle(int); void slotBulletStr(const QString &str); void slotNumName(const QString &str);