View Issue Details

IDProjectCategoryView StatusLast Update
0017243ScribusText Frames / Story Editorpublic2026-07-15 08:00
Reporterale Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Product Version1.6.3.svn 
Summary0017243: Left indent for numbered lists
DescriptionThe Scribus Paragraph Effects now have a list.

Sadly, it's not possible to create a correct hanging indent, because the existing field "offset" does not start from the left (or right for RTL) margin but from the suffix.

This is a bigger issue at least for numbered lists with more than 9 elements (and for shorter lists that are not in arab numbers).

See this forum thread for a complaint about this:

Aligning Numbered Lists Vertically
 https://forums.scribus.net/index.php/topic,5213.msg23805.html#msg23805

I've checked how Libreoffice does it:
From what I can tell, it simply adds a tab character after the suffix. Automatically. Always.
If no tab is defined, the cursor will jump to the first default tab.

This having been said that, I wonder what's the use case for the offset that starts from the number / suffix.
Is there any?

If there is no known usage for it, I guess that the simplest solution is to repurpose this offset to start from the left margin.
The feature is pretty new in the stable version and -- if nobody if it is has no real purpose in its current implementation, i don't see why somebody would have used it...

The better solution is probably:

- The "offset" field is deprecated (and in the long term completely removed from Scribus; except if somebody comes up with a use case for the current implementation...).
- By default the list paragraph effects jump to the first existing tab (the default one if there is none) by inserting an automatic tab character after the suffix
- It might be possible to disable the automatic tab (if somebody comes up with a use case where this is useful)
- If there is a way to disable the automatic tab and the offset gets deprecated, allow multiple chars in the suffix (in order to allow a space after the dot)
TagsNo tags attached.
PatchNo

Relationships

related to 0016985 new Numbered list: there is no way to add a tab after the suffix 
related to 0016963 resolvedFahad second line is indented on the left, when RTL drop caps is enabled 
related to 0013488 confirmed Position of the number in numbered lists 

Activities

ale

2025-02-20 09:15

manager   ~0052074

this should be fixed as soon as possible.

people are starting using the numbering and, as soon as the number grows over 9 (or the width of the digits are not somehow the same), the entries WILL NOT BE ALIGNED!

the current way of doing the auto-indent is almost always wrong and shall be deprecated / replaced by one that does work!

the solution seems pretty simple to me:

- the "auto-indent" checkbox should be used to add a tab before the number and one after the dot.
- the "Character offset" field should be used to define an hanging indent and a left tab.
  on top of, it we need a right tab slightly to left, of it for aligning the number and the dot.
- if the user has defined an (hanging) indent or tabs for the paragraph, that indent should be used and no new tab should be "defined".
  the "Character offset" field should be disabled and a tooltip should explain why ("can only be filled when no tabs or indent is defined").
autoindent.png (7,871 bytes)   
autoindent.png (7,871 bytes)   
autoindent-correct.png (13,748 bytes)   
autoindent-correct.png (13,748 bytes)   

ale

2025-02-20 14:10

manager   ~0052075

i have to correct myself, it seems to be possible to get an acceptable result by setting the left indent for the paragraph, the automatic indent and a small character offset.

but, then, the numbers are right aligned.

a solution that would use the tabs and hanging indents would be much more flexible and, probably, easier to discover for the user.
numbering-nitramr.png (119,211 bytes)   
numbering-nitramr.png (119,211 bytes)   

ale

2025-02-20 15:31

manager   ~0052076

Last edited: 2025-02-20 15:32

the code for applying the distances in the list seems to be very intricate.

the PageItem_TextFrame::layout() function that probably applies the layout of the lists (among a lot of other things) is almost 2000 lines of code with specific instruction for the various supported types of text elements.
there might be performance reasons to keep all the code together, but i fear that the numerious conditions and loops also hide bugs and inefficient code that could be avoided by refactoring the code in function and structures with telling names and one concern.
also, by having separate functions for each concern, it might be possible to add tests and be more confident that the code does the right thing!

