FLOSS Manuals

 English |  Español |  Français |  Italiano |  Português |  Русский |  Shqip

Python Scripting with Scribus

centervert.py

Here is a script that seemed like a good idea at the time. The problem it solved in its own way was to figure out how to center text vertically in a frame. Scribus has always had center justification to place the text horizontally in the middle, but there wasn't any way other than manually entering enough lines or space somehow before your text for vertical centering.

What this script does is to get the linespacing, multiply that by the number of lines of text, and then adjust the top distance (the space between the top edge of the frame and the first line of text) so that the space above and below the text is even. I don't know if anyone other than me ever used this script, but subsequently a new setting was added for text in the Columns and Text Distances subtab of Text Properties, Vertical Alignment, with choices of Top, Middle, and Bottom. At any rate, it is useful for showing how Scripter handles text distances.

#!/usr/bin/env python
# -*- coding: utf-8  -*-

"""

centervert.py

Centers text vertically in a text frame. Works with fixed linespacing.

USAGE

Select a text frame, run script.

"""

try:
    import scribus
except ImportError:
    print "Unable to import the 'scribus' module. This script will only run within"
    print "the Python interpreter embedded in Scribus. Try Script->Execute Script."
    sys.exit(1)

if not scribus.haveDoc():
    scribus.messageBox('Scribus - Script Error', "No document open", scribus.ICON_WARNING, scribus.BUTTON_OK)
    sys.exit(1)

if scribus.selectionCount() == 0:
    scribus.messageBox('Scribus - Script Error',
            "There is no object selected.\nPlease select a text frame and try again.",
            scribus.ICON_WARNING, scribus.BUTTON_OK)
    sys.exit(2)
if scribus.selectionCount() > 1:
    scribus.messageBox('Scribus - Script Error',
            "You have more than one object selected.\nPlease select one text frame and try again.",
            scribus.ICON_WARNING, scribus.BUTTON_OK)
    sys.exit(2)
textbox = scribus.getSelectedObject()
pageitems = scribus.getPageItems()
scribus.setRedraw(False)
for item in pageitems:
    if (item[0] == textbox):
        if (item[1] != 4):
            scribus.messageBox('Scribus - Script Error',
                          "This is not a textframe. Try again.", scribus.ICON_WARNING, scribus.BUTTON_OK)
            scribus.setRedraw(True)
            sys.exit(2)

            
        lines = scribus.getTextLines(textbox)
        distances = scribus.getTextDistances(textbox)
        linespace = scribus.getLineSpacing(textbox)
        dimensions = scribus.getSize(textbox) # (width, height)
        if (scribus.textOverflows(textbox, 1) > 0):
            scribus.messageBox('User Error', "This frame is already overflowing", scribus.ICON_WARNING, scribus.BUTTON_OK)
            scribus.setRedraw(True)
            sys.exit(2)
        newtopdist = (dimensions[1] - linespace * lines)/2
        scribus.setTextDistances(distances[0],distances[1],newtopdist,distances[3],textbox)
        scribus.moveObject(-4,0,textbox)
        scribus.moveObject(4,0,textbox)
scribus.setRedraw(True)

Something you might notice right away, once you get past the comments, is that about half of the actual commands are for error-handling. First we check to see the script is being used with Scribus, next we check if a document is open, next we check to make sure an object is selected, and then we check to make sure only one is selected, and we're not even done with error-checking!

We've assigned our object to this variable textbox, but actually we don't know if this is a text frame or not. This is important, since we have operations ahead that will only work for text frames. We sort this out by making a Python list of all the objects on the page, then going through the list until one matches our textbox. It turns out that these individual pageitems are themselves lists. The first element, pageitem[0], is its name. The second, pageitem[1] is its type (aha!), and the value of pageitem[1] should be 4 if it is a text frame. So now you can see the reason for collecting, then cycling through the pageitems. In the end, if this is not a text frame, we generate another error message and quit.

We begin the actual work of centering the text by getting the number of lines of text, the text distances settings, the line spacing, and then the width and height of the frame. I should mention here that if I were making this script for general consumption I should have done the getUnit(), setUnit(), setUnit() process that I showed in bcaption.py.

There is one last error check - making sure that text is not overflowing in this frame. If that's the case, there is no solution. The entries between the parentheses in textOverflows() are first the frame name, and secondly the 1 indicates we only want to know about this frame, not those it links to. If text is overflowing, this command returns 1. It would probably be better to have written this as

 if (scribus.textOverflows(textbox, 1) == 1):

but either works. A little math follows, where we take the height of the frame, subtract the quotient of linespacing times the number of lines divided by 2. The result is then plugged into setting a new top distance with setTextDistances().

But then look at the next two lines. I'm moving the frame 4 points to the left, then moving 4 points to the right. This shows the source of one of the uncertainties I have about setRedraw(True). Notice that in this script I have already used setRedraw(False). It turns out that if I don't do this little moving wiggle, when the script is done, you don't see the text brought down in the frame. You can see that the vertical distance is set as it should, but the text stay at the top of the frame. One work around is to save the file, then open it again. I also found that if I moved the frame a little, then the text moved to where it was supposed to be, so it's some kind of display issue. Later, I found out that if I did this little movement in the script, it worked the same way.

settopdistance.py

One of the reasons I keep old scripts even when the original reason for their existence disappears is that you never know when you might recycle them in some form. Here is a mini version of this script that simply sets a top distance.

#!/usr/bin/env python
# -*- coding: utf-8  -*-

"""

settopdistance.py

USAGE

Select a text frame, run script.

"""

import scribus

textbox = scribus.getSelectedObject()
units = scribus.getUnit()
scribus.setUnit(scribus.UNIT_POINTS)
scribus.setRedraw(False)

distances = scribus.getTextDistances(textbox)
linespace = scribus.getLineSpacing(textbox)
scribus.setTextDistances(distances[0],distances[1],5.00,distances[3],textbox)
scribus.moveObject(-4,0,textbox)
scribus.moveObject(4,0,textbox)
scribus.setUnit(units)
scribus.setRedraw(True)

This is a script I shared on the mail list as a work around for the situation where someone wanted to automatically set the Line Offset in text frames to Linespacing mode. It turns out that there is no setting in Preferences for this, and no Scripter command for it either. What this script does is use the top distance as a proxy. I found that a 5 points top distance was indistinguishable from the spacing you see with Line Offset set to Linespacing, at least for a 12-point font.

This is a very basic script, and as you can see contains no error-checking. I mainly was presenting it so that whoever might use it could modify as desired. Sometimes with very simple scripts you can get by without the added lines.


There has been error in communication with Booktype server. Not sure right now where is the problem.

You should refresh this page.