as an example (i swear, it was in in the 40 lines of code currently on my screen!) this complex conditions set got my attention:

            if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || SpecialChars::isBreak(itemText.text(a), m_columns > 1) || (current.xPos - current.maxShrink + hyphWidth) >= current.mustLineEnd)
            {
                //end of row reached - right column, end of column, break char or line must end
                if (current.isEmpty && !current.afterOverflow && !SpecialChars::isBreak(itemText.text(a), m_columns > 1))
                {
                    //no glyphs in line, so start new row
                    if (SpecialChars::isBreak(itemText.text(a), m_columns > 1))


this snippet

- is calling three times the function `SpecialChars::isBreak(itemText.text(a), m_columns > 1)`. no idea how expensive that is...
- and -- if i understand it correctly -- the last one is useless, since the preceding line checks for `!SpecialChars::isBreak(itemText.text(a), m_columns > 1)` .

but the code is so complex and not self documenting that i'm not even 100% that the last "if" will always be false!

as an example having

            auto breakAtEndOfColumn = SpecialChars::isBreak(itemText.text(a), m_columns > 1) 
            if ((current.isEndOfLine(style.rightMargin() + hyphWidth)) || current.isEndOfCol(realDesc) || breakAtEndOfColumn || (current.xPos - current.maxShrink + hyphWidth) >= current.mustLineEnd)
            {
                //end of row reached - right column, end of column, break char or line must end
                if (current.isEmpty && !current.afterOverflow && !breakAtEndOfColumn))
                {
                    //no glyphs in line, so start new row
                    if (breakAtEndOfColumn))


would already be a bit easier to parse.
(of course, i'm not at all sure that name of the new variable above is correct!.)

all this because i wanted to tell you, that i wanted to check if i can manage to get scribus to respect the tabs pasted inside prefix and suffix, i've probably even found (one of) the line(s) that make it hard, and gave up the task.

ale

2025-02-20 20:47

manager   ~0052079

To be even more clear: a user wanted to achieve the attached result and this seems not to be possible, when using the Scribus lists.
enumarte-left-aligned.png (35,060 bytes)   
enumarte-left-aligned.png (35,060 bytes)   

nitramr

2025-02-20 22:03

developer   ~0052080

Last edited: 2025-02-20 22:04

I could recreate the screenshot with a numbered list in Scribus.

1. Create a new paragraph style
2. enable numbered list (no left indent, no auto indent)
3. Add a new tab (right)
4. set fill char "dot"

Text should be formatted like "Chapter I <tab> 1"
The paragraph style will format it like "1. Chapter I..........1"

Attached file has been created with 1.7.1 svn

What I see as a missing feature is a flexible tabulator position to push the number always to the right edge of the text frame. Each time you resize text frame the numbers stay at the same position because of the absolute tabulator position.
Document-1.sla (22,279 bytes)   
<?xml version="1.0" encoding="UTF-8"?>
<SCRIBUSUTF8NEW Version="1.7.1.svn">
    <DOCUMENT ANZPAGES="1" PAGEWIDTH="595.275590551181" PAGEHEIGHT="841.889763779528" BORDERLEFT="40" BORDERRIGHT="40" BORDERTOP="40" BORDERBOTTOM="40" PRESET="0" BleedTop="0" BleedLeft="0" BleedRight="0" BleedBottom="0" ORIENTATION="0" PAGESIZE="IsoA_A04" FIRSTNUM="1" BOOK="0" AUTOSPALTEN="1" ABSTSPALTEN="11" UNITS="1" DFONT="Arial Regular" DSIZE="12" DCOL="1" DGAP="0" TabFill="" TabWidth="36" TextDistLeft="0" TextDistRight="0" TextDistBottom="0" TextDistTop="0" FirstLineOffset="1" AUTHOR="" COMMENTS="" KEYWORDS="" PUBLISHER="" DOCDATE="" DOCTYPE="" DOCFORMAT="" DOCIDENT="" DOCSOURCE="" DOCLANGINFO="" DOCRELATION="" DOCCOVER="" DOCRIGHTS="" DOCCONTRIB="" TITLE="" SUBJECT="" VHOCH="33" VHOCHSC="66" VTIEF="33" VTIEFSC="66" VKAPIT="75" BASEGRID="14.4" BASEO="0" AUTOL="100" UnderlinePos="-1" UnderlineWidth="-1" StrikeThruPos="-1" StrikeThruWidth="-1" GROUPC="1" HCMS="0" DPSo="0" DPSFo="0" DPuse="0" DPgam="0" DPbla="1" DPPr="ISO Coated v2 300% (basICColor)" DPIn="sRGB display profile (ICC v2.2)" DPInCMYK="ISO Coated v2 300% (basICColor)" DPIn2="sRGB display profile (ICC v2.2)" DPIn3="ISO Coated v2 300% (basICColor)" DISc="1" DIIm="0" ALAYER="0" LANGUAGE="en_US" AUTOMATIC="1" AUTOCHECK="0" GUIDELOCK="0" SnapToGuides="0" SnapToGrid="0" SnapToElement="0" MINGRID="20.001" MAJGRID="100.001" SHOWGRID="0" SHOWGUIDES="1" showcolborders="1" SHOWFRAME="1" SHOWControl="0" SHOWLAYERM="0" SHOWMARGIN="1" SHOWBASE="0" SHOWPICT="1" SHOWLINK="0" rulerMode="1" showrulers="1" showBleed="1" rulerXoffset="0" rulerYoffset="0" GuideRad="10" GRAB="4" POLYC="4" POLYF="0.502" POLYR="0" POLYIR="0" POLYCUR="0" POLYOCUR="0" POLYS="0" arcStartAngle="30" arcSweepAngle="300" spiralStartAngle="0" spiralEndAngle="1080" spiralFactor="1.2" AutoSave="1" AutoSaveTime="600000" AutoSaveCount="1" AutoSaveKeep="0" AUtoSaveInDocDir="1" AutoSaveDir="" ScratchBottom="508.031" ScratchLeft="1000.001" ScratchRight="1000.001" ScratchTop="508.031" GapHorizontal="0" GapVertical="1000.001" StartArrow="0" EndArrow="0" PEN="Black" BRUSH="None" PENLINE="Black" PENTEXT="Black" StrokeText="Black" TextBackGround="None" TextLineColor="None" TextBackGroundShade="100" TextLineShade="100" TextPenShade="100" TextStrokeShade="100" STIL="1" STILLINE="1" WIDTH="1" WIDTHLINE="1" PENSHADE="100" LINESHADE="100" BRUSHSHADE="100" CPICT="None" PICTSHADE="100" CSPICT="None" PICTSSHADE="100" PICTSCX="1" PICTSCY="1" PSCALE="1" PASPECT="1" EmbeddedPath="0" HalfRes="1" dispX="10.001" dispY="10.001" constrain="15" MINORC="#00ff00" MAJORC="#00ff00" GuidesColor="#000080" BaselineGridColor="#c0c0c0" renderStack="2 0 4 1 3" GridType="0" PAGEC="#ffffff" MARGC="#0000ff" RANDF="0" currentProfile="PDF 1.4" calligraphicPenFillColor="Black" calligraphicPenLineColor="Black" calligraphicPenFillColorShade="100" calligraphicPenLineColorShade="100" calligraphicPenLineWidth="1" calligraphicPenAngle="0" calligraphicPenWidth="10" calligraphicPenStyle="1">
        <CheckProfile Name="PDF 1.3" ignoreErrors="0" autoCheck="1" checkGlyphs="1" checkOrphans="1" checkOverflow="1" checkPictures="1" checkPartFilledImageFrames="0" checkResolution="1" checkTransparency="1" minResolution="144" maxResolution="2400" checkAnnotations="0" checkRasterPDF="1" checkForGIF="1" ignoreOffLayers="0" checkNotCMYKOrSpot="0" checkDeviceColorsAndOutputIntent="0" checkFontNotEmbedded="1" checkFontIsOpenType="1" checkAppliedMasterDifferentSide="1" checkEmptyTextFrames="1"/>
        <CheckProfile Name="PDF 1.4" ignoreErrors="0" autoCheck="1" checkGlyphs="1" checkOrphans="1" checkOverflow="1" checkPictures="1" checkPartFilledImageFrames="0" checkResolution="1" checkTransparency="0" minResolution="144" maxResolution="2400" checkAnnotations="0" checkRasterPDF="1" checkForGIF="1" ignoreOffLayers="0" checkNotCMYKOrSpot="0" checkDeviceColorsAndOutputIntent="0" checkFontNotEmbedded="1" checkFontIsOpenType="1" checkAppliedMasterDifferentSide="1" checkEmptyTextFrames="1"/>
        <CheckProfile Name="PDF 1.5" ignoreErrors="0" autoCheck="1" checkGlyphs="1" checkOrphans="1" checkOverflow="1" checkPictures="1" checkPartFilledImageFrames="0" checkResolution="1" checkTransparency="0" minResolution="144" maxResolution="2400" checkAnnotations="0" checkRasterPDF="1" checkForGIF="1" ignoreOffLayers="0" checkNotCMYKOrSpot="0" checkDeviceColorsAndOutputIntent="0" checkFontNotEmbedded="1" checkFontIsOpenType="1" checkAppliedMasterDifferentSide="1" checkEmptyTextFrames="1"/>
        <CheckProfile Name="PDF 1.6" ignoreErrors="0" autoCheck="1" checkGlyphs="1" checkOrphans="1" checkOverflow="1" checkPictures="1" checkPartFilledImageFrames="0" checkResolution="1" checkTransparency="0" minResolution="144" maxResolution="2400" checkAnnotations="0" checkRasterPDF="1" checkForGIF="1" ignoreOffLayers="0" checkNotCMYKOrSpot="0" checkDeviceColorsAndOutputIntent="0" checkFontNotEmbedded="1" checkFontIsOpenType="0" checkAppliedMasterDifferentSide="1" checkEmptyTextFrames="1"/>
        <CheckProfile Name="PDF/X-1a" ignoreErrors="0" autoCheck="1" checkGlyphs="1" checkOrphans="1" checkOverflow="1" checkPictures="1" checkPartFilledImageFrames="0" checkResolution="1" checkTransparency="1" minResolution="144" maxResolution="2400" checkAnnotations="1" checkRasterPDF="1" checkForGIF="1" ignoreOffLayers="0" checkNotCMYKOrSpot="1" checkDeviceColorsAndOutputIntent="0" checkFontNotEmbedded="1" checkFontIsOpenType="1" checkAppliedMasterDifferentSide="1" checkEmptyTextFrames="1"/>
        <CheckProfile Name="PDF/X-3" ignoreErrors="0" autoCheck="1" checkGlyphs="1" checkOrphans="1" checkOverflow="1" checkPictures="1" checkPartFilledImageFrames="0" checkResolution="1" checkTransparency="1" minResolution="144" maxResolution="2400" checkAnnotations="1" checkRasterPDF="1" checkForGIF="1" ignoreOffLayers="0" checkNotCMYKOrSpot="0" checkDeviceColorsAndOutputIntent="1" checkFontNotEmbedded="1" checkFontIsOpenType="1" checkAppliedMasterDifferentSide="1" checkEmptyTextFrames="1"/>
        <CheckProfile Name="PDF/X-4" ignoreErrors="0" autoCheck="1" checkGlyphs="1" checkOrphans="1" checkOverflow="1" checkPictures="1" checkPartFilledImageFrames="0" checkResolution="1" checkTransparency="0" minResolution="144" maxResolution="2400" checkAnnotations="1" checkRasterPDF="1" checkForGIF="1" ignoreOffLayers="0" checkNotCMYKOrSpot="0" checkDeviceColorsAndOutputIntent="1" checkFontNotEmbedded="1" checkFontIsOpenType="0" checkAppliedMasterDifferentSide="1" checkEmptyTextFrames="1"/>
        <CheckProfile Name="PostScript" ignoreErrors="0" autoCheck="1" checkGlyphs="1" checkOrphans="1" checkOverflow="1" checkPictures="1" checkPartFilledImageFrames="0" checkResolution="1" checkTransparency="1" minResolution="144" maxResolution="2400" checkAnnotations="0" checkRasterPDF="1" checkForGIF="1" ignoreOffLayers="0" checkNotCMYKOrSpot="0" checkDeviceColorsAndOutputIntent="0" checkFontNotEmbedded="0" checkFontIsOpenType="0" checkAppliedMasterDifferentSide="1" checkEmptyTextFrames="1"/>
        <COLOR NAME=" Aluminum 1" SPACE="RGB" R="238" G="238" B="236"/>
        <COLOR NAME=" Aluminum 2" SPACE="RGB" R="211" G="215" B="207"/>
        <COLOR NAME=" Aluminum 3" SPACE="RGB" R="186" G="189" B="182"/>
        <COLOR NAME=" Aluminum 4" SPACE="RGB" R="136" G="138" B="133"/>
        <COLOR NAME=" Aluminum 5" SPACE="RGB" R="85" G="87" B="83"/>
        <COLOR NAME=" Aluminum 6" SPACE="RGB" R="46" G="52" B="54"/>
        <COLOR NAME=" Blue 1" SPACE="RGB" R="191" G="206" B="234"/>
        <COLOR NAME=" Blue 2" SPACE="RGB" R="67" G="116" B="183"/>
        <COLOR NAME=" Blue 3" SPACE="RGB" R="33" G="65" B="132"/>
        <COLOR NAME=" Blue 4" SPACE="RGB" R="16" G="37" B="72"/>
        <COLOR NAME=" Butter 1" SPACE="RGB" R="252" G="233" B="79"/>
        <COLOR NAME=" Butter 2" SPACE="RGB" R="237" G="212" B="0"/>
        <COLOR NAME=" Butter 3" SPACE="RGB" R="196" G="160" B="0"/>
        <COLOR NAME=" CC Green 1" SPACE="RGB" R="224" G="228" B="225"/>
        <COLOR NAME=" CC Green 2" SPACE="RGB" R="171" G="184" B="175"/>
        <COLOR NAME=" CC Green 3" SPACE="RGB" R="67" G="89" B="74"/>
        <COLOR NAME=" CC Green 4" SPACE="RGB" R="42" G="55" B="47"/>
        <COLOR NAME=" Chameleon 1" SPACE="RGB" R="138" G="226" B="52"/>
        <COLOR NAME=" Chameleon 2" SPACE="RGB" R="115" G="210" B="22"/>
        <COLOR NAME=" Chameleon 3" SPACE="RGB" R="78" G="154" B="6"/>
        <COLOR NAME=" Chocolate 1" SPACE="RGB" R="233" G="185" B="110"/>
        <COLOR NAME=" Chocolate 2" SPACE="RGB" R="193" G="125" B="17"/>
        <COLOR NAME=" Chocolate 3" SPACE="RGB" R="143" G="89" B="2"/>
        <COLOR NAME=" Gray 1" SPACE="RGB" R="237" G="237" B="238"/>
        <COLOR NAME=" Gray 2" SPACE="RGB" R="220" G="221" B="222"/>
        <COLOR NAME=" Gray 3" SPACE="RGB" R="167" G="169" B="172"/>
        <COLOR NAME=" Gray 4" SPACE="RGB" R="99" G="100" B="102"/>
        <COLOR NAME=" Gray 5" SPACE="RGB" R="57" G="56" B="57"/>
        <COLOR NAME=" Gray 6" SPACE="RGB" R="18" G="21" B="19"/>
        <COLOR NAME=" Green 1" SPACE="RGB" R="228" G="235" B="160"/>
        <COLOR NAME=" Green 2" SPACE="RGB" R="152" G="200" B="7"/>
        <COLOR NAME=" Green 3" SPACE="RGB" R="98" G="125" B="15"/>
        <COLOR NAME=" Green 4" SPACE="RGB" R="61" G="80" B="36"/>
        <COLOR NAME=" Magenta 1" SPACE="RGB" R="247" G="178" B="204"/>
        <COLOR NAME=" Magenta 2" SPACE="RGB" R="182" G="43" B="110"/>
        <COLOR NAME=" Magenta 3" SPACE="RGB" R="123" G="27" B="83"/>
        <COLOR NAME=" Magenta 4" SPACE="RGB" R="79" G="16" B="53"/>
        <COLOR NAME=" Orange 1" SPACE="RGB" R="252" G="175" B="62"/>
        <COLOR NAME=" Orange 2" SPACE="RGB" R="245" G="121" B="0"/>
        <COLOR NAME=" Orange 3" SPACE="RGB" R="206" G="92" B="0"/>
        <COLOR NAME=" Orange 4" SPACE="RGB" R="84" G="61" B="3"/>
        <COLOR NAME=" Plum 1" SPACE="RGB" R="173" G="127" B="168"/>
        <COLOR NAME=" Plum 2" SPACE="RGB" R="117" G="80" B="123"/>
        <COLOR NAME=" Plum 3" SPACE="RGB" R="92" G="53" B="102"/>
        <COLOR NAME=" Purple 1" SPACE="RGB" R="214" G="180" B="214"/>
        <COLOR NAME=" Purple 2" SPACE="RGB" R="150" G="40" B="198"/>
        <COLOR NAME=" Purple 3" SPACE="RGB" R="102" G="41" B="120"/>
        <COLOR NAME=" Purple 4" SPACE="RGB" R="66" G="25" B="79"/>
        <COLOR NAME=" Red 1" SPACE="RGB" R="250" G="180" B="153"/>
        <COLOR NAME=" Red 2" SPACE="RGB" R="209" G="56" B="20"/>
        <COLOR NAME=" Red 3" SPACE="RGB" R="145" G="43" B="16"/>
        <COLOR NAME=" Red 4" SPACE="RGB" R="90" G="28" B="14"/>
        <COLOR NAME=" Sand 1" SPACE="RGB" R="235" G="224" B="178"/>
        <COLOR NAME=" Sand 2" SPACE="RGB" R="177" G="162" B="74"/>
        <COLOR NAME=" Sand 3" SPACE="RGB" R="109" G="97" B="24"/>
        <COLOR NAME=" Sand 4" SPACE="RGB" R="68" G="65" B="31"/>
        <COLOR NAME=" Scarlet Red 1" SPACE="RGB" R="239" G="41" B="41"/>
        <COLOR NAME=" Scarlet Red 2" SPACE="RGB" R="204" G="0" B="0"/>
        <COLOR NAME=" Scarlet Red 3" SPACE="RGB" R="164" G="0" B="0"/>
        <COLOR NAME=" Sky Blue 1" SPACE="RGB" R="114" G="159" B="207"/>
        <COLOR NAME=" Sky Blue 2" SPACE="RGB" R="52" G="101" B="164"/>
        <COLOR NAME=" Sky Blue 3" SPACE="RGB" R="32" G="74" B="135"/>
        <COLOR NAME=" Yellow 1" SPACE="RGB" R="255" G="243" B="162"/>
        <COLOR NAME=" Yellow 2" SPACE="RGB" R="237" G="216" B="18"/>
        <COLOR NAME=" Yellow 3" SPACE="RGB" R="176" G="154" B="17"/>
        <COLOR NAME=" Yellow 4" SPACE="RGB" R="78" G="73" B="23"/>
        <COLOR NAME="Black" SPACE="CMYK" C="0" M="0" Y="0" K="100"/>
        <COLOR NAME="Registration" SPACE="CMYK" C="100" M="100" Y="100" K="100" Register="1"/>
        <COLOR NAME="White" SPACE="CMYK" C="0" M="0" Y="0" K="0"/>
        <HYPHEN/>
        <CHARSTYLE CNAME="Default Character Style" DefaultStyle="1" FONT="Arial Regular" FONTSIZE="12" FONTFEATURES="" FEATURES="inherit" FCOLOR="Black" FSHADE="100" HyphenWordMin="3" SCOLOR="Black" BGCOLOR="None" BGSHADE="100" SSHADE="100" TXTSHX="5" TXTSHY="-5" TXTOUT="1" TXTULP="-0.1" TXTULW="-0.1" TXTSTP="-0.1" TXTSTW="-0.1" SCALEH="100" SCALEV="100" BASEO="0" KERN="0" LANGUAGE="en_US"/>
        <STYLE NAME="Default Paragraph Style" DefaultStyle="1" ALIGN="0" DIRECTION="0" LINESPMode="0" LINESP="15" INDENT="0" RMARGIN="0" FIRST="0" VOR="0" NACH="0" ParagraphEffectOffset="0" DROP="0" DROPLIN="2" Bullet="0" Numeration="0" HyphenConsecutiveLines="2" BCOLOR="None" BSHADE="100"/>
        <STYLE NAME="TOC List" ParagraphEffectOffset="5.66929133858268" ParagraphEffectIndent="0" DROP="0" Bullet="0" Numeration="1" OpticalMarginSetId="preset_0" LANGUAGE="en_US">
            <Tabs Type="1" Pos="340" Fill="."/>
        </STYLE>
        <TableStyle NAME="Default Table Style" DefaultStyle="1" FillColor="None" FillShade="100">
            <TableBorderLeft>
                <TableBorderLine Width="1" PenStyle="1" Color="Black" Shade="100"/>
            </TableBorderLeft>
            <TableBorderRight>
                <TableBorderLine Width="1" PenStyle="1" Color="Black" Shade="100"/>
            </TableBorderRight>
            <TableBorderTop>
                <TableBorderLine Width="1" PenStyle="1" Color="Black" Shade="100"/>
            </TableBorderTop>
            <TableBorderBottom>
                <TableBorderLine Width="1" PenStyle="1" Color="Black" Shade="100"/>
            </TableBorderBottom>
        </TableStyle>
        <CellStyle NAME="Default Cell Style" DefaultStyle="1" FillColor="None" FillShade="100" LeftPadding="1" RightPadding="1" TopPadding="1" BottomPadding="1">
            <TableBorderLeft>
                <TableBorderLine Width="1" PenStyle="1" Color="Black" Shade="100"/>
            </TableBorderLeft>
            <TableBorderRight>
                <TableBorderLine Width="1" PenStyle="1" Color="Black" Shade="100"/>
            </TableBorderRight>
            <TableBorderTop>
                <TableBorderLine Width="1" PenStyle="1" Color="Black" Shade="100"/>
            </TableBorderTop>
            <TableBorderBottom>
                <TableBorderLine Width="1" PenStyle="1" Color="Black" Shade="100"/>
            </TableBorderBottom>
        </CellStyle>
        <LAYERS NUMMER="0" LEVEL="0" NAME="Background" SICHTBAR="1" DRUCKEN="1" EDIT="1" SELECT="0" FLOW="1" TRANS="1" BLEND="0" OUTL="0" LAYERC="#000000"/>
        <Printer firstUse="1" toFile="0" useAltPrintCommand="0" outputSeparations="0" useSpotColors="1" useColor="1" mirrorH="0" mirrorV="0" useICC="0" doGCR="0" doClip="0" setDevParam="0" useDocBleeds="1" cropMarks="0" bleedMarks="0" registrationMarks="0" colorMarks="0" includePDFMarks="1" PSLevel="3" PrintEngine="3" markLength="20.0013" markOffset="0" BleedTop="0" BleedLeft="0" BleedRight="0" BleedBottom="0" printer="File" filename="" separationName="All" printerCommand=""/>
        <PDF firstUse="1" Thumbnails="0" Articles="0" Bookmarks="0" Compress="1" CMethod="0" Quality="0" EmbedPDF="0" MirrorH="0" MirrorV="0" Clip="0" rangeSel="0" rangeTxt="" RotateDeg="0" PresentMode="0" RecalcPic="0" FontEmbedding="0" Grayscale="0" RGBMode="1" UseProfiles="0" UseProfiles2="0" Binding="0" PicRes="300" Resolution="300" Version="14" Intent="1" Intent2="0" SolidP="sRGB display profile (ICC v2.2)" ImageP="sRGB display profile (ICC v2.2)" PrintP="ISO Coated v2 300% (basICColor)" InfoString="" BTop="0" BLeft="0" BRight="0" BBottom="0" useDocBleeds="1" cropMarks="0" bleedMarks="0" registrationMarks="0" colorMarks="0" docInfoMarks="0" markLength="20.0012598425197" markOffset="0" ImagePr="0" PassOwner="" PassUser="" Permissions="-4" Encrypt="0" UseLayers="0" UseLpi="0" UseSpotColors="1" doMultiFile="0" displayBookmarks="0" displayFullscreen="0" displayLayers="0" displayThumbs="0" hideMenuBar="0" hideToolBar="0" fitWindow="0" openAfterExport="0" PageLayout="0" openAction="">
            <LPI Color="Black" Frequency="133" Angle="45" SpotFunction="3"/>
            <LPI Color="Cyan" Frequency="133" Angle="105" SpotFunction="3"/>
            <LPI Color="Magenta" Frequency="133" Angle="75" SpotFunction="3"/>
            <LPI Color="Yellow" Frequency="133" Angle="90" SpotFunction="3"/>
        </PDF>
        <DocItemAttributes/>
        <Indexes/>
        <TablesOfContents/>
        <NotesStyles>
            <notesStyle Name="Default" Start="1" Endnotes="0" Type="Type_1_2_3" Range="0" Prefix="" Suffix=")" AutoHeight="1" AutoWidth="1" AutoRemove="1" AutoWeld="1" SuperNote="1" SuperMaster="1" MarksStyle="" NotesStyle=""/>
        </NotesStyles>
        <OpticalMarginSets>
            <Set Id="preset_0" Type="preset" Name="Default">
                <Rules>
                    <Rule Left="0" Right="0.5" Unit="7" Characters="U+003A,U+003B,U+2013,U+2033"/>
                    <Rule Left="0" Right="0.75" Unit="7" Characters="U+002C,U+002D,U+002E,U+2010,U+2032"/>
                    <Rule Left="0.25" Right="0.25" Unit="7" Characters="U+2014"/>
                    <Rule Left="0.5" Right="0" Unit="7" Characters="U+2036"/>
                    <Rule Left="0.5" Right="0.5" Unit="7" Characters="U+0022,U+0028,U+0029,U+005B,U+005D,U+00AB,U+00BB,U+201C,U+201D,U+201E,U+201F"/>
                    <Rule Left="0.75" Right="0" Unit="7" Characters="U+2035"/>
                    <Rule Left="0.75" Right="0.75" Unit="7" Characters="U+0027,U+002A,U+0060,U+007E,U+00B4,U+2018,U+2019,U+201A,U+201B,U+2039,U+203A"/>
                </Rules>
            </Set>
        </OpticalMarginSets>
        <PageSets>
            <Set Name="Single Page" FirstPage="0" Rows="1" Columns="1"/>
            <Set Name="Facing Pages" FirstPage="1" Rows="1" Columns="2">
                <PageNames Name="Left Page"/>
                <PageNames Name="Right Page"/>
            </Set>
            <Set Name="3-Fold" FirstPage="0" Rows="1" Columns="3">
                <PageNames Name="Left Page"/>
                <PageNames Name="Middle"/>
                <PageNames Name="Right Page"/>
            </Set>
            <Set Name="4-Fold" FirstPage="0" Rows="1" Columns="4">
                <PageNames Name="Left Page"/>
                <PageNames Name="Middle Left"/>
                <PageNames Name="Middle Right"/>
                <PageNames Name="Right Page"/>
            </Set>
        </PageSets>
        <Sections>
            <Section Number="0" Name="Section 1" From="0" To="0" Type="Type_1_2_3" Start="1" Reversed="0" Active="1" FillChar="0" FieldWidth="0"/>
        </Sections>
        <MASTERPAGE PAGEXPOS="1000.001" PAGEYPOS="508.031" PAGEWIDTH="595.275590551181" PAGEHEIGHT="841.889763779528" BORDERLEFT="40" BORDERRIGHT="40" BORDERTOP="40" BORDERBOTTOM="40" NUM="0" NAM="Normal" MNAM="" Size="IsoA_A04" Orientation="0" LEFT="0" PRESET="0" VerticalGuides="" HorizontalGuides="" AGhorizontalAutoGap="0" AGverticalAutoGap="0" AGhorizontalAutoCount="0" AGverticalAutoCount="0" AGhorizontalAutoRefer="0" AGverticalAutoRefer="0" AGSelection="0 0 0 0" pageEffectDuration="1" pageViewDuration="1" effectType="0" Dm="0" M="0" Di="0"/>
        <PAGE PAGEXPOS="1000.001" PAGEYPOS="508.031" PAGEWIDTH="595.275590551181" PAGEHEIGHT="841.889763779528" BORDERLEFT="40" BORDERRIGHT="40" BORDERTOP="40" BORDERBOTTOM="40" NUM="0" NAM="" MNAM="Normal" Size="IsoA_A04" Orientation="0" LEFT="0" PRESET="0" VerticalGuides="" HorizontalGuides="" AGhorizontalAutoGap="0" AGverticalAutoGap="0" AGhorizontalAutoCount="0" AGverticalAutoCount="0" AGhorizontalAutoRefer="0" AGverticalAutoRefer="0" AGSelection="0 0 0 0" pageEffectDuration="1" pageViewDuration="1" effectType="0" Dm="0" M="0" Di="0"/>
        <PAGEOBJECT XPOS="1115.52068503937" YPOS="582.75" OwnPage="0" ItemID="1236526944" PTYPE="4" WIDTH="343.22931496063" HEIGHT="444.75" FRTYPE="0" CLIPEDIT="0" PWIDTH="1" PLINEART="1" LOCALSCX="1" LOCALSCY="1" LOCALX="0" LOCALY="0" LOCALROT="0" PICART="1" SCALETYPE="1" RATIO="1" COLUMNS="1" COLGAP="0" AUTOTEXT="0" EXTRA="0" TEXTRA="0" BEXTRA="0" REXTRA="0" VAlign="0" FLOP="1" PLTSHOW="0" BASEOF="0" textPathType="0" textPathFlipped="0" path="M0 0 L343.229 0 L343.229 444.75 L0 444.75 L0 0 Z" copath="M0 0 L343.229 0 L343.229 444.75 L0 444.75 L0 0 Z" gXpos="1115.52068503937" gYpos="582.75" gWidth="0" gHeight="0" PSTYLE="TOC List" LAYER="0" NEXTITEM="-1" BACKITEM="-1">
            <StoryText>
                <DefaultStyle PARENT="TOC List"/>
                <ITEXT CH="Chapter I"/>
                <tab/>
                <ITEXT CH="1"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter II"/>
                <tab/>
                <ITEXT CH="14"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter III"/>
                <tab/>
                <ITEXT CH="25"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter IV"/>
                <tab/>
                <ITEXT CH="41"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter V"/>
                <tab/>
                <ITEXT CH="49"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter VI"/>
                <tab/>
                <ITEXT CH="59"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter VII"/>
                <tab/>
                <ITEXT CH="68"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter VIII"/>
                <tab/>
                <ITEXT CH="78"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter IX"/>
                <tab/>
                <ITEXT CH="91"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter X"/>
                <tab/>
                <ITEXT CH="98"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter XI"/>
                <tab/>
                <ITEXT CH="110"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter XII"/>
                <tab/>
                <ITEXT CH="118"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter XIII"/>
                <tab/>
                <ITEXT CH="125"/>
                <para PARENT="TOC List"/>
                <ITEXT CH="Chapter XIV"/>
                <tab/>
                <ITEXT CH="125"/>
                <para PARENT="TOC List"/>
            </StoryText>
        </PAGEOBJECT>
    </DOCUMENT>
</SCRIBUSUTF8NEW>
Document-1.sla (22,279 bytes)   

ale

2025-02-21 17:36

manager   ~0052083

I mean: the above screenshot shows the bad result.
The "Chapter"s are not aligned.

They are probably almost aligned until the ninth.
Then it gets really bad.

Sorry, I thought in the context it would have been clear.

nitramr

2025-02-21 18:59

developer   ~0052086

Ok, I misunderstood it. So what we need is a text alignment option for the numbering (left/right/center?)

With such an option, you can create a numbered list with "left indent" and "auto-indent" as I described above.

ale

2025-02-22 09:26

manager   ~0052093

yes, exactly.

i've just found this ticket about the same topic: 0013488

qirat

2026-02-26 15:50

reporter   ~0053542

I recently filed a similar ticket to request an option to align suffix. Is it easy to program so that whatever char is typed in the suffix filed is aligned, than other ways of handling this?

qirat

2026-02-26 15:50

reporter   ~0053543

suffix field*

Fahad

2026-07-06 03:59

developer   ~0053980

@nitramr @ale
as far as I understand this issue. the requirement of a text alignment option for the numbering (left/right/center) not required for suffix field only but also the text after the suffix. Am I right? or it is enough suffix alignment? if so how the text get alignment?

qirat

2026-07-06 04:55

reporter   ~0053985

Report 0017768 is either related or a duplicate.

Fahad

2026-07-09 08:14

developer   ~0054001

Hi all, here is a patch to implement this feature. It does the following:

- Removes the old Auto-Indent entirely
- Adds a new SuffixAlignment enum (SuffixAlign_Left, SuffixAlign_Center, SuffixAlign_Right)
- Add suffix align to propertywidget_pareffect & Style Manager
- Support RTL.

@ale & @qirat @nitramr please test.
suffixalignment v1.patch (76,522 bytes)   
Index: scribus/pageitem_textframe.cpp
===================================================================
--- scribus/pageitem_textframe.cpp	(revision 27701)
+++ scribus/pageitem_textframe.cpp	(working copy)
@@ -1075,7 +1075,47 @@
 	return style.lineSpacing();
 }
 
+/**
+ * @brief Pre-pass to compute the maximum paragraph effect width.
+ */
+static double maxParagraphEffectWidth(PageItem* item)
+{
+	ShapedTextFeed shapedText(&item->itemText, 0, item);
 
+	QList<GlyphCluster> 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())
+			{
+				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;
+}
+
 // 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
 // The incomplete* vars are used to ensure that we don't run into an endless loop
@@ -1391,8 +1431,8 @@
 		setMaxY(-1);
 		double maxYAsc = 0.0, maxYDesc = 0.0;
 		int regionMinY = 0, regionMaxY= 0;
+		double cachedMaxParEffectWidth = -1.0;
 
-		double autoLeftIndent = 0.0;
 		for (int i = 0; shapedText.haveMoreText(i, glyphClusters); ++i)
 		{
 			int currentIndex = i - current.lineData.firstCluster;
@@ -1425,16 +1465,6 @@
 			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 +1837,7 @@
 					else
 					{
 						// LTR: Original behavior
-						current.leftIndent = style.leftMargin() + autoLeftIndent;
+						current.leftIndent = style.leftMargin();
 						if (itemText.isBlockStart(a))
 						{
 							current.leftIndent += style.firstIndent();
@@ -1816,33 +1846,31 @@
 
 					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)
+						{
+							if (cachedMaxParEffectWidth < 0.0)
+								cachedMaxParEffectWidth = maxParagraphEffectWidth(this);
 
-							if (style.direction() == ParagraphStyle::RTL)
-							{
-								current.rightIndent -= style.parEffectOffset() + effectWidth;
-								if (current.rightIndent < 0.0)
-									current.rightIndent = 0.0;
-							}
+							if (style.suffixAlignment() == ParagraphStyle::SuffixAlign_Right)
+								indentAdjust = style.parEffectOffset() + (effectWidth - cachedMaxParEffectWidth);
 							else
-							{
-								current.leftIndent -= style.parEffectOffset() + effectWidth;
-								if (current.leftIndent < 0.0)
-								{
-									autoLeftIndent = abs(current.leftIndent);
-									current.leftIndent = 0.0;
-								}
-							}
+								indentAdjust = style.parEffectOffset() + (effectWidth - cachedMaxParEffectWidth) / 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.
Index: scribus/plugins/fileloader/scribus150format/scribus150format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus150format/scribus150format.cpp	(revision 27701)
+++ scribus/plugins/fileloader/scribus150format/scribus150format.cpp	(working copy)
@@ -3123,10 +3123,6 @@
 	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<bool>(attrs.valueAsInt(DROP)));
@@ -5497,8 +5493,6 @@
 		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<bool>(attrs.valueAsInt("DROP")));
 	if (attrs.hasAttribute("DROPLIN"))
Index: scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp
===================================================================
--- scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp	(revision 27701)
+++ scribus/plugins/fileloader/scribus150format/scribus150format_save.cpp	(working copy)
@@ -842,8 +842,6 @@
 		docu.writeAttribute("ParagraphEffectCharStyle", style.peCharStyleName());
 	if ( ! style.isInhParEffectOffset())
 		docu.writeAttribute("ParagraphEffectOffset", style.parEffectOffset());
-	if ( ! style.isInhParEffectIndent())
-		docu.writeAttribute("ParagraphEffectIndent", static_cast<int>(style.parEffectIndent()));
 	if ( ! style.isInhHasDropCap())
 		docu.writeAttribute("DROP", static_cast<int>(style.hasDropCap()));
 	if ( ! style.isInhDropCapLines())
Index: scribus/plugins/fileloader/scribus170format/scribus170format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus170format/scribus170format.cpp	(revision 27701)
+++ scribus/plugins/fileloader/scribus170format/scribus170format.cpp	(working copy)
@@ -3131,10 +3131,6 @@
 	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<bool>(attrs.valueAsInt(DROP)));
@@ -5567,8 +5563,6 @@
 		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<bool>(attrs.valueAsInt("DROP")));
 	if (attrs.hasAttribute("DROPLIN"))
Index: scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp
===================================================================
--- scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp	(revision 27701)
+++ scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp	(working copy)
@@ -844,8 +844,6 @@
 		docu.writeAttribute("ParagraphEffectCharStyle", style.peCharStyleName());
 	if (!style.isInhParEffectOffset())
 		docu.writeAttribute("ParagraphEffectOffset", style.parEffectOffset());
-	if (!style.isInhParEffectIndent())
-		docu.writeAttribute("ParagraphEffectIndent", static_cast<int>(style.parEffectIndent()));
 	if (!style.isInhHasDropCap())
 		docu.writeAttribute("DROP", static_cast<int>(style.hasDropCap()));
 	if (!style.isInhDropCapLines())
Index: scribus/plugins/fileloader/scribus171format/scribus171format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus171format/scribus171format.cpp	(revision 27701)
+++ scribus/plugins/fileloader/scribus171format/scribus171format.cpp	(working copy)
@@ -3635,10 +3635,6 @@
 	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<bool>(attrs.valueAsInt("DROP")));
@@ -3695,6 +3691,10 @@
 	if (attrs.hasAttribute(NumerationSuffix))
 		newStyle.setNumSuffix(attrs.valueAsString(NumerationSuffix));
 
+	static const QString SuffixAlignment("SuffixAlignment");
+	if (attrs.hasAttribute(SuffixAlignment))
+		newStyle.setSuffixAlignment(static_cast<ParagraphStyle::SuffixAlignment>(attrs.valueAsInt(SuffixAlignment)));
+
 	static const QString NumerationRestart("NumerationRestart");
 	if (attrs.hasAttribute(NumerationRestart))
 		newStyle.setNumRestart(attrs.valueAsInt(NumerationRestart));
@@ -6679,8 +6679,6 @@
 		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<bool>(attrs.valueAsInt("DROP")));
@@ -6717,6 +6715,8 @@
 		pstyle.setNumPrefix(attrs.valueAsString("NumerationPrefix"));
 	if (attrs.hasAttribute("NumerationSuffix"))
 		pstyle.setNumSuffix(attrs.valueAsString("NumerationSuffix"));
+	if (attrs.hasAttribute("SuffixAlignment"))
+		pstyle.setSuffixAlignment(static_cast<ParagraphStyle::SuffixAlignment>(attrs.valueAsInt("SuffixAlignment")));
 	if (attrs.hasAttribute("NumerationRestart"))
 	{
 		NumerationRange numRange = (NumerationRange) attrs.valueAsInt("NumerationRestart");
Index: scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp
===================================================================
--- scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp	(revision 27701)
+++ scribus/plugins/fileloader/scribus171format/scribus171format_save.cpp	(working copy)
@@ -846,8 +846,6 @@
 		docu.writeAttribute("ParagraphEffectCharStyle", style.peCharStyleName());
 	if (!style.isInhParEffectOffset())
 		docu.writeAttribute("ParagraphEffectOffset", style.parEffectOffset());
-	if (!style.isInhParEffectIndent())
-		docu.writeAttribute("ParagraphEffectIndent", static_cast<int>(style.parEffectIndent()));
 	if (!style.isInhHasDropCap())
 		docu.writeAttribute("HasDropCap", static_cast<int>(style.hasDropCap()));
 	if (!style.isInhDropCapLines())
@@ -868,6 +866,8 @@
 		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())
Index: scribus/styles/paragraphstyle.attrdefs.cxx
===================================================================
--- scribus/styles/paragraphstyle.attrdefs.cxx	(revision 27701)
+++ scribus/styles/paragraphstyle.attrdefs.cxx	(working copy)
@@ -40,7 +40,6 @@
 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, 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)
Index: scribus/styles/paragraphstyle.cpp
===================================================================
--- scribus/styles/paragraphstyle.cpp	(revision 27701)
+++ scribus/styles/paragraphstyle.cpp	(working copy)
@@ -208,6 +208,14 @@
 #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 @@
 	return QString::number(static_cast<int>(val));
 }
 
+static QString toXMLString(ParagraphStyle::SuffixAlignment val)
+{
+	return QString::number(static_cast<int>(val));
+}
+
 static QString toXMLString(ParagraphStyle::DirectionType val)
 {
 	return QString::number(static_cast<int>(val));
@@ -345,6 +358,12 @@
 }
 
 template<>
+ParagraphStyle::SuffixAlignment parse<ParagraphStyle::SuffixAlignment>(const Xml_string& str)
+{
+	return parseEnum<ParagraphStyle::SuffixAlignment>(str);
+}
+
+template<>
 ParagraphStyle::DirectionType parse<ParagraphStyle::DirectionType>(const Xml_string& str)
 {
 	return parseEnum<ParagraphStyle::DirectionType>(str);
Index: scribus/styles/paragraphstyle.h
===================================================================
--- scribus/styles/paragraphstyle.h	(revision 27701)
+++ scribus/styles/paragraphstyle.h	(working copy)
@@ -76,6 +76,13 @@
 		CenterTab = 4
 	};
 
+	enum SuffixAlignment
+	{
+		SuffixAlign_Left   = 0,
+		SuffixAlign_Center = 1,
+		SuffixAlign_Right  = 2
+	};
+
 	struct TabRecord
 	{
 		qreal tabPosition {0.0};
@@ -113,6 +120,7 @@
 	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; }
Index: scribus/ui/propertywidget_pareffect.cpp
===================================================================
--- scribus/ui/propertywidget_pareffect.cpp	(revision 27701)
+++ scribus/ui/propertywidget_pareffect.cpp	(working copy)
@@ -45,6 +45,10 @@
 	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 @@
 		stackedWidget->setVisible(true);
 		peGroup->setVisible(true);
 	}
+	bool isNumberedList = (id == 2);
+	suffixAlignmentLabel->setVisible(isNumberedList);
+	suffixAlignmentCombo->setVisible(isNumberedList);
 }
 
 void PropertyWidget_ParEffect::fillBulletStrEditCombo()
@@ -230,8 +237,8 @@
 	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 @@
 
 	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<int>(displayAlign));
+	if (idx >= 0)
+		suffixAlignmentCombo->setCurrentIndex(idx);
+
 	if (oldPeComboIndex != peCombo->currentIndex())
 		emit needsRelayout();
 }
@@ -288,7 +302,7 @@
 	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 @@
 	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 @@
 		newStyle.setHasBullet(false);
 		newStyle.setHasNum(false);
 	}
-	newStyle.setParEffectOffset(peOffset->value() / m_unitRatio);
-	newStyle.setParEffectIndent(peIndent->isChecked());
 
 	setType(peCombo->currentData().toInt());
 
@@ -537,12 +549,15 @@
 	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<ParagraphStyle::SuffixAlignment>(suffixAlignmentCombo->itemData(index).toInt());
+	if (m_item->currentStyle().direction() == ParagraphStyle::RTL)
+		align = newStyle.flipSuffixAlignmentForRTL(align);
+	newStyle.setSuffixAlignment(align);
 	handleChanges(m_item, newStyle);
 }
 
Index: scribus/ui/propertywidget_pareffect.h
===================================================================
--- scribus/ui/propertywidget_pareffect.h	(revision 27701)
+++ scribus/ui/propertywidget_pareffect.h	(working copy)
@@ -66,7 +66,7 @@
 	void handleNumSuffix(const QString&);
 	void handleNumStart(int);
 	void handlePEOffset(double);
-	void handlePEIndent(bool);
+	void handleSuffixAlignment(int);
 	void handlePECharStyle(const QString&);
 
 private slots:
Index: scribus/ui/propertywidget_pareffectbase.ui
===================================================================
--- scribus/ui/propertywidget_pareffectbase.ui	(revision 27701)
+++ scribus/ui/propertywidget_pareffectbase.ui	(working copy)
@@ -1,568 +1,575 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>PropertyWidget_ParEffectBase</class>
- <widget class="QFrame" name="PropertyWidget_ParEffectBase">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>295</width>
-    <height>274</height>
-   </rect>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <property name="spacing">
-    <number>4</number>
-   </property>
-   <property name="leftMargin">
-    <number>8</number>
-   </property>
-   <property name="topMargin">
-    <number>8</number>
-   </property>
-   <property name="rightMargin">
-    <number>8</number>
-   </property>
-   <property name="bottomMargin">
-    <number>8</number>
-   </property>
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout_6">
-     <item>
-      <widget class="FormWidget" name="peLabel">
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
-       <property name="label" stdset="0">
-        <string/>
-       </property>
-       <layout class="QHBoxLayout" name="horizontalLayout_7">
-        <property name="leftMargin">
-         <number>0</number>
-        </property>
-        <property name="topMargin">
-         <number>0</number>
-        </property>
-        <property name="rightMargin">
-         <number>0</number>
-        </property>
-        <property name="bottomMargin">
-         <number>0</number>
-        </property>
-        <item>
-         <widget class="QComboBox" name="peCombo"/>
-        </item>
-       </layout>
-      </widget>
-     </item>
-     <item>
-      <spacer name="horizontalSpacer_6">
-       <property name="orientation">
-        <enum>Qt::Orientation::Horizontal</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>0</width>
-         <height>20</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <widget class="StackedContainer" name="stackedWidget">
-     <property name="currentIndex">
-      <number>2</number>
-     </property>
-     <widget class="QWidget" name="pageDropCaps">
-      <layout class="QGridLayout" name="gridLayout">
-       <property name="leftMargin">
-        <number>0</number>
-       </property>
-       <property name="topMargin">
-        <number>4</number>
-       </property>
-       <property name="rightMargin">
-        <number>0</number>
-       </property>
-       <property name="bottomMargin">
-        <number>4</number>
-       </property>
-       <property name="horizontalSpacing">
-        <number>4</number>
-       </property>
-       <property name="verticalSpacing">
-        <number>8</number>
-       </property>
-       <item row="0" column="0">
-        <widget class="QLabel" name="dropCapLinesLabel">
-         <property name="toolTip">
-          <string>Number of lines used by the drop cap</string>
-         </property>
-         <property name="text">
-          <string>Lines:</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="1">
-        <widget class="QSpinBox" name="dropCapLines">
-         <property name="toolTip">
-          <string>Drop Cap Lines</string>
-         </property>
-         <property name="minimum">
-          <number>2</number>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="2">
-        <spacer name="horizontalSpacer">
-         <property name="orientation">
-          <enum>Qt::Orientation::Horizontal</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>40</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-      </layout>
-     </widget>
-     <widget class="QWidget" name="pageBulletedList">
-      <layout class="QGridLayout" name="gridLayout_6" columnstretch="0,0,0,1">
-       <property name="leftMargin">
-        <number>0</number>
-       </property>
-       <property name="topMargin">
-        <number>4</number>
-       </property>
-       <property name="rightMargin">
-        <number>0</number>
-       </property>
-       <property name="bottomMargin">
-        <number>4</number>
-       </property>
-       <property name="horizontalSpacing">
-        <number>4</number>
-       </property>
-       <property name="verticalSpacing">
-        <number>8</number>
-       </property>
-       <item row="0" column="2">
-        <widget class="QPushButton" name="bulletCharTableButton">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="toolTip">
-          <string>Enhanced Character Table to choose bullet characters</string>
-         </property>
-         <property name="text">
-          <string>Char Table</string>
-         </property>
-         <property name="checkable">
-          <bool>true</bool>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="0">
-        <widget class="QLabel" name="bulletCharLabel">
-         <property name="text">
-          <string>Bullet Char(s):</string>
-         </property>
-         <property name="buddy">
-          <cstring>bulletStrEdit</cstring>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="1">
-        <widget class="QComboBox" name="bulletStrEdit">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="editable">
-          <bool>true</bool>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="3">
-        <spacer name="horizontalSpacer_7">
-         <property name="orientation">
-          <enum>Qt::Orientation::Horizontal</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>0</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-      </layout>
-     </widget>
-     <widget class="QWidget" name="pageNumberedList">
-      <layout class="QGridLayout" name="gridLayout_5" columnstretch="0,0,0,0,0,0">
-       <property name="leftMargin">
-        <number>0</number>
-       </property>
-       <property name="topMargin">
-        <number>4</number>
-       </property>
-       <property name="rightMargin">
-        <number>0</number>
-       </property>
-       <property name="bottomMargin">
-        <number>4</number>
-       </property>
-       <property name="horizontalSpacing">
-        <number>4</number>
-       </property>
-       <property name="verticalSpacing">
-        <number>8</number>
-       </property>
-       <item row="2" column="5">
-        <spacer name="horizontalSpacer_4">
-         <property name="orientation">
-          <enum>Qt::Orientation::Horizontal</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>0</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item row="2" column="1">
-        <widget class="QSpinBox" name="numLevelSpin">
-         <property name="minimum">
-          <number>1</number>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="0">
-        <widget class="QLabel" name="numComboLabel">
-         <property name="text">
-          <string>Set:</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="3">
-        <widget class="QLabel" name="numStartLabel">
-         <property name="text">
-          <string>Start:</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="0">
-        <widget class="QLabel" name="numPrefixLabel">
-         <property name="text">
-          <string>Prefix:</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
-         </property>
-         <property name="buddy">
-          <cstring>numPrefix</cstring>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="3">
-        <widget class="QLabel" name="numSuffixLabel">
-         <property name="text">
-          <string>Suffix:</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
-         </property>
-         <property name="buddy">
-          <cstring>numSuffix</cstring>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="2">
-        <spacer name="horizontalSpacer_3">
-         <property name="orientation">
-          <enum>Qt::Orientation::Horizontal</enum>
-         </property>
-         <property name="sizeType">
-          <enum>QSizePolicy::Policy::Fixed</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>16</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item row="1" column="0">
-        <widget class="QLabel" name="numFormatLabel">
-         <property name="text">
-          <string>Style:</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
-         </property>
-         <property name="buddy">
-          <cstring>numFormatCombo</cstring>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="0">
-        <widget class="QLabel" name="numLevelLabel">
-         <property name="text">
-          <string>Level:</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
-         </property>
-         <property name="buddy">
-          <cstring>numLevelSpin</cstring>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="4">
-        <widget class="QSpinBox" name="numStart">
-         <property name="minimum">
-          <number>1</number>
-         </property>
-         <property name="maximum">
-          <number>999</number>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="1">
-        <widget class="QLineEdit" name="numPrefix"/>
-       </item>
-       <item row="3" column="4">
-        <widget class="QLineEdit" name="numSuffix"/>
-       </item>
-       <item row="1" column="1" colspan="4">
-        <widget class="NumFormatCombo" name="numFormatCombo">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="1" colspan="4">
-        <widget class="QComboBox" name="numComboBox">
-         <property name="currentIndex">
-          <number>-1</number>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </widget>
-   </item>
-   <item>
-    <widget class="QWidget" name="peGroup" native="true">
-     <layout class="QVBoxLayout" name="verticalLayout_2">
-      <property name="spacing">
-       <number>8</number>
-      </property>
-      <property name="leftMargin">
-       <number>0</number>
-      </property>
-      <property name="topMargin">
-       <number>0</number>
-      </property>
-      <property name="rightMargin">
-       <number>0</number>
-      </property>
-      <property name="bottomMargin">
-       <number>0</number>
-      </property>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_5">
-        <property name="spacing">
-         <number>20</number>
-        </property>
-        <item>
-         <widget class="FormWidget" name="peOffsetLabel">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="label" stdset="0">
-           <string/>
-          </property>
-          <layout class="QHBoxLayout" name="horizontalLayout_2">
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="ScrSpinBox" name="peOffset">
-             <property name="toolTip">
-              <string>Paragraph Effects characters offset</string>
-             </property>
-             <property name="minimum">
-              <double>-3000.000000000000000</double>
-             </property>
-             <property name="maximum">
-              <double>3000.000000000000000</double>
-             </property>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="peIndent">
-          <property name="text">
-           <string>Auto-Indent</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <spacer name="horizontalSpacer_5">
-          <property name="orientation">
-           <enum>Qt::Orientation::Horizontal</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>0</width>
-            <height>20</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout">
-        <property name="spacing">
-         <number>4</number>
-        </property>
-        <item>
-         <widget class="FormWidget" name="peCharStyleLabel">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="label" stdset="0">
-           <string/>
-          </property>
-          <layout class="QHBoxLayout" name="horizontalLayout_3">
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <widget class="CharStyleComboBox" name="peCharStyleCombo">
-             <property name="toolTip">
-              <string>Choose Character Style or leave blank to use default Paragraph Style</string>
-             </property>
-            </widget>
-           </item>
-          </layout>
-         </widget>
-        </item>
-        <item>
-         <spacer name="horizontalSpacer_2">
-          <property name="orientation">
-           <enum>Qt::Orientation::Horizontal</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>0</width>
-            <height>20</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>FormWidget</class>
-   <extends>QWidget</extends>
-   <header>ui/widgets/form_widget.h</header>
-   <container>1</container>
-  </customwidget>
-  <customwidget>
-   <class>ScrSpinBox</class>
-   <extends>QDoubleSpinBox</extends>
-   <header location="global">ui/scrspinbox.h</header>
-  </customwidget>
-  <customwidget>
-   <class>CharStyleComboBox</class>
-   <extends>QComboBox</extends>
-   <header>ui/stylecombos.h</header>
-  </customwidget>
-  <customwidget>
-   <class>NumFormatCombo</class>
-   <extends>QComboBox</extends>
-   <header>ui/numformatcombo.h</header>
-  </customwidget>
-  <customwidget>
-   <class>StackedContainer</class>
-   <extends>QStackedWidget</extends>
-   <header>ui/widgets/stacked_container.h</header>
-   <container>1</container>
-  </customwidget>
- </customwidgets>
- <tabstops>
-  <tabstop>peCombo</tabstop>
-  <tabstop>numComboBox</tabstop>
-  <tabstop>numFormatCombo</tabstop>
-  <tabstop>numLevelSpin</tabstop>
-  <tabstop>numStart</tabstop>
-  <tabstop>numPrefix</tabstop>
-  <tabstop>numSuffix</tabstop>
-  <tabstop>peOffset</tabstop>
-  <tabstop>peIndent</tabstop>
-  <tabstop>peCharStyleCombo</tabstop>
-  <tabstop>dropCapLines</tabstop>
-  <tabstop>bulletStrEdit</tabstop>
-  <tabstop>bulletCharTableButton</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PropertyWidget_ParEffectBase</class>
+ <widget class="QFrame" name="PropertyWidget_ParEffectBase">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>295</width>
+    <height>274</height>
+   </rect>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>4</number>
+   </property>
+   <property name="leftMargin">
+    <number>8</number>
+   </property>
+   <property name="topMargin">
+    <number>8</number>
+   </property>
+   <property name="rightMargin">
+    <number>8</number>
+   </property>
+   <property name="bottomMargin">
+    <number>8</number>
+   </property>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_6">
+     <item>
+      <widget class="FormWidget" name="peLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="label" stdset="0">
+        <string/>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout_7">
+        <property name="leftMargin">
+         <number>0</number>
+        </property>
+        <property name="topMargin">
+         <number>0</number>
+        </property>
+        <property name="rightMargin">
+         <number>0</number>
+        </property>
+        <property name="bottomMargin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QComboBox" name="peCombo"/>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_6">
+       <property name="orientation">
+        <enum>Qt::Orientation::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>0</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="StackedContainer" name="stackedWidget">
+     <property name="currentIndex">
+      <number>2</number>
+     </property>
+     <widget class="QWidget" name="pageDropCaps">
+      <layout class="QGridLayout" name="gridLayout">
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>4</number>
+       </property>
+       <property name="horizontalSpacing">
+        <number>4</number>
+       </property>
+       <property name="verticalSpacing">
+        <number>8</number>
+       </property>
+       <item row="0" column="0">
+        <widget class="QLabel" name="dropCapLinesLabel">
+         <property name="toolTip">
+          <string>Number of lines used by the drop cap</string>
+         </property>
+         <property name="text">
+          <string>Lines:</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QSpinBox" name="dropCapLines">
+         <property name="toolTip">
+          <string>Drop Cap Lines</string>
+         </property>
+         <property name="minimum">
+          <number>2</number>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="2">
+        <spacer name="horizontalSpacer">
+         <property name="orientation">
+          <enum>Qt::Orientation::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>40</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="pageBulletedList">
+      <layout class="QGridLayout" name="gridLayout_6" columnstretch="0,0,0,1">
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>4</number>
+       </property>
+       <property name="horizontalSpacing">
+        <number>4</number>
+       </property>
+       <property name="verticalSpacing">
+        <number>8</number>
+       </property>
+       <item row="0" column="2">
+        <widget class="QPushButton" name="bulletCharTableButton">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="toolTip">
+          <string>Enhanced Character Table to choose bullet characters</string>
+         </property>
+         <property name="text">
+          <string>Char Table</string>
+         </property>
+         <property name="checkable">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QLabel" name="bulletCharLabel">
+         <property name="text">
+          <string>Bullet Char(s):</string>
+         </property>
+         <property name="buddy">
+          <cstring>bulletStrEdit</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QComboBox" name="bulletStrEdit">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="editable">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="3">
+        <spacer name="horizontalSpacer_7">
+         <property name="orientation">
+          <enum>Qt::Orientation::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>0</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="pageNumberedList">
+      <layout class="QGridLayout" name="gridLayout_5" columnstretch="0,0,0,0,0,0">
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>4</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>4</number>
+       </property>
+       <property name="horizontalSpacing">
+        <number>4</number>
+       </property>
+       <property name="verticalSpacing">
+        <number>8</number>
+       </property>
+       <item row="2" column="5">
+        <spacer name="horizontalSpacer_4">
+         <property name="orientation">
+          <enum>Qt::Orientation::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>0</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="2" column="1">
+        <widget class="QSpinBox" name="numLevelSpin">
+         <property name="minimum">
+          <number>1</number>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="0">
+        <widget class="QLabel" name="numComboLabel">
+         <property name="text">
+          <string>Set:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="3">
+        <widget class="QLabel" name="numStartLabel">
+         <property name="text">
+          <string>Start:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="0">
+        <widget class="QLabel" name="numPrefixLabel">
+         <property name="text">
+          <string>Prefix:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
+         </property>
+         <property name="buddy">
+          <cstring>numPrefix</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="3">
+        <widget class="QLabel" name="numSuffixLabel">
+         <property name="text">
+          <string>Suffix:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
+         </property>
+         <property name="buddy">
+          <cstring>numSuffix</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="2">
+        <spacer name="horizontalSpacer_3">
+         <property name="orientation">
+          <enum>Qt::Orientation::Horizontal</enum>
+         </property>
+         <property name="sizeType">
+          <enum>QSizePolicy::Policy::Fixed</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>16</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item row="1" column="0">
+        <widget class="QLabel" name="numFormatLabel">
+         <property name="text">
+          <string>Style:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
+         </property>
+         <property name="buddy">
+          <cstring>numFormatCombo</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="numLevelLabel">
+         <property name="text">
+          <string>Level:</string>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
+         </property>
+         <property name="buddy">
+          <cstring>numLevelSpin</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="4">
+        <widget class="QSpinBox" name="numStart">
+         <property name="minimum">
+          <number>1</number>
+         </property>
+         <property name="maximum">
+          <number>999</number>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="1">
+        <widget class="QLineEdit" name="numPrefix"/>
+       </item>
+       <item row="3" column="4">
+        <widget class="QLineEdit" name="numSuffix"/>
+       </item>
+       <item row="1" column="1" colspan="4">
+        <widget class="NumFormatCombo" name="numFormatCombo">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1" colspan="4">
+        <widget class="QComboBox" name="numComboBox">
+         <property name="currentIndex">
+          <number>-1</number>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="peGroup" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>8</number>
+      </property>
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_5">
+        <property name="spacing">
+         <number>20</number>
+        </property>
+        <item>
+         <widget class="FormWidget" name="peOffsetLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="label" stdset="0">
+           <string/>
+          </property>
+          <layout class="QHBoxLayout" name="horizontalLayout_2">
+           <property name="leftMargin">
+            <number>0</number>
+           </property>
+           <property name="topMargin">
+            <number>0</number>
+           </property>
+           <property name="rightMargin">
+            <number>0</number>
+           </property>
+           <property name="bottomMargin">
+            <number>0</number>
+           </property>
+           <item>
+            <widget class="ScrSpinBox" name="peOffset">
+             <property name="toolTip">
+              <string>Paragraph Effects characters offset</string>
+             </property>
+             <property name="minimum">
+              <double>-3000.000000000000000</double>
+             </property>
+             <property name="maximum">
+              <double>3000.000000000000000</double>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+<item>
+         <widget class="QLabel" name="suffixAlignmentLabel">
+          <property name="text">
+           <string>Suffix Align:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="suffixAlignmentCombo">
+          <property name="toolTip">
+           <string>Alignment of suffix characters in numbered lists</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_5">
+          <property name="orientation">
+           <enum>Qt::Orientation::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>0</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <property name="spacing">
+         <number>4</number>
+        </property>
+        <item>
+         <widget class="FormWidget" name="peCharStyleLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="label" stdset="0">
+           <string/>
+          </property>
+          <layout class="QHBoxLayout" name="horizontalLayout_3">
+           <property name="leftMargin">
+            <number>0</number>
+           </property>
+           <property name="topMargin">
+            <number>0</number>
+           </property>
+           <property name="rightMargin">
+            <number>0</number>
+           </property>
+           <property name="bottomMargin">
+            <number>0</number>
+           </property>
+           <item>
+            <widget class="CharStyleComboBox" name="peCharStyleCombo">
+             <property name="toolTip">
+              <string>Choose Character Style or leave blank to use default Paragraph Style</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Orientation::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>0</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>FormWidget</class>
+   <extends>QWidget</extends>
+   <header>ui/widgets/form_widget.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>ScrSpinBox</class>
+   <extends>QDoubleSpinBox</extends>
+   <header location="global">ui/scrspinbox.h</header>
+  </customwidget>
+  <customwidget>
+   <class>CharStyleComboBox</class>
+   <extends>QComboBox</extends>
+   <header>ui/stylecombos.h</header>
+  </customwidget>
+  <customwidget>
+   <class>NumFormatCombo</class>
+   <extends>QComboBox</extends>
+   <header>ui/numformatcombo.h</header>
+  </customwidget>
+  <customwidget>
+   <class>StackedContainer</class>
+   <extends>QStackedWidget</extends>
+   <header>ui/widgets/stacked_container.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>peCombo</tabstop>
+  <tabstop>numComboBox</tabstop>
+  <tabstop>numFormatCombo</tabstop>
+  <tabstop>numLevelSpin</tabstop>
+  <tabstop>numStart</tabstop>
+  <tabstop>numPrefix</tabstop>
+  <tabstop>numSuffix</tabstop>
+<tabstop>peOffset</tabstop>
+  <tabstop>suffixAlignmentCombo</tabstop>
+  <tabstop>peCharStyleCombo</tabstop>
+  <tabstop>dropCapLines</tabstop>
+  <tabstop>bulletStrEdit</tabstop>
+  <tabstop>bulletCharTableButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
Index: scribus/ui/smpstylewidget.cpp
===================================================================
--- scribus/ui/smpstylewidget.cpp	(revision 27701)
+++ scribus/ui/smpstylewidget.cpp	(working copy)
@@ -25,7 +25,6 @@
 	return al == bl;
 }
 
-
 SMPStyleWidget::SMPStyleWidget(ScribusDoc* doc, StyleSet<CharStyle> *cstyles) :
 	m_Doc(doc),
 	m_cstyles(cstyles)
@@ -74,6 +73,7 @@
 	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 @@
 	numRestartCombo->blockSignals(numRestartComboBlocked);
 
 	fillPECombo();
-
+	fillSuffixAlignmentCombo();
 	backgroundColor->colorButton->setPersistentToolTip( tr("Background color of selected text"));
 	backgroundColor->setText(tr("Background"));
 }
@@ -303,8 +303,19 @@
 
 		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<int>(displayAlign));
+		suffixAlignmentCombo->setCurrentItem(suffixAlignIndex, pstyle->isInhSuffixAlignment());
+		suffixAlignmentCombo->setParentItem(suffixAlignmentCombo->findData(static_cast<int>(parentDisplayAlign)));
+
 		dropCapLines->setValue(pstyle->dropCapLines(), pstyle->isInhDropCapLines());
 		dropCapLines->setParentValue(parent->dropCapLines());
 		bulletStrEdit->setEditText(pstyle->bulletStr());
@@ -356,10 +367,13 @@
 		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<int>(displayAlign));
+		suffixAlignmentCombo->setCurrentItem((suffixAlignIndex >= 0) ? suffixAlignIndex : 0);
 		dropCapLines->setValue(pstyle->dropCapLines());
 		bulletStrEdit->setEditText(pstyle->bulletStr());
 		setWidgetBoldFont(bulletCharLabel, false);
@@ -1000,6 +1014,17 @@
 	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 @@
 		peGroup->setVisible(false);
 		peCombo->setCurrentIndex(0);
 	}
+	bool isNumberedList = (id == 3);
+	suffixAlignmentLabel->setVisible(isNumberedList);
+	suffixAlignmentCombo->setVisible(isNumberedList);
 }
 
 void SMPStyleWidget::showDropCap(const QList<ParagraphStyle*> &pstyles, const QList<CharStyle> &cstyles, int unitIndex)
Index: scribus/ui/smpstylewidget.h
===================================================================
--- scribus/ui/smpstylewidget.h	(revision 27701)
+++ scribus/ui/smpstylewidget.h	(working copy)
@@ -52,6 +52,7 @@
 	void fillNumerationsCombo();
 	void fillNumRestartCombo();
 	void fillPECombo();
+	void fillSuffixAlignmentCombo();
 	void setParagraphEffect(int);
 	void showColors(const QList<ParagraphStyle*> &cstyles);
 	void showLineSpacing(const QList<ParagraphStyle*> &pstyles);
Index: scribus/ui/smpstylewidget.ui
===================================================================
--- scribus/ui/smpstylewidget.ui	(revision 27701)
+++ scribus/ui/smpstylewidget.ui	(working copy)
@@ -29,7 +29,7 @@
    <item>
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>0</number>
+      <number>1</number>
      </property>
      <widget class="QWidget" name="tab">
       <attribute name="title">
@@ -181,7 +181,7 @@
             <item>
              <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1">
               <item>
-               <widget class="FormWidget" name="consecutiveHyphenLabel">
+               <widget class="FormWidget" name="consecutiveHyphenLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -280,7 +280,7 @@
              <number>4</number>
             </property>
             <item row="0" column="1">
-             <widget class="FormWidget" name="minSpaceLabel">
+             <widget class="FormWidget" name="minSpaceLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -326,7 +326,7 @@
              </widget>
             </item>
             <item row="1" column="2">
-             <widget class="FormWidget" name="maxGlyphExtLabel">
+             <widget class="FormWidget" name="maxGlyphExtLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -379,7 +379,7 @@
              </spacer>
             </item>
             <item row="0" column="0">
-             <widget class="FormWidget" name="formWidget_3">
+             <widget class="FormWidget" name="formWidget_3" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -389,7 +389,7 @@
               <property name="label" stdset="0">
                <string/>
               </property>
-              <property name="preserveLabelSpace">
+              <property name="preserveLabelSpace" stdset="0">
                <bool>true</bool>
               </property>
               <layout class="QHBoxLayout" name="horizontalLayout">
@@ -419,7 +419,7 @@
              </widget>
             </item>
             <item row="1" column="1">
-             <widget class="FormWidget" name="minGlyphExtLabel">
+             <widget class="FormWidget" name="minGlyphExtLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -459,7 +459,7 @@
              </widget>
             </item>
             <item row="1" column="0">
-             <widget class="FormWidget" name="formWidget_4">
+             <widget class="FormWidget" name="formWidget_4" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -469,7 +469,7 @@
               <property name="label" stdset="0">
                <string/>
               </property>
-              <property name="preserveLabelSpace">
+              <property name="preserveLabelSpace" stdset="0">
                <bool>true</bool>
               </property>
               <layout class="QHBoxLayout" name="horizontalLayout_2">
@@ -597,7 +597,7 @@
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="lineSpacingLabel">
+               <widget class="FormWidget" name="lineSpacingLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -673,7 +673,7 @@
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="spaceAboveLabel">
+               <widget class="FormWidget" name="spaceAboveLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -710,7 +710,7 @@
                </widget>
               </item>
               <item>
-               <widget class="FormWidget" name="spaceBelowLabel">
+               <widget class="FormWidget" name="spaceBelowLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -804,7 +804,7 @@
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="keepLabelStart">
+               <widget class="FormWidget" name="keepLabelStart" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -844,7 +844,7 @@
                </widget>
               </item>
               <item>
-               <widget class="FormWidget" name="keepLabelEnd">
+               <widget class="FormWidget" name="keepLabelEnd" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -1021,7 +1021,7 @@
        <item>
         <layout class="QHBoxLayout" name="horizontalLayout_20">
          <item>
-          <widget class="FormWidget" name="peLabel">
+          <widget class="FormWidget" name="peLabel" native="true">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
              <horstretch>0</horstretch>
@@ -1441,7 +1441,7 @@
               </widget>
              </item>
              <item row="0" column="6">
-              <widget class="FormWidget" name="formWidget_2">
+              <widget class="FormWidget" name="formWidget_2" native="true">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                  <horstretch>0</horstretch>
@@ -1451,10 +1451,7 @@
                <property name="label" stdset="0">
                 <string>New Set:</string>
                </property>
-               <property name="direction">
-                <enum>FormWidget::LabelPosition::Left</enum>
-               </property>
-               <property name="useSmallFont">
+               <property name="useSmallFont" stdset="0">
                 <bool>false</bool>
                </property>
                <layout class="QHBoxLayout" name="horizontalLayout_25">
@@ -1476,6 +1473,20 @@
                </layout>
               </widget>
              </item>
+             <item row="3" column="6">
+              <widget class="SMScComboBox" name="suffixAlignmentCombo">
+               <property name="toolTip">
+                <string>Alignment of suffix characters in numbered lists</string>
+               </property>
+              </widget>
+             </item>
+             <item row="3" column="5">
+              <widget class="QLabel" name="suffixAlignmentLabel">
+               <property name="text">
+                <string>Suffix Align:</string>
+               </property>
+              </widget>
+             </item>
             </layout>
            </item>
           </layout>
@@ -1506,7 +1517,7 @@
              <number>16</number>
             </property>
             <item>
-             <widget class="FormWidget" name="distFromTextLabel">
+             <widget class="FormWidget" name="distFromTextLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -1546,46 +1557,6 @@
              </widget>
             </item>
             <item>
-             <widget class="FormWidget" name="formWidget">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="label" stdset="0">
-               <string/>
-              </property>
-              <property name="preserveLabelSpace">
-               <bool>true</bool>
-              </property>
-              <layout class="QHBoxLayout" name="horizontalLayout_24">
-               <property name="leftMargin">
-                <number>0</number>
-               </property>
-               <property name="topMargin">
-                <number>0</number>
-               </property>
-               <property name="rightMargin">
-                <number>0</number>
-               </property>
-               <property name="bottomMargin">
-                <number>0</number>
-               </property>
-               <item>
-                <widget class="SMCheckBox" name="parEffectIndentBox">
-                 <property name="toolTip">
-                  <string>Hang Paragraph Effect before paragraph indent</string>
-                 </property>
-                 <property name="text">
-                  <string>Auto-Indent</string>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </widget>
-            </item>
-            <item>
              <spacer name="horizontalSpacer_14">
               <property name="orientation">
                <enum>Qt::Orientation::Horizontal</enum>
@@ -1606,7 +1577,7 @@
              <number>16</number>
             </property>
             <item>
-             <widget class="FormWidget" name="parEffectCharStyleComboLabel">
+             <widget class="FormWidget" name="parEffectCharStyleComboLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -1792,7 +1763,6 @@
   <tabstop>parentParEffectsButton</tabstop>
   <tabstop>dropCapLines</tabstop>
   <tabstop>parEffectOffset</tabstop>
-  <tabstop>parEffectIndentBox</tabstop>
   <tabstop>parEffectCharStyleCombo</tabstop>
   <tabstop>numPrefix</tabstop>
   <tabstop>numSuffix</tabstop>
Index: scribus/ui/smtextstyles.cpp
===================================================================
--- scribus/ui/smtextstyles.cpp	(revision 27701)
+++ scribus/ui/smtextstyles.cpp	(working copy)
@@ -37,7 +37,6 @@
 #include "units.h"
 #include "util.h"
 
-
 SMParagraphStyle::SMParagraphStyle(SMCharacterStyle* cstyleItem):
 	m_cstyleItem(cstyleItem)
 {
@@ -511,7 +510,7 @@
 	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 @@
 	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 @@
 	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<ParagraphStyle::SuffixAlignment>(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();
 }
 
Index: scribus/ui/smtextstyles.h
===================================================================
--- scribus/ui/smtextstyles.h	(revision 27701)
+++ scribus/ui/smtextstyles.h	(working copy)
@@ -77,7 +77,7 @@
 	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);
suffixalignment v1.patch (76,522 bytes)   
suffix-align.png (75,581 bytes)   
suffix-align.png (75,581 bytes)   

qirat

2026-07-09 12:19

reporter   ~0054002

I tested, @Fahad. It seems even selecting "right" does not align the suffix perfectly. See attached screenshot (notice the guideline).

Would you kindly give the patch a try that I attached to issue 0017768 ?

It has 3 options (in case suffix is not used) as you have and a 4th option "Suffix" which seem to align it better. Your thoughts are welcome.
align_suffix_test.png (59,655 bytes)   
align_suffix_test.png (59,655 bytes)   

qirat

2026-07-09 13:10

reporter   ~0054003

I didnt know that about auto-ubdent UI. Here is the updated one.

I do not know much of the coding side. So kindly take that as a grain of salt but this works great for me.
list-marker-alignment-v1.2-r27703-remove-autoindent-ui.patch (44,571 bytes)   
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<int>(itemText.nrOfParagraphs());
+		const int para = qBound(0, is->getInt("PARA"), maxPara);
+		pos = itemText.endOfParagraph(static_cast<uint>(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 <QDebug>
+#include <QHash>
 #include <QList>
 #include <QTransform>
+#include <QVector>
 #include <QPalette>
 #include <QPoint>
 #include <QPolygon>
@@ -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<GlyphCluster>& glyphClusters, int markerStart, int markerEnd, int suffixLength)
+	{
+		NumberedListMarkerMetrics metrics;
+		QVector<double> 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<GlyphCluster> glyphClusters; // = textShaper.shape();
+		QHash<int, NumberedListMarkerMetrics> 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<QString, double> maxMarkerWidthForList;
+			QHash<QString, double> maxSuffixAnchorForList;
+			QHash<int, QString> 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<QString, double> 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<ParagraphStyle::NumAlignment>(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<ParagraphStyle::NumAlignment>(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<int>(style.hasNum()));
 	if ( ! style.isInhNumFormat())
 		docu.writeAttribute("NumerationFormat", style.numFormat());
+	if ( ! style.isInhNumAlignment())
+		docu.writeAttribute("NumerationAlignment", static_cast<int>(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<ParagraphStyle::NumAlignment>(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<ParagraphStyle::NumAlignment>(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<int>(style.hasNum()));
 	if (!style.isInhNumFormat())
 		docu.writeAttribute("NumerationFormat", style.numFormat());
+	if (!style.isInhNumAlignment())
+		docu.writeAttribute("NumerationAlignment", static_cast<int>(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<ParagraphStyle::NumAlignment>(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<ParagraphStyle::NumAlignment>(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<int>(style.hasNum()));
 	if (!style.isInhNumFormat())
 		docu.writeAttribute("NumerationFormat", style.numFormat());
+	if (!style.isInhNumAlignment())
+		docu.writeAttribute("NumerationAlignment", static_cast<int>(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<ParagraphStyle>(Um::SetStyle);
 						is->set("SET_PARASTYLE");
 						is->set("POS", pos);
+						is->set("PARA", static_cast<int>(currItem->itemText.nrOfParagraph(pos)));
 						is->setStates(currItem->itemText.paragraphStyle(pos), newStyle);
 						m_undoManager->action(currItem, is);
 					}
@@ -9784,6 +9785,7 @@
 				auto *is = new ScOldNewState<ParagraphStyle>(Um::SetStyle);
 				is->set("SET_PARASTYLE");
 				is->set("POS", stop);
+				is->set("PARA", static_cast<int>(currItem->itemText.nrOfParagraph(stop)));
 				is->setStates(currItem->itemText.paragraphStyle(stop), newStyle2);
 				m_undoManager->action(currItem, is);
 			}
@@ -9956,6 +9958,7 @@
 						auto *is = new ScOldNewState<ParagraphStyle>(Um::SetStyle);
 						is->set("APPLY_PARASTYLE");
 						is->set("POS", pos);
+						is->set("PARA", static_cast<int>(currItem->itemText.nrOfParagraph(pos)));
 						is->setStates(currItem->itemText.paragraphStyle(pos), newStyle);
 						m_undoManager->action(currItem, is);
 					}
@@ -9967,6 +9970,7 @@
 				auto *is = new ScOldNewState<ParagraphStyle>(Um::SetStyle);
 				is->set("APPLY_PARASTYLE");
 				is->set("POS", stop);
+				is->set("PARA", static_cast<int>(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<int>(val));
 }
 
+static QString toXMLString(ParagraphStyle::NumAlignment val)
+{
+	return QString::number(static_cast<int>(val));
+}
+
 static QString toXMLString(const QList<ParagraphStyle::TabRecord> & )
 {
 	return "dummy";
@@ -356,6 +361,12 @@
 	return parseEnum<ParagraphStyle::LineSpacingMode>(str);
 }
 
+template<>
+ParagraphStyle::NumAlignment parse<ParagraphStyle::NumAlignment>(const Xml_string& str)
+{
+	return parseEnum<ParagraphStyle::NumAlignment>(str);
+}
+
 
 using Tablist = QList<ParagraphStyle::TabRecord>;
 

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<int>(ParagraphStyle::NumLeftAligned));
+	numAlignmentCombo->addItem(tr("Center"), static_cast<int>(ParagraphStyle::NumCentered));
+	numAlignmentCombo->addItem(tr("Right"), static_cast<int>(ParagraphStyle::NumRightAligned));
+	numAlignmentCombo->addItem(tr("Suffix"), static_cast<int>(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<int>(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<ParagraphStyle::NumAlignment>(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<ParagraphStyle::NumAlignment>(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 @@
          </property>
         </widget>
        </item>
+
       </layout>
      </widget>
     </widget>
@@ -439,9 +440,25 @@
          </widget>
         </item>
         <item>
-         <widget class="QCheckBox" name="peIndent">
+         <widget class="QLabel" name="numAlignmentLabel">
+          <property name="toolTip">
+           <string>Align the generated list marker inside its marker area</string>
+          </property>
           <property name="text">
-           <string>Auto-Indent</string>
+           <string>Marker alignment:</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
+          </property>
+          <property name="buddy">
+           <cstring>numAlignmentCombo</cstring>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="numAlignmentCombo">
+          <property name="toolTip">
+           <string>Use Suffix to align suffixes such as dots or parentheses in 1., 10., 100.</string>
           </property>
          </widget>
         </item>
@@ -557,7 +574,7 @@
   <tabstop>numPrefix</tabstop>
   <tabstop>numSuffix</tabstop>
   <tabstop>peOffset</tabstop>
-  <tabstop>peIndent</tabstop>
+  <tabstop>numAlignmentCombo</tabstop>
   <tabstop>peCharStyleCombo</tabstop>
   <tabstop>dropCapLines</tabstop>
   <tabstop>bulletStrEdit</tabstop>

Index: scribus/ui/smpstylewidget.cpp
===================================================================
--- scribus/ui/smpstylewidget.cpp	(revision 27703)
+++ scribus/ui/smpstylewidget.cpp	(working copy)
@@ -6,6 +6,7 @@
 */
 
 #include <QEvent>
+#include <QSignalBlocker>
 
 
 #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<int>(pstyle->numAlignment()), pstyle->isInhNumAlignment());
+		numAlignmentCombo->setParentItem(numAlignmentCombo->getItemIndexForData(static_cast<int>(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<int>(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<int>(ParagraphStyle::NumLeftAligned));
+	numAlignmentCombo->addItem(tr("Center"), static_cast<int>(ParagraphStyle::NumCentered));
+	numAlignmentCombo->addItem(tr("Right"), static_cast<int>(ParagraphStyle::NumRightAligned));
+	numAlignmentCombo->addItem(tr("Suffix"), static_cast<int>(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<ParagraphStyle *> &pstyles, const QList<CharStyle> &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<int>(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 @@
                </layout>
               </widget>
              </item>
+
             </layout>
            </item>
           </layout>
@@ -1546,44 +1547,41 @@
              </widget>
             </item>
             <item>
-             <widget class="FormWidget" name="formWidget">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="label" stdset="0">
-               <string/>
-              </property>
-              <property name="preserveLabelSpace">
-               <bool>true</bool>
-              </property>
-              <layout class="QHBoxLayout" name="horizontalLayout_24">
-               <property name="leftMargin">
-                <number>0</number>
-               </property>
-               <property name="topMargin">
-                <number>0</number>
-               </property>
-               <property name="rightMargin">
-                <number>0</number>
-               </property>
-               <property name="bottomMargin">
-                <number>0</number>
-               </property>
-               <item>
-                <widget class="SMCheckBox" name="parEffectIndentBox">
-                 <property name="toolTip">
-                  <string>Hang Paragraph Effect before paragraph indent</string>
-                 </property>
-                 <property name="text">
-                  <string>Auto-Indent</string>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </widget>
+              <widget class="FormWidget" name="numAlignmentLabel">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="toolTip">
+                <string>Align the generated list marker inside its marker area</string>
+               </property>
+               <property name="label" stdset="0">
+                <string>Marker alignment:</string>
+               </property>
+               <layout class="QHBoxLayout" name="horizontalLayout_24">
+                <property name="leftMargin">
+                 <number>0</number>
+                </property>
+                <property name="topMargin">
+                 <number>0</number>
+                </property>
+                <property name="rightMargin">
+                 <number>0</number>
+                </property>
+                <property name="bottomMargin">
+                 <number>0</number>
+                </property>
+                <item>
+                 <widget class="SMScComboBox" name="numAlignmentCombo">
+                  <property name="toolTip">
+                   <string>Use Suffix to align suffixes such as dots or parentheses in 1., 10., 100.</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </widget>
             </item>
             <item>
              <spacer name="horizontalSpacer_14">
@@ -1792,7 +1790,7 @@
   <tabstop>parentParEffectsButton</tabstop>
   <tabstop>dropCapLines</tabstop>
   <tabstop>parEffectOffset</tabstop>
-  <tabstop>parEffectIndentBox</tabstop>
+  <tabstop>numAlignmentCombo</tabstop>
   <tabstop>parEffectCharStyleCombo</tabstop>
   <tabstop>numPrefix</tabstop>
   <tabstop>numSuffix</tabstop>

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<ParagraphStyle::NumAlignment>(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<class ItemType> 
 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<QString,Keys> keyMap();
 
 public slots:
+	void setPaletteShown(bool visible) override;
 	void setDoc(ScribusDoc *doc);
 	void languageChange();
 	void unitChange();

qirat

2026-07-10 01:02

reporter   ~0054006

with* a grain of salt... Lol

Fahad

2026-07-13 15:01

developer   ~0054029

First of all, thank you so much for putting together the second-list-marker-alignment-indent-ui.patch and offering your help! I really appreciate the time and effort you took to look into the performance issues and propose a clever workaround. Your approach to reusing the main layout loop's text feed was a great piece of engineering to avoid redundant shaping.

After diving deep into the performance profile and looking at how other major software handles this, I wanted to share why I couldn't use that exact patch as-is, what the underlying problem turned out to be, and how the final design solves it permanently.

The Problem with the First Two Approaches
The core feature—automatically fitting the list alignment precisely to the widest live marker—is inherently expensive.
- My original patch (v1) was perfectly accurate across multiple linked text frames, but it was incredibly slow. It forced a full re-shape of the entire story from scratch on every single keystroke.
- Your patch genuinely fixed the duplicate shaping bug by reusing the layout's active ShapedTextFeed. However, because it started measuring from the current frame (firstInFrame()) instead of the very beginning of the story (character 0), it introduced a correctness bug: if a numbered list spans across multiple linked frames, each frame only sees its own local text. This causes the alignment to break and become inconsistent across frame boundaries.

I was stuck in a trade-off: my way was correct but slow; your way was fast but broke cross-frame alignment.

How Industry Giants Solve This:

To figure out a way out of this trap, I researched how LibreOffice, InDesign, and LaTeX handle list alignment. It turns out none of them do live document scanning like I was trying to do:

- LibreOffice & InDesign: They don't measure the numbers at all. They use a fixed-width box (a user-defined indent/tab setting) and align the text inside that box. If your numbers get too big, they clip or overflow until the user manually changes the setting.

- LaTeX (enumitem): LaTeX has an "auto-fit" feature, but it doesn't scan the document either. It takes a hardcoded placeholder guess (like "viii" for Roman numerals) and measures just that one string to determine the width.

My New, Final Approach:

I realized I could get the best of both worlds: the instant O(1) performance of LaTeX/LibreOffice, combined with the exact accuracy of my original live-updating feature.

Instead of scanning real text frames or glyphs in the document, my final patch derives the maximum width using synthetic string generation:
1. Track the Max Counter: Scribus already tracks list counts during layout. I added a small field (m_maxCounters) to remember the highest number a list actually reaches.
2. Generate the Worst-Case String: For normal numbers (1, 2, 3), the highest number is always the widest string. For non-monotonic lists (like Roman numerals, where 38 is XXXVIII—much wider than 39), I run a lightning-fast, pure-arithmetic string loop from 1 to the max count to find the longest text candidate.
3. Measure a "Ghost" String: I pass only that one winning candidate string to a lightweight, isolated text-shaper probe. It never touches the real document text or frames.
4. Global Cache: The resulting width is cached in StoryText's shared memory, making it instantly available across all linked frames without any recalculations.

This completely eliminates the heavy story-scanning loops, maintains absolute cross-frame correctness, and actually outperforms what LaTeX does because it uses the real list count rather than a hardcoded guess!

The result:

    Same correctness as your original patch (handles multi-frame chains perfectly).

    No full-document reshaping—performance is O(1) in most cases.

    No frame-boundary bugs (since we don't rely on frame text at all).

    Better UX than industry standards—we keep the live auto-fit.

Finally, please the new patch with huge document.
one last note, I couldn't reproduce your problem in my machine. it may be caching problem.
suffixalignment v2.patch (51,056 bytes)   
diff --git a/scribus/numeration.h b/scribus/numeration.h
index 88857e042..a3bad3aed 100644
--- a/scribus/numeration.h
+++ b/scribus/numeration.h
@@ -77,6 +77,7 @@ struct NumStruct
 	QString m_name;
 	QList<Numeration> m_nums;
 	QList<int> m_counters;
+	QList<int> 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 1c5b95c58..ed0eb1df3 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<NumFormat>(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<GlyphCluster> 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<GlyphCluster> 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<QString, double>& 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<NumFormat>(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<QString, double> 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.
diff --git a/scribus/plugins/fileloader/scribus150format/scribus150format.cpp b/scribus/plugins/fileloader/scribus150format/scribus150format.cpp
index 424ddcfbc..763a573ba 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<bool>(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<bool>(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 a6e7b4baa..ffebaef12 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<int>(style.parEffectIndent()));
 	if ( ! style.isInhHasDropCap())
 		docu.writeAttribute("DROP", static_cast<int>(style.hasDropCap()));
 	if ( ! style.isInhDropCapLines())
diff --git a/scribus/plugins/fileloader/scribus170format/scribus170format.cpp b/scribus/plugins/fileloader/scribus170format/scribus170format.cpp
index c18650807..a08b06396 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<bool>(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<bool>(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 3b7a5ec1c..1e8c88068 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<int>(style.parEffectIndent()));
 	if (!style.isInhHasDropCap())
 		docu.writeAttribute("DROP", static_cast<int>(style.hasDropCap()));
 	if (!style.isInhDropCapLines())
diff --git a/scribus/plugins/fileloader/scribus171format/scribus171format.cpp b/scribus/plugins/fileloader/scribus171format/scribus171format.cpp
index 6c96651fb..a1372df7f 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<bool>(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<ParagraphStyle::SuffixAlignment>(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<bool>(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<ParagraphStyle::SuffixAlignment>(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 ae959bec6..2608bc355 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<int>(style.parEffectIndent()));
 	if (!style.isInhHasDropCap())
 		docu.writeAttribute("HasDropCap", static_cast<int>(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 c55f7634f..3faf9ae00 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)
diff --git a/scribus/styles/paragraphstyle.attrdefs.cxx b/scribus/styles/paragraphstyle.attrdefs.cxx
index 238e71a5c..bbd0c0525 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 f182104f3..9384ef24e 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<int>(val));
 }
 
+static QString toXMLString(ParagraphStyle::SuffixAlignment val)
+{
+	return QString::number(static_cast<int>(val));
+}
+
 static QString toXMLString(ParagraphStyle::DirectionType val)
 {
 	return QString::number(static_cast<int>(val));
@@ -344,6 +357,12 @@ ParagraphStyle::AlignmentType parse<ParagraphStyle::AlignmentType>(const Xml_str
 	return parseEnum<ParagraphStyle::AlignmentType>(str);
 }
 
+template<>
+ParagraphStyle::SuffixAlignment parse<ParagraphStyle::SuffixAlignment>(const Xml_string& str)
+{
+	return parseEnum<ParagraphStyle::SuffixAlignment>(str);
+}
+
 template<>
 ParagraphStyle::DirectionType parse<ParagraphStyle::DirectionType>(const Xml_string& str)
 {
diff --git a/scribus/styles/paragraphstyle.h b/scribus/styles/paragraphstyle.h
index 4e5bac2a1..2f8303791 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 d984c7901..d7d7a882f 100644
--- a/scribus/text/sctext_shared.cpp
+++ b/scribus/text/sctext_shared.cpp
@@ -68,6 +68,7 @@ void ScText_Shared::clear()
 	if (marksCount > 0)
 		marksCountChanged = true;
 	marksCount = 0;
+	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 d16bd8267..2de71bbbb 100644
--- a/scribus/text/sctext_shared.h
+++ b/scribus/text/sctext_shared.h
@@ -2,6 +2,7 @@
 #define SCTEXT_SHARED_H
 
 #include <QList>
+#include <QHash>
 #include <QObject>
 #include <QString>
 #include <cassert>
@@ -35,6 +36,10 @@ 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<QString, double> maxParEffectWidthCache;
+
 	void clear();
 	
 	/**
diff --git a/scribus/text/storytext.cpp b/scribus/text/storytext.cpp
index 4214bb583..5c9f2b468 100644
--- a/scribus/text/storytext.cpp
+++ b/scribus/text/storytext.cpp
@@ -1391,6 +1391,11 @@ void StoryText::clearFlag(int pos, LayoutFlags flags)
 	d->at(pos)->setEffects(~(flags & ScStyle_NonUserStyles) & d->at(pos)->effects().value);
 }
 
+QHash<QString, double> &StoryText::maxParEffectWidthCache()
+{
+	return d->maxParEffectWidthCache;
+}
+
 
 const CharStyle & StoryText::charStyle() const
 {
@@ -2261,6 +2266,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 7920d56ab..9aaf6effe 100644
--- a/scribus/text/storytext.h
+++ b/scribus/text/storytext.h
@@ -29,6 +29,7 @@ pageitem.cpp  -  description
 #include <QObject>
 #include <QString>
 #include <QList>
+#include <QHash>
 #include <unicode/uversion.h>
 
 #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<QString, double>& 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 0e6ef1e52..1a3701ea5 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<int>(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<ParagraphStyle::SuffixAlignment>(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 62729f7c2..54d2aeab4 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 1a2670a01..fa21acf2e 100644
--- a/scribus/ui/propertywidget_pareffectbase.ui
+++ b/scribus/ui/propertywidget_pareffectbase.ui
@@ -438,10 +438,17 @@
           </layout>
          </widget>
         </item>
-        <item>
-         <widget class="QCheckBox" name="peIndent">
+<item>
+         <widget class="QLabel" name="suffixAlignmentLabel">
           <property name="text">
-           <string>Auto-Indent</string>
+           <string>Suffix Align:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="suffixAlignmentCombo">
+          <property name="toolTip">
+           <string>Alignment of suffix characters in numbered lists</string>
           </property>
          </widget>
         </item>
@@ -556,8 +563,8 @@
   <tabstop>numStart</tabstop>
   <tabstop>numPrefix</tabstop>
   <tabstop>numSuffix</tabstop>
-  <tabstop>peOffset</tabstop>
-  <tabstop>peIndent</tabstop>
+<tabstop>peOffset</tabstop>
+  <tabstop>suffixAlignmentCombo</tabstop>
   <tabstop>peCharStyleCombo</tabstop>
   <tabstop>dropCapLines</tabstop>
   <tabstop>bulletStrEdit</tabstop>
diff --git a/scribus/ui/smpstylewidget.cpp b/scribus/ui/smpstylewidget.cpp
index 12fde4428..d5e0fc626 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<CharStyle> *cstyles) :
 	m_Doc(doc),
 	m_cstyles(cstyles)
@@ -74,6 +73,7 @@ SMPStyleWidget::SMPStyleWidget(ScribusDoc* doc, StyleSet<CharStyle> *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<ParagraphStyle> &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<int>(displayAlign));
+		suffixAlignmentCombo->setCurrentItem(suffixAlignIndex, pstyle->isInhSuffixAlignment());
+		suffixAlignmentCombo->setParentItem(suffixAlignmentCombo->findData(static_cast<int>(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<ParagraphStyle> &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<int>(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<ParagraphStyle*> &pstyles, const QList<CharStyle> &cstyles, int unitIndex)
diff --git a/scribus/ui/smpstylewidget.h b/scribus/ui/smpstylewidget.h
index c985d7033..4cb5c88bd 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<ParagraphStyle*> &cstyles);
 	void showLineSpacing(const QList<ParagraphStyle*> &pstyles);
diff --git a/scribus/ui/smpstylewidget.ui b/scribus/ui/smpstylewidget.ui
index 8a6d90e31..f62551956 100644
--- a/scribus/ui/smpstylewidget.ui
+++ b/scribus/ui/smpstylewidget.ui
@@ -29,7 +29,7 @@
    <item>
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>0</number>
+      <number>1</number>
      </property>
      <widget class="QWidget" name="tab">
       <attribute name="title">
@@ -181,7 +181,7 @@
             <item>
              <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1">
               <item>
-               <widget class="FormWidget" name="consecutiveHyphenLabel">
+               <widget class="FormWidget" name="consecutiveHyphenLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -280,7 +280,7 @@ A value of 0 means unlimited hyphenations.</string>
              <number>4</number>
             </property>
             <item row="0" column="1">
-             <widget class="FormWidget" name="minSpaceLabel">
+             <widget class="FormWidget" name="minSpaceLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -326,7 +326,7 @@ A value of 0 means unlimited hyphenations.</string>
              </widget>
             </item>
             <item row="1" column="2">
-             <widget class="FormWidget" name="maxGlyphExtLabel">
+             <widget class="FormWidget" name="maxGlyphExtLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -379,7 +379,7 @@ A value of 0 means unlimited hyphenations.</string>
              </spacer>
             </item>
             <item row="0" column="0">
-             <widget class="FormWidget" name="formWidget_3">
+             <widget class="FormWidget" name="formWidget_3" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -389,7 +389,7 @@ A value of 0 means unlimited hyphenations.</string>
               <property name="label" stdset="0">
                <string/>
               </property>
-              <property name="preserveLabelSpace">
+              <property name="preserveLabelSpace" stdset="0">
                <bool>true</bool>
               </property>
               <layout class="QHBoxLayout" name="horizontalLayout">
@@ -419,7 +419,7 @@ A value of 0 means unlimited hyphenations.</string>
              </widget>
             </item>
             <item row="1" column="1">
-             <widget class="FormWidget" name="minGlyphExtLabel">
+             <widget class="FormWidget" name="minGlyphExtLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -459,7 +459,7 @@ A value of 0 means unlimited hyphenations.</string>
              </widget>
             </item>
             <item row="1" column="0">
-             <widget class="FormWidget" name="formWidget_4">
+             <widget class="FormWidget" name="formWidget_4" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -469,7 +469,7 @@ A value of 0 means unlimited hyphenations.</string>
               <property name="label" stdset="0">
                <string/>
               </property>
-              <property name="preserveLabelSpace">
+              <property name="preserveLabelSpace" stdset="0">
                <bool>true</bool>
               </property>
               <layout class="QHBoxLayout" name="horizontalLayout_2">
@@ -597,7 +597,7 @@ A value of 0 means unlimited hyphenations.</string>
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="lineSpacingLabel">
+               <widget class="FormWidget" name="lineSpacingLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -673,7 +673,7 @@ A value of 0 means unlimited hyphenations.</string>
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="spaceAboveLabel">
+               <widget class="FormWidget" name="spaceAboveLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -710,7 +710,7 @@ A value of 0 means unlimited hyphenations.</string>
                </widget>
               </item>
               <item>
-               <widget class="FormWidget" name="spaceBelowLabel">
+               <widget class="FormWidget" name="spaceBelowLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -804,7 +804,7 @@ A value of 0 means unlimited hyphenations.</string>
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="keepLabelStart">
+               <widget class="FormWidget" name="keepLabelStart" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -844,7 +844,7 @@ A value of 0 means unlimited hyphenations.</string>
                </widget>
               </item>
               <item>
-               <widget class="FormWidget" name="keepLabelEnd">
+               <widget class="FormWidget" name="keepLabelEnd" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -1021,7 +1021,7 @@ A value of 0 means unlimited hyphenations.</string>
        <item>
         <layout class="QHBoxLayout" name="horizontalLayout_20">
          <item>
-          <widget class="FormWidget" name="peLabel">
+          <widget class="FormWidget" name="peLabel" native="true">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
              <horstretch>0</horstretch>
@@ -1441,7 +1441,7 @@ A value of 0 means unlimited hyphenations.</string>
               </widget>
              </item>
              <item row="0" column="6">
-              <widget class="FormWidget" name="formWidget_2">
+              <widget class="FormWidget" name="formWidget_2" native="true">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                  <horstretch>0</horstretch>
@@ -1451,10 +1451,7 @@ A value of 0 means unlimited hyphenations.</string>
                <property name="label" stdset="0">
                 <string>New Set:</string>
                </property>
-               <property name="direction">
-                <enum>FormWidget::LabelPosition::Left</enum>
-               </property>
-               <property name="useSmallFont">
+               <property name="useSmallFont" stdset="0">
                 <bool>false</bool>
                </property>
                <layout class="QHBoxLayout" name="horizontalLayout_25">
@@ -1476,6 +1473,20 @@ A value of 0 means unlimited hyphenations.</string>
                </layout>
               </widget>
              </item>
+             <item row="3" column="6">
+              <widget class="SMScComboBox" name="suffixAlignmentCombo">
+               <property name="toolTip">
+                <string>Alignment of suffix characters in numbered lists</string>
+               </property>
+              </widget>
+             </item>
+             <item row="3" column="5">
+              <widget class="QLabel" name="suffixAlignmentLabel">
+               <property name="text">
+                <string>Suffix Align:</string>
+               </property>
+              </widget>
+             </item>
             </layout>
            </item>
           </layout>
@@ -1506,7 +1517,7 @@ A value of 0 means unlimited hyphenations.</string>
              <number>16</number>
             </property>
             <item>
-             <widget class="FormWidget" name="distFromTextLabel">
+             <widget class="FormWidget" name="distFromTextLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -1545,46 +1556,6 @@ A value of 0 means unlimited hyphenations.</string>
               </layout>
              </widget>
             </item>
-            <item>
-             <widget class="FormWidget" name="formWidget">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="label" stdset="0">
-               <string/>
-              </property>
-              <property name="preserveLabelSpace">
-               <bool>true</bool>
-              </property>
-              <layout class="QHBoxLayout" name="horizontalLayout_24">
-               <property name="leftMargin">
-                <number>0</number>
-               </property>
-               <property name="topMargin">
-                <number>0</number>
-               </property>
-               <property name="rightMargin">
-                <number>0</number>
-               </property>
-               <property name="bottomMargin">
-                <number>0</number>
-               </property>
-               <item>
-                <widget class="SMCheckBox" name="parEffectIndentBox">
-                 <property name="toolTip">
-                  <string>Hang Paragraph Effect before paragraph indent</string>
-                 </property>
-                 <property name="text">
-                  <string>Auto-Indent</string>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </widget>
-            </item>
             <item>
              <spacer name="horizontalSpacer_14">
               <property name="orientation">
@@ -1606,7 +1577,7 @@ A value of 0 means unlimited hyphenations.</string>
              <number>16</number>
             </property>
             <item>
-             <widget class="FormWidget" name="parEffectCharStyleComboLabel">
+             <widget class="FormWidget" name="parEffectCharStyleComboLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -1792,7 +1763,6 @@ A value of 0 means unlimited hyphenations.</string>
   <tabstop>parentParEffectsButton</tabstop>
   <tabstop>dropCapLines</tabstop>
   <tabstop>parEffectOffset</tabstop>
-  <tabstop>parEffectIndentBox</tabstop>
   <tabstop>parEffectCharStyleCombo</tabstop>
   <tabstop>numPrefix</tabstop>
   <tabstop>numSuffix</tabstop>
diff --git a/scribus/ui/smtextstyles.cpp b/scribus/ui/smtextstyles.cpp
index b021322dd..390365f53 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<ParagraphStyle::SuffixAlignment>(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 3dd02356a..087870f22 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);
suffixalignment v2.patch (51,056 bytes)   

qirat

2026-07-14 03:29

reporter   ~0054030

Thank yo very much @Fahad. This time, I tested the patch on a clean r27709. I use 3-directory structure src, build and install, keeping things separate. I deleted all of them, fetched the source, built and compiled. Here is what I observed and more:

1. I think it is the fonts. Different fonts behave differently with dot as a suffix.
2. When I use other suffixes like ) or even ! (just as a test), they all seem to align fine. Only dot gives a problem.
3. Try Adwaita Sans. Dots do not align perfectly but ) does.
4. No issue of any kind with monospace fonts (dots and ) align fine).

The UI with your patch needs tweaking I think. The "Restart after..." options belong below the "Restart:[dropdown]" property, at the very least for now.

Also, the "Auto-Indent" UI you removed. I find it very useful when I tested it earlier. It is amazing what one can achieve with just one tick in the checkbox. It only just needs to be renamed to "Auto Hanging Indent" imho.

Fahad

2026-07-14 04:04

developer   ~0054031

I couldn't reproduce it. I am using Fedora 44.
 Auto-Indent feature is confusing a little bit, to work you have to set left margin first which is not obvious in the first place, the new feature is more simple and easy. GUI staff I don't know . I think the whole page needs to redesign IMO.
1.png (53,167 bytes)   
1.png (53,167 bytes)   
2.png (67,323 bytes)   
2.png (67,323 bytes)   

qirat

2026-07-14 05:17

reporter   ~0054032

That is weird. I think I will test on other system and OS, and report back.

I might also try the UI stuff but guide me a little here how should the UI patch go?
- I post it here and one is supposed to apply it after your patch? (Bcs it will have components you added that did not exist earlier.)
- or, I post it as a new bug report (which I think will confuse things more, as one does not know when to apply that)

Fahad

2026-07-14 06:11

developer   ~0054033

try to export to pdf and check if the problem still there.
for UI, I think it is better to open a new bug report because it is not related to this feature.

Fahad

2026-07-14 11:31

developer   ~0054034

To stress-test my patch against large documents, I created a 200-page document and filled it with 11,250 single-line paragraphs. I then changed the paragraph effect to apply a Numbered List.

I noticed a very slow performance during this test. Since the default alignment suffix is left—which matches what the current trunk has—I confirmed that my new approach did not cause this lag. The bottleneck already existed in the trunk.

I managed to fix the slowness in the layout engine. Now, I have made Scribus acceptably fast when applying paragraph effects, even across massive, document-wide style changes.

finally please test
suffixalignmentv3.patch (54,288 bytes)   
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<Numeration> m_nums;
 	QList<int> m_counters;
+	QList<int> 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<NumFormat>(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<GlyphCluster> 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<GlyphCluster> 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<QString, double>& 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<NumFormat>(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<QString, double> 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<bool>(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<bool>(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<int>(style.parEffectIndent()));
 	if ( ! style.isInhHasDropCap())
 		docu.writeAttribute("DROP", static_cast<int>(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<bool>(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<bool>(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<int>(style.parEffectIndent()));
 	if (!style.isInhHasDropCap())
 		docu.writeAttribute("DROP", static_cast<int>(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<bool>(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<ParagraphStyle::SuffixAlignment>(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<bool>(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<ParagraphStyle::SuffixAlignment>(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<int>(style.parEffectIndent()));
 	if (!style.isInhHasDropCap())
 		docu.writeAttribute("HasDropCap", static_cast<int>(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<Numeration> nums;
 	QList<int> 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<int>(val));
 }
 
+static QString toXMLString(ParagraphStyle::SuffixAlignment val)
+{
+	return QString::number(static_cast<int>(val));
+}
+
 static QString toXMLString(ParagraphStyle::DirectionType val)
 {
 	return QString::number(static_cast<int>(val));
@@ -344,6 +357,12 @@ ParagraphStyle::AlignmentType parse<ParagraphStyle::AlignmentType>(const Xml_str
 	return parseEnum<ParagraphStyle::AlignmentType>(str);
 }
 
+template<>
+ParagraphStyle::SuffixAlignment parse<ParagraphStyle::SuffixAlignment>(const Xml_string& str)
+{
+	return parseEnum<ParagraphStyle::SuffixAlignment>(str);
+}
+
 template<>
 ParagraphStyle::DirectionType parse<ParagraphStyle::DirectionType>(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 <QList>
+#include <QHash>
 #include <QObject>
 #include <QString>
 #include <cassert>
@@ -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<QString, double> 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 <QList>
 #include <cassert>  //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<QString, double> &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 <QObject>
 #include <QString>
 #include <QList>
+#include <QHash>
 #include <unicode/uversion.h>
 
 #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<QString, double>& 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<int>(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<ParagraphStyle::SuffixAlignment>(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 @@
           </layout>
          </widget>
         </item>
-        <item>
-         <widget class="QCheckBox" name="peIndent">
+<item>
+         <widget class="QLabel" name="suffixAlignmentLabel">
           <property name="text">
-           <string>Auto-Indent</string>
+           <string>Suffix Align:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="suffixAlignmentCombo">
+          <property name="toolTip">
+           <string>Alignment of suffix characters in numbered lists</string>
           </property>
          </widget>
         </item>
@@ -556,8 +563,8 @@
   <tabstop>numStart</tabstop>
   <tabstop>numPrefix</tabstop>
   <tabstop>numSuffix</tabstop>
-  <tabstop>peOffset</tabstop>
-  <tabstop>peIndent</tabstop>
+<tabstop>peOffset</tabstop>
+  <tabstop>suffixAlignmentCombo</tabstop>
   <tabstop>peCharStyleCombo</tabstop>
   <tabstop>dropCapLines</tabstop>
   <tabstop>bulletStrEdit</tabstop>
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<CharStyle> *cstyles) :
 	m_Doc(doc),
 	m_cstyles(cstyles)
@@ -74,6 +73,7 @@ SMPStyleWidget::SMPStyleWidget(ScribusDoc* doc, StyleSet<CharStyle> *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<ParagraphStyle> &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<int>(displayAlign));
+		suffixAlignmentCombo->setCurrentItem(suffixAlignIndex, pstyle->isInhSuffixAlignment());
+		suffixAlignmentCombo->setParentItem(suffixAlignmentCombo->findData(static_cast<int>(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<ParagraphStyle> &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<int>(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<ParagraphStyle*> &pstyles, const QList<CharStyle> &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<ParagraphStyle*> &cstyles);
 	void showLineSpacing(const QList<ParagraphStyle*> &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 @@
    <item>
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>0</number>
+      <number>1</number>
      </property>
      <widget class="QWidget" name="tab">
       <attribute name="title">
@@ -181,7 +181,7 @@
             <item>
              <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1">
               <item>
-               <widget class="FormWidget" name="consecutiveHyphenLabel">
+               <widget class="FormWidget" name="consecutiveHyphenLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -280,7 +280,7 @@ A value of 0 means unlimited hyphenations.</string>
              <number>4</number>
             </property>
             <item row="0" column="1">
-             <widget class="FormWidget" name="minSpaceLabel">
+             <widget class="FormWidget" name="minSpaceLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -326,7 +326,7 @@ A value of 0 means unlimited hyphenations.</string>
              </widget>
             </item>
             <item row="1" column="2">
-             <widget class="FormWidget" name="maxGlyphExtLabel">
+             <widget class="FormWidget" name="maxGlyphExtLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -379,7 +379,7 @@ A value of 0 means unlimited hyphenations.</string>
              </spacer>
             </item>
             <item row="0" column="0">
-             <widget class="FormWidget" name="formWidget_3">
+             <widget class="FormWidget" name="formWidget_3" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -389,7 +389,7 @@ A value of 0 means unlimited hyphenations.</string>
               <property name="label" stdset="0">
                <string/>
               </property>
-              <property name="preserveLabelSpace">
+              <property name="preserveLabelSpace" stdset="0">
                <bool>true</bool>
               </property>
               <layout class="QHBoxLayout" name="horizontalLayout">
@@ -419,7 +419,7 @@ A value of 0 means unlimited hyphenations.</string>
              </widget>
             </item>
             <item row="1" column="1">
-             <widget class="FormWidget" name="minGlyphExtLabel">
+             <widget class="FormWidget" name="minGlyphExtLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -459,7 +459,7 @@ A value of 0 means unlimited hyphenations.</string>
              </widget>
             </item>
             <item row="1" column="0">
-             <widget class="FormWidget" name="formWidget_4">
+             <widget class="FormWidget" name="formWidget_4" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -469,7 +469,7 @@ A value of 0 means unlimited hyphenations.</string>
               <property name="label" stdset="0">
                <string/>
               </property>
-              <property name="preserveLabelSpace">
+              <property name="preserveLabelSpace" stdset="0">
                <bool>true</bool>
               </property>
               <layout class="QHBoxLayout" name="horizontalLayout_2">
@@ -597,7 +597,7 @@ A value of 0 means unlimited hyphenations.</string>
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="lineSpacingLabel">
+               <widget class="FormWidget" name="lineSpacingLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -673,7 +673,7 @@ A value of 0 means unlimited hyphenations.</string>
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="spaceAboveLabel">
+               <widget class="FormWidget" name="spaceAboveLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -710,7 +710,7 @@ A value of 0 means unlimited hyphenations.</string>
                </widget>
               </item>
               <item>
-               <widget class="FormWidget" name="spaceBelowLabel">
+               <widget class="FormWidget" name="spaceBelowLabel" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -804,7 +804,7 @@ A value of 0 means unlimited hyphenations.</string>
                <number>16</number>
               </property>
               <item>
-               <widget class="FormWidget" name="keepLabelStart">
+               <widget class="FormWidget" name="keepLabelStart" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -844,7 +844,7 @@ A value of 0 means unlimited hyphenations.</string>
                </widget>
               </item>
               <item>
-               <widget class="FormWidget" name="keepLabelEnd">
+               <widget class="FormWidget" name="keepLabelEnd" native="true">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                   <horstretch>0</horstretch>
@@ -1021,7 +1021,7 @@ A value of 0 means unlimited hyphenations.</string>
        <item>
         <layout class="QHBoxLayout" name="horizontalLayout_20">
          <item>
-          <widget class="FormWidget" name="peLabel">
+          <widget class="FormWidget" name="peLabel" native="true">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
              <horstretch>0</horstretch>
@@ -1441,7 +1441,7 @@ A value of 0 means unlimited hyphenations.</string>
               </widget>
              </item>
              <item row="0" column="6">
-              <widget class="FormWidget" name="formWidget_2">
+              <widget class="FormWidget" name="formWidget_2" native="true">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                  <horstretch>0</horstretch>
@@ -1451,10 +1451,7 @@ A value of 0 means unlimited hyphenations.</string>
                <property name="label" stdset="0">
                 <string>New Set:</string>
                </property>
-               <property name="direction">
-                <enum>FormWidget::LabelPosition::Left</enum>
-               </property>
-               <property name="useSmallFont">
+               <property name="useSmallFont" stdset="0">
                 <bool>false</bool>
                </property>
                <layout class="QHBoxLayout" name="horizontalLayout_25">
@@ -1476,6 +1473,20 @@ A value of 0 means unlimited hyphenations.</string>
                </layout>
               </widget>
              </item>
+             <item row="3" column="6">
+              <widget class="SMScComboBox" name="suffixAlignmentCombo">
+               <property name="toolTip">
+                <string>Alignment of suffix characters in numbered lists</string>
+               </property>
+              </widget>
+             </item>
+             <item row="3" column="5">
+              <widget class="QLabel" name="suffixAlignmentLabel">
+               <property name="text">
+                <string>Suffix Align:</string>
+               </property>
+              </widget>
+             </item>
             </layout>
            </item>
           </layout>
@@ -1506,7 +1517,7 @@ A value of 0 means unlimited hyphenations.</string>
              <number>16</number>
             </property>
             <item>
-             <widget class="FormWidget" name="distFromTextLabel">
+             <widget class="FormWidget" name="distFromTextLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -1545,46 +1556,6 @@ A value of 0 means unlimited hyphenations.</string>
               </layout>
              </widget>
             </item>
-            <item>
-             <widget class="FormWidget" name="formWidget">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="label" stdset="0">
-               <string/>
-              </property>
-              <property name="preserveLabelSpace">
-               <bool>true</bool>
-              </property>
-              <layout class="QHBoxLayout" name="horizontalLayout_24">
-               <property name="leftMargin">
-                <number>0</number>
-               </property>
-               <property name="topMargin">
-                <number>0</number>
-               </property>
-               <property name="rightMargin">
-                <number>0</number>
-               </property>
-               <property name="bottomMargin">
-                <number>0</number>
-               </property>
-               <item>
-                <widget class="SMCheckBox" name="parEffectIndentBox">
-                 <property name="toolTip">
-                  <string>Hang Paragraph Effect before paragraph indent</string>
-                 </property>
-                 <property name="text">
-                  <string>Auto-Indent</string>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </widget>
-            </item>
             <item>
              <spacer name="horizontalSpacer_14">
               <property name="orientation">
@@ -1606,7 +1577,7 @@ A value of 0 means unlimited hyphenations.</string>
              <number>16</number>
             </property>
             <item>
-             <widget class="FormWidget" name="parEffectCharStyleComboLabel">
+             <widget class="FormWidget" name="parEffectCharStyleComboLabel" native="true">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                 <horstretch>0</horstretch>
@@ -1792,7 +1763,6 @@ A value of 0 means unlimited hyphenations.</string>
   <tabstop>parentParEffectsButton</tabstop>
   <tabstop>dropCapLines</tabstop>
   <tabstop>parEffectOffset</tabstop>
-  <tabstop>parEffectIndentBox</tabstop>
   <tabstop>parEffectCharStyleCombo</tabstop>
   <tabstop>numPrefix</tabstop>
   <tabstop>numSuffix</tabstop>
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<ParagraphStyle::SuffixAlignment>(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);
suffixalignmentv3.patch (54,288 bytes)   

qirat

2026-07-15 08:00

reporter   ~0054038

Perfect. Works across linked frames (tested with 100 items). Thanks a lot, @Fahad.

Issue History

Date Modified Username Field Change
2024-07-01 13:00 ale New Issue
2024-07-01 13:02 ale Relationship added related to 0016985
2024-07-01 13:02 ale Relationship added related to 0016963
2025-02-20 09:15 ale Note Added: 0052074
2025-02-20 09:15 ale File Added: autoindent.png
2025-02-20 09:15 ale File Added: autoindent-correct.png
2025-02-20 14:10 ale Note Added: 0052075
2025-02-20 14:10 ale File Added: numbering-nitramr.png
2025-02-20 15:31 ale Note Added: 0052076
2025-02-20 15:32 ale Note Edited: 0052076
2025-02-20 20:47 ale Note Added: 0052079
2025-02-20 20:47 ale File Added: enumarte-left-aligned.png
2025-02-20 22:03 nitramr Note Added: 0052080
2025-02-20 22:03 nitramr File Added: Document-1.sla
2025-02-20 22:04 nitramr Note Edited: 0052080
2025-02-21 17:36 ale Note Added: 0052083
2025-02-21 18:59 nitramr Note Added: 0052086
2025-02-22 08:23 ale Relationship added related to 0013488
2025-02-22 09:26 ale Note Added: 0052093
2025-04-27 19:16 cbradney Category Story Editor / Text Frames => Text Frames / Story Editor
2026-02-26 15:50 qirat Note Added: 0053542
2026-02-26 15:50 qirat Note Added: 0053543
2026-07-06 03:59 Fahad Note Added: 0053980
2026-07-06 04:55 qirat Note Added: 0053985
2026-07-09 08:14 Fahad Note Added: 0054001
2026-07-09 08:14 Fahad File Added: suffixalignment v1.patch
2026-07-09 08:14 Fahad File Added: suffix-align.png
2026-07-09 12:19 qirat Note Added: 0054002
2026-07-09 12:19 qirat File Added: align_suffix_test.png
2026-07-09 13:10 qirat Note Added: 0054003
2026-07-09 13:10 qirat File Added: list-marker-alignment-v1.2-r27703-remove-autoindent-ui.patch
2026-07-10 01:02 qirat Note Added: 0054006
2026-07-13 15:01 Fahad Note Added: 0054029
2026-07-13 15:01 Fahad File Added: suffixalignment v2.patch
2026-07-14 03:29 qirat Note Added: 0054030
2026-07-14 03:29 qirat File Added: Screenshot From 2026-07-14 08-42-43.png
2026-07-14 03:29 qirat File Added: Screenshot From 2026-07-14 08-28-30.png
2026-07-14 04:04 Fahad Note Added: 0054031
2026-07-14 04:04 Fahad File Added: 1.png
2026-07-14 04:04 Fahad File Added: 2.png
2026-07-14 05:17 qirat Note Added: 0054032
2026-07-14 06:11 Fahad Note Added: 0054033
2026-07-14 11:31 Fahad Note Added: 0054034
2026-07-14 11:31 Fahad File Added: suffixalignmentv3.patch
2026-07-15 08:00 qirat Note Added: 0054038
2026-07-15 08:00 qirat File Added: Screenshot From 2026-07-15 09-43-16.png