Subversion Repositories Scribus

Rev

Rev 3002 | Rev 3448 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1048 cbradney 1
#!/usr/bin/env python2.3
2
# -*- coding: utf-8 -*-
3
 
4
# ****************************************************************************
5
#  This program is free software; you can redistribute it and/or modify 
6
#  it under the terms of the GNU General Public License as published by
7
#  the Free Software Foundation; either version 2 of the License, or
8
#  (at your option) any later version.
9
#
10
#  This program is distributed in the hope that it will be useful,
11
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
#  GNU General Public License for more details.
14
#
15
#  You should have received a copy of the GNU General Public License
16
#  along with this program; if not, write to the Free Software
17
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
# 
19
# ****************************************************************************
20
 
21
"""
22
******************************************************************************
23
 
24
DESCRIPTION & USAGE:
540 subik 25
This script needs Tkinter. It will create a GUI with an alphabetical list
26
of fonts using the names as they will be shown in Scribus. User can select
27
one or more fonts and create an example sheet(s) to print or create a PDF
28
from. It is heavily commented to make it easier for the user to adjust it
29
for his / her own needs.
222 Franz 30
 
1048 cbradney 31
Note: this version needs read/write access to .scribus directory in users
32
home. You will also need Python Imaging Library (PIL) installed.
33
If your system does not meet these requirements then change showPreviewPanel
34
to a value of 0. This will disable the new preview features.
540 subik 35
 
1048 cbradney 36
******************************************************************************
540 subik 37
 
1048 cbradney 38
First release    : 30/12/2003
3012 mrdocs 39
This release     : v0.7.4tk (released 14th Aug 2005)
1066 cbradney 40
Copyright        : (C) 2003 - 2005 Steve Callcott
41
Latest releases
42
and support      : www.firstwish.co.uk/sjc/scribus/index.php
43
Maintainer       : Steve Callcott 2003 - 2005
3002 mrdocs 44
Email            : stotte@firstwish.co.uk
540 subik 45
 
46
For revision history see the ChangeLog file.
47
Bugs and future plans are listed in the TODO file.
48
See NEWS for new features since last version.
49
 
3012 mrdocs 50
WHATS NEW v0.7.4tk
51
Now updates the Scribus Progress Bar (one increment for each font drawn).
52
 
3002 mrdocs 53
WHATS NEW v0.7.3tk
54
Fix typo in exception code.
55
Modified case of some script variables to make compatible with changes
56
in Scribus 1.3 scriptor.
57
Removed the reduntant "self.master.maxsize(1, 1)" from the application class.
58
 
1072 cbradney 59
WHATS NEW v0.7.2tk
60
More cleanups in font preview code. If a font cannot be displayed
61
then the preview panel is cleared. Removed many error messages returned
62
to the console.
63
 
1066 cbradney 64
WHATS NEW v0.7.1tk
65
Removed discontinued email address.
66
 
1048 cbradney 67
WHATS NEW v0.7tk
68
Added a preview panel so user can see a sample of what a font may look like
69
before selecting it to use.
70
Detects failure of Python Imaging Library module to load and tests for the
71
ability to write to .scribus folder then disables preview if necessary.
72
Incorporated Craig Ringers boilerplate and Scribus function case changes.
73
Put labels on the left and right listboxes describing what they do.
74
Listboxes now get focus when selected with the mouse. This allows Up Down
75
keys to be used to scroll through font names.
76
When selecting a single item in a listbox, the font highlighted will be
77
displayed in a panel.
78
Some function names have changed and some docstrings added.
79
The main window should no longer be expandable.
540 subik 80
 
1048 cbradney 81
******************************************************************************
540 subik 82
"""
83
 
1048 cbradney 84
import sys
85
import os
222 Franz 86
 
1048 cbradney 87
try:
88
    import scribus
89
except ImportError,err:
90
    print "This Python script is written for the Scribus scripting interface."
91
    print "It can only be run from within Scribus."
92
    sys.exit(1)
222 Franz 93
 
1048 cbradney 94
try:
95
    from Tkinter import *
96
except ImportError,err:
97
    print "This script will not work without Tkinter"
98
    sys.exit(1)
99
 
100
 
3012 mrdocs 101
WINDOWTITLE = "Font Sampler v0.7.4tk - Steve Callcott"
1048 cbradney 102
TEMPPATH = os.path.join(os.path.expanduser("~"), ".scribus")
103
 
104
showPreviewPanel = 1  # change to 0 to permanently hide the preview
105
 
1072 cbradney 106
if showPreviewPanel:
1048 cbradney 107
    if not os.path.exists(TEMPPATH):
108
        print ".scribus folder not found, disabling font preview panel"
109
        showPreviewPanel = 0
110
 
1072 cbradney 111
if showPreviewPanel:
1048 cbradney 112
    if not os.access(TEMPPATH, os.W_OK):  
113
        print "Unable to write to .scribus folder, disabling font preview panel"
114
        showPreviewPanel = 0
115
 
116
 
117
if showPreviewPanel:
118
    try:
119
        import Image
120
    except ImportError,err:
121
        print "You need to install Python Imaging Library (PIL)."
122
        print "If using gentoo then you need to emerge /dev-python/imaging"
3002 mrdocs 123
        print "If using an RPM based linux distribution then you add python-imaging or similar."
1048 cbradney 124
        print "Script will continue without the font preview panel."
125
        showPreviewPanel = 0
126
 
127
 
128
if showPreviewPanel:
129
    try:
130
        import ImageTk
131
    except ImportError,err:
2991 mrdocs 132
        print "Module ImageTk not found, font preview disabled"
1048 cbradney 133
        showPreviewPanel = 0
134
 
135
 
136
# Define some empty containers for later...
137
app = None
138
root = None
139
samplePic = None
140
previewId = None
141
 
222 Franz 142
class BookStyle:
1048 cbradney 143
    pass
222 Franz 144
bookstyle = BookStyle()
145
 
146
 
147
class TocStyle:
1048 cbradney 148
    pass
222 Franz 149
tocstyle = TocStyle()
150
 
151
 
152
class Paper:
1048 cbradney 153
    pass
222 Franz 154
paper = Paper()
155
 
156
 
157
bookstyle.fixedfont = ""
158
bookstyle.propfont = ""
159
tocstyle.charsInRow = 75
160
 
161
 
162
def setFixedFont():
1048 cbradney 163
    fixed = (
164
    "Luxi Mono Regular",
3002 mrdocs 165
    "Nimbus Mono L Regular",
166
    "Courier 10 Pitch Regular",
167
    "Courier New Regular",
168
    "Courier Regular",
169
    "Andale Mono Regular",
1048 cbradney 170
    "Larabiefont Regular"
171
    )
222 Franz 172
 
1048 cbradney 173
    fontList = scribus.getFontNames()
174
    found = 0
175
    for f in fixed:
176
        if found == 1:
177
            break
178
        for i in fontList:
179
            if found == 0:
180
                if f == i:
181
                    bookstyle.fixedfont = f
182
                    found = 1
183
                    break
184
    if found == 0:
3002 mrdocs 185
        print "No suitable fixed width font found."
1048 cbradney 186
        print "Please install at least one of these fixed width fonts:"
187
        print fixed
222 Franz 188
 
189
 
190
def setPropFont():
1048 cbradney 191
    proportional = (
192
    "Nimbus Sans L Regular",
193
    "Luxi Sans Regular",
194
    "Bitstream Vera Sans",
195
    "Helvetica",
196
    "Arial Regular"
197
    )
222 Franz 198
 
1048 cbradney 199
    fontList = scribus.getFontNames()
200
    found = 0
201
    for p in proportional:
202
        if found == 1:
203
            break
204
        for i in fontList:
205
            if found == 0:
206
                if p == i:
207
                    bookstyle.propfont = p
208
                    found = 1
209
                    break
210
    if found == 0:
3002 mrdocs 211
        print "No suitable proportional font found."
1048 cbradney 212
        print "Please install at least one of these proportional fonts:"
213
        print proportional
222 Franz 214
 
215
 
216
def setPaperSize(paperSize):
1048 cbradney 217
    if paperSize == 1:              # A4 - 595 x 842 Points
2991 mrdocs 218
        paper.size = scribus.PAPER_A4
1048 cbradney 219
        paper.width = 595
220
        paper.height = 842
221
        paper.tmargin = 60
222
        paper.bmargin = 50
223
        paper.lmargin = 50
224
        paper.rmargin = 50
225
        paper.binding = 16
226
        tocstyle.tocRows = 56
227
        paper.pagenumvoffset = 16
228
        paper.textwidth = paper.width - paper.lmargin - paper.rmargin - 2
229
        paper.lmarginOdd = paper.lmargin + paper.binding
230
        paper.rmarginEven = paper.rmargin + paper.binding
231
        paper.textheight = paper.height - paper.tmargin - paper.bmargin
232
        paper.margins = paper.lmargin, paper.rmargin, paper.tmargin, paper.bmargin
233
    if paperSize == 2:              # US Letter - 612 x 792 Points
2991 mrdocs 234
        paper.size = scribus.PAPER_LETTER
1048 cbradney 235
        paper.width = 612
236
        paper.height = 792
237
        paper.tmargin = 27
238
        paper.bmargin = 45
239
        paper.lmargin = 50
240
        paper.rmargin = 50
241
        paper.binding = 18
242
        tocstyle.tocRows = 55
243
        paper.pagenumvoffset = 16
244
        paper.textwidth = paper.width - paper.lmargin - paper.rmargin - 2
245
        paper.lmarginOdd = paper.lmargin + paper.binding
246
        paper.rmarginEven = paper.rmargin + paper.binding
247
        paper.textheight = paper.height - paper.tmargin - paper.bmargin
248
        paper.margins = paper.lmargin, paper.rmargin, paper.tmargin, paper.bmargin
222 Franz 249
 
250
 
251
def setTextWidthForBinding(wantBindingOffset):
1048 cbradney 252
    # if we are adding a binding offset to the margins then we will have less width for our text.
253
    if wantBindingOffset == 1:
254
        paper.textwidth = paper.width - paper.lmargin - paper.rmargin - paper.binding - 2
255
    else:
256
        paper.textwidth = paper.width - paper.lmargin - paper.rmargin -2
222 Franz 257
 
258
 
259
def setPageGeometries():
1048 cbradney 260
    setPaperSize(app.paper.get())
261
    setTextWidthForBinding(app.wantBindingOffset.get())
222 Franz 262
 
263
 
264
def setOddEven(pageNum):
1048 cbradney 265
    """ Sets the left and right margins.
222 Franz 266
 
1048 cbradney 267
    Checks the number passed to it and sets left and right
268
    margins accordingly. Call once after each new page is created.
269
    Returns 1 if even and 0 if odd page.
270
    """
271
    if pageNum % 2 == 0:
272
        isEvenPage = 1                                          # Even side
273
    else:
274
        isEvenPage = 0                                          # Odd side
222 Franz 275
 
1048 cbradney 276
    if app.wantBindingOffset.get() == 1:
277
        if isEvenPage == 1 and app.wantDoubleSided.get() == 1:  # Even (when double sided)
278
            paper.leftSide = paper.lmargin + 1
279
            paper.rightSide = paper.rmarginEven + 1
280
        else:                                                   # Odd side
281
            paper.leftSide = paper.lmarginOdd + 1
282
            paper.rightSide = paper.rmargin + 1
283
    else:                                                       # No binding
284
        paper.leftSide = paper.lmargin + 1
285
        paper.rightSide = paper.rmargin + 1
222 Franz 286
 
1048 cbradney 287
    return isEvenPage
222 Franz 288
 
289
 
1048 cbradney 290
def addSampleRow(font, fontSize, lineSpace, textString, x, y, w, h, style, getSizeOnly):
291
    if getSizeOnly == 0:
292
        f = scribus.createText(x, y, w, h)
293
        scribus.insertText(textString, 0, f)
294
        if style == "l":
295
            scribus.setFont(bookstyle.propfont, f)
296
        else:
297
            scribus.setFont(font, f)
298
        scribus.setFontSize(fontSize, f)
299
        scribus.setLineSpacing(lineSpace, f)
300
        scribus.setTextAlignment(0, f)
301
    return y + h + 1
222 Franz 302
 
303
 
1048 cbradney 304
def drawSampleBlock(fontName, x, y, w, getSizeOnly):
305
    startPos = y
222 Franz 306
 
1048 cbradney 307
    # An "l" as last parameter will result in that line being in a plain font.
308
    # Use \xBC etc to insert Hex ascii chars into the sample strings below.
222 Franz 309
 
1048 cbradney 310
    samples = (
311
    # Template: fontsize, linespace, textstring, height, style
312
    # comment out any sample lines below that you do not require...
313
    [16, 15, fontName + '\n', 23, "l"],
314
    [10.5, 12, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#?$*&\n", 18, ""],
315
    [6, 6, "This line is in 6 point\n", 13, ""],
316
    [8, 8, "This line is in 8 point\n", 16, ""],
317
    [10, 11, "This line is in 10 point\n", 19, ""],
318
    [12, 11, "This line is in 12 point\n", 21, ""],
319
    [16, 13, "This line is in 16 point\n", 26, ""],
320
    [20, 16, "This line is in 20 point\n", 31, ""],
321
    [32, 29, "This line is in 32 point\n", 49, ""]
322
    )
222 Franz 323
 
1048 cbradney 324
    for i in samples:
325
        # (note there is one extra point inserted by addSampleRow() for each row generated)...
326
        y = addSampleRow(fontName, i[0], i[1], i[2], x, y, w, i[3], i[4], getSizeOnly)
327
    y = y + 1
222 Franz 328
 
1048 cbradney 329
    if getSizeOnly == 0:
330
        scribus.createLine(x, y, (w + x), y)
331
    else:
332
        y = y + 1   # if changing line above then check this, it should be exactly the same as the line height
333
    y = y + 5
334
    return y - startPos
222 Franz 335
 
336
 
1048 cbradney 337
def addTocRow(fontName, pageNum, yPos, frame):
338
    dotLine = ""
339
    dotQuant = tocstyle.charsInRow - len(fontName) - len(str(pageNum)) + 1
340
    for i in range(dotQuant):
341
        dotLine = dotLine + '.'
342
    oneLine = fontName + dotLine + str(pageNum) + "\n"
343
    scribus.insertText(oneLine, yPos, frame)
344
    yPos = yPos + len(oneLine) + 0
345
    return yPos
222 Franz 346
 
1048 cbradney 347
 
222 Franz 348
def buildTocPageFrames():
1048 cbradney 349
    # first put a header on the empty page...
350
    textstring = "Table of Contents"
351
    yPos = paper.tmargin + 1
352
    header = scribus.createText(paper.leftSide, yPos, paper.textwidth, 35)
353
    scribus.insertText(textstring, 0, header)
354
    scribus.setFont(bookstyle.propfont, header)
355
    scribus.setFontSize(24, header)
356
    scribus.setTextAlignment(1, header)
222 Franz 357
 
1048 cbradney 358
    # now create a text frame for the table of contents...
359
    yPos = yPos + 36
360
    body = scribus.createText(paper.leftSide, yPos, paper.textwidth, paper.height - yPos - paper.bmargin - 1)
361
    scribus.setFont(bookstyle.fixedfont, body)
362
    scribus.setFontSize(10, body)
363
    scribus.setLineSpacing(12, body)
364
    return body
222 Franz 365
 
366
 
367
def addToc(tocList):
1048 cbradney 368
    rowCount = 0
369
    yPos = 0
370
    tocPageNum = 1
371
    tocPageCount = 1
222 Franz 372
 
1048 cbradney 373
    scribus.newPage(tocPageNum)
374
    isEvenPage = setOddEven(tocPageNum)
375
    body = buildTocPageFrames()             # create frames for new empty page
376
    if isEvenPage == 0:
377
        scribus.setTextAlignment(2, body)
378
    else:
379
        scribus.setTextAlignment(0, body)
380
    for i in tocList:
381
        yPos = addTocRow(i[0], i[1], yPos, body)
382
        rowCount = rowCount + 1
383
        if rowCount > tocstyle.tocRows:     # Need to build a new TOC page (started from zero, not one)
384
            tocPageNum = tocPageNum + 1
385
            scribus.newPage(tocPageNum)
386
            isEvenPage = setOddEven(tocPageNum)
387
            body = buildTocPageFrames()
388
            if isEvenPage == 0:
389
                scribus.setTextAlignment(2, body)
390
            else:
391
                scribus.setTextAlignment(0, body)
392
            rowCount = 0
393
            yPos = 0
394
            tocPageCount = tocPageCount + 1
395
    if app.wantDoubleSided.get() == 1:
396
        if tocPageCount % 2 != 0:           # Odd page
397
            tocPageNum = tocPageNum + 1
398
            scribus.newPage(tocPageNum)     # Add an extra page if odd number
222 Franz 399
 
400
 
1048 cbradney 401
def addPageNum(pageNum):
402
    yPos = paper.height - paper.bmargin - paper.pagenumvoffset
403
    footer = scribus.createText(paper.leftSide, yPos, paper.textwidth, 15)
404
    scribus.insertText("%s" % pageNum, 0, footer)
405
    scribus.setFont(bookstyle.propfont, footer)
406
    scribus.setFontSize(9, footer)
407
    scribus.setTextAlignment(1, footer)
408
    scribus.setLineSpacing(10, footer)
222 Franz 409
 
410
 
1048 cbradney 411
def useSelection(fontList):
3012 mrdocs 412
    """Draws the sample blocks onto the Scribus canvas. Also updates the Progress Bar."""
413
    progress = 1
414
    scribus.progressReset()
415
    scribus.progressTotal(len(fontList))
1048 cbradney 416
    tocList = []
417
    yPos = paper.tmargin + 1
418
    pageNum = 1
2991 mrdocs 419
    if scribus.newDoc(paper.size, paper.margins, scribus.PORTRAIT, 1, scribus.UNIT_POINTS, scribus.NOFACINGPAGES, scribus.FIRSTPAGERIGHT):
1048 cbradney 420
        # We have a new page by default so set it up first...
421
        setOddEven(pageNum)
422
        if app.wantPageNum.get() == 1:
423
            addPageNum(pageNum)
424
        scribus.createLine(paper.leftSide, yPos, paper.leftSide + paper.textwidth, yPos)
425
        yPos = yPos + 5
426
        for i in fontList:
427
            # Test if fits...
428
            blockHeight = drawSampleBlock(i, paper.leftSide, yPos, paper.textwidth, 1)
429
            if yPos + blockHeight > paper.height - paper.bmargin - paper.pagenumvoffset:
430
                # Not enough room so create a new page first...
431
                scribus.newPage(-1)
432
                pageNum = pageNum + 1
433
                setOddEven(pageNum)
434
                yPos = paper.tmargin +1     # Reset y position back to top of page
435
                if app.wantPageNum.get() == 1:
436
                    addPageNum(pageNum)
437
                scribus.createLine(paper.leftSide, yPos, paper.leftSide + paper.textwidth, yPos)
438
                yPos = yPos + 5
439
            # Now place the actual sample block...
440
            blockHeight = drawSampleBlock(i, paper.leftSide, yPos, paper.textwidth, 0)
3012 mrdocs 441
            # and also increment the Scribus progress bar...
442
            scribus.progressSet(progress)
443
            progress = progress + 1
1048 cbradney 444
            yPos = yPos + blockHeight
445
            tocList.append([i, pageNum])    # Add to TOC
446
        if app.wantToc.get() == 1:
447
            addToc(tocList)                 # Insert table of contents - (before page numbering)
448
        scribus.gotoPage(1)
449
    app.quit()
222 Franz 450
 
451
 
1048 cbradney 452
def fontPreview(fontName):
453
    """Gets the named font and puts a sample in the preview panel.
454
 
455
    Pick up the temp sample qpixmap file and display it in a canvas object
456
    The temp file is put in the users ".scribus" folder and cleaned up on exit.
457
    We create samplePic as a global as a workaround because the reference count
458
    does not increase when we add the image to the canvas. Therefore python
459
    garbage collection removes our image before we have even displayed it.
460
    Note app.previewPanel is the actual canvas.
461
    """
462
    global samplePic
463
    global previewId
1072 cbradney 464
    scribus.renderFont(fontName, os.path.join(TEMPPATH,"temp079r.bmp"),"Woven silk pyjamas exchanged for blue quartz",28)    
465
    try:
466
        tempPic = Image.open(os.path.join(TEMPPATH,"temp079r.bmp"))
467
        tempPic.save(os.path.join(TEMPPATH,"temp079r.jpeg"),format="JPEG")
468
        tempImage = Image.open(os.path.join(TEMPPATH,"temp079r.jpeg"))
469
        imgDimen = tempPic.getbbox()
470
        samplePic = ImageTk.PhotoImage(tempImage)
471
        # To center the image use "Half display height minus half the image height"
472
        # preview panel is allegedly 56 (60 less a 2 pixel border top and bottom)
473
        # need to be lower than that to look correct visually... 
474
        topEdge = (32 - (imgDimen[3] / 2))
475
        previewId = app.previewPanel.create_image(5, topEdge, anchor=NW, image=samplePic)
476
        os.remove(os.path.join(TEMPPATH,"temp079r.bmp"))
477
        os.remove(os.path.join(TEMPPATH,"temp079r.jpeg"))
478
    except IOError:
479
        samplePic = None
480
        previewId = app.previewPanel.create_image(0, 0, anchor=NW, image=samplePic)
1048 cbradney 481
    return
482
 
483
 
222 Franz 484
class Application(Frame):
1048 cbradney 485
    def __init__(self, master = None):
486
        Frame.__init__(self, master)
222 Franz 487
 
1048 cbradney 488
        self.grid()
222 Franz 489
 
3002 mrdocs 490
        # Remove maximise button and resize. Not good to allow resizable window
491
        # because the listboxes are fixed width...
1048 cbradney 492
        self.master.resizable(0, 0)  
222 Franz 493
 
1048 cbradney 494
        # now start adding our widgets starting with the top frame...
495
        self.listbox_frame = Frame(self)
496
        self.listbox_frame.grid(row=0, column=0, sticky=EW)
222 Franz 497
 
1048 cbradney 498
        # left hand listbox assembly
499
        self.leftListbox_frame = Frame(self.listbox_frame, borderwidth=1, relief=SUNKEN)
500
        self.leftListbox_frame.grid(row=1, column=0)
222 Franz 501
 
1048 cbradney 502
        self.leftLabel = Label(self.listbox_frame, text="Available Fonts")
503
        self.leftLabel.grid(row=0, column=0, sticky=NS)
222 Franz 504
 
1048 cbradney 505
        self.yScroll1 = Scrollbar(self.leftListbox_frame, orient=VERTICAL)
506
        self.yScroll1.grid(row=0, column=1, sticky=NS)
507
        self.xScroll1 = Scrollbar(self.leftListbox_frame, orient=HORIZONTAL)
508
        self.xScroll1.grid(row=1, column=0, sticky=EW)
222 Franz 509
 
1048 cbradney 510
        self.listbox1 = Listbox(self.leftListbox_frame,
511
            xscrollcommand=self.xScroll1.set,
512
            yscrollcommand=self.yScroll1.set,
513
            selectmode=EXTENDED,
514
            height=20, width=40)
515
        self.listbox1.grid(row=0, column=0, sticky=NSEW)
516
        self.xScroll1["command"] = self.listbox1.xview
517
        self.yScroll1["command"] = self.listbox1.yview
222 Franz 518
 
1048 cbradney 519
        def __listbox1KeyRelease(event):
520
            """Check if an Up or Down key has been pressed and released and
521
            if so the preview panel is refreshed. If the keys are held down
522
            the file system slows the scroll. Need a timer here to delay
523
            updates."""
524
            if (event.keysym == "Down" or event.keysym == "Up"):
525
                __listbox1DoLogicCallback(self)
222 Franz 526
 
1048 cbradney 527
        def __listbox1SingleClick(event):
528
            """Call this first when listbox1 is clicked with mouse to put focus
529
            into the listbox. Note we call when mouse click is released, not pressed,
530
            due to the fact that the listbox does not change the selection until the button
531
            is released."""
532
            self.listbox1.focus_set()
533
            __listbox1DoLogicCallback(self)
534
        self.listbox1.bind("<ButtonRelease-1>", __listbox1SingleClick)
222 Franz 535
 
1048 cbradney 536
        def __listbox1DoLogicCallback(event):
537
            """Decides if current selection should be previewed.
1066 cbradney 538
 
1048 cbradney 539
            Start by counting items in selection list and if equal to one then
540
            show selected font, ignoring if more or less than one. Then also
541
            set up buttons logic depending on selection. We bind the FocusIn
542
            to this too so button logic and preview gets updated when focus
543
            enters the listbox.
544
            """        
545
            # note we are not making use of "self.listbox1.get(ACTIVE)" due to
546
            # it not getting the real active name. Always one selection behind
547
            # even though we are doing all this in the ButtonRelease event.
548
            # Have made a change here. If more than one font name is selected
549
            # then we just empty the preview.
550
            names = self.listbox1.curselection()
551
            if len(names) == 1:
552
                selectedFont = self.listbox1.get(names[0])
553
                self.__curSelectedItem(selectedFont)
554
            else:
555
                try:
556
                    app.previewPanel.delete(previewId)
557
                except:
558
                    pass
559
            #else:
560
                #selectedFont = self.listbox1.get(ACTIVE) 
561
                #print selectedFont  # for testing
562
                #if selectedFont != "":
563
                    #self.__curSelectedItem(selectedFont)                
222 Franz 564
 
1048 cbradney 565
            # Now do the button logic...
566
            self.listbox2.selection_clear(0,END)
567
            self.__setUpDownActive(0, 0)    # Force a disable if in other box
568
            if self.listbox1.size() > 0:
569
                self.__setSelButtonsActive(0, 1)
570
            else:
571
                self.__setSelButtonsActive(0, 0)
572
        self.listbox1.bind("<FocusIn>", __listbox1DoLogicCallback)
573
        self.listbox1.bind('<Any-KeyRelease>', __listbox1KeyRelease)
222 Franz 574
 
1048 cbradney 575
        def __listbox1DoubleClickCallback(event):
576
            """The single click event will fire also when left listbox
577
            is double clicked but we are detecting the single click button up event."""
578
            self.__listSelectionToRight()
579
        self.listbox1.bind("<Double-Button-1>", __listbox1DoubleClickCallback)
222 Franz 580
 
1048 cbradney 581
        # middle button frame assembly
582
        self.midbutton_frame = Frame(self.listbox_frame)
583
        self.midbutton_frame.grid(row=0, rowspan=2, column=1, sticky=NSEW)
222 Franz 584
 
1048 cbradney 585
        self.rsingleButton = Button(self.midbutton_frame, state='disabled', text=">", command=self.__rsingleButtonClick)
586
        self.rsingleButton.grid(row=0, column=0, padx=5, pady=5, sticky=EW)
587
        self.rdoubleButton = Button(self.midbutton_frame, text=">>", command=self.__rdoubleButtonClick)
588
        self.rdoubleButton.grid(row=1, column=0, padx=5, pady=5, sticky=EW)
222 Franz 589
 
1048 cbradney 590
        self.itemupButton = Button(self.midbutton_frame, state='disabled', text="Up", command=self.__itemupButtonClick)
591
        self.itemupButton.grid(row=2, column=0, padx=5, pady=5, sticky=EW)
592
        self.itemdownButton = Button(self.midbutton_frame, state='disabled', text="Down", command=self.__itemdownButtonClick)
593
        self.itemdownButton.grid(row=3, column=0, padx=5, pady=5, sticky=EW)
222 Franz 594
 
1048 cbradney 595
        self.lsingleButton = Button(self.midbutton_frame, state='disabled', text="<", command=self.__lsingleButtonClick)
596
        self.lsingleButton.grid(row=4, column=0, padx=5, pady=5, sticky=EW)
597
        self.ldoubleButton = Button(self.midbutton_frame, state='disabled', text="<<", command=self.__ldoubleButtonClick)
598
        self.ldoubleButton.grid(row=5, column=0, padx=5, pady=5, sticky=EW)
222 Franz 599
 
1048 cbradney 600
        # Right hand listbox assembly
601
        self.rightListbox_frame = Frame(self.listbox_frame, borderwidth=1, relief=SUNKEN)
602
        self.rightListbox_frame.grid(row=1, column=2)
222 Franz 603
 
1048 cbradney 604
        self.rightLabel = Label(self.listbox_frame, text="Selected Fonts")
605
        self.rightLabel.grid(row=0, column=2, sticky=NS)
222 Franz 606
 
1048 cbradney 607
        self.yScroll2 = Scrollbar(self.rightListbox_frame, orient=VERTICAL)
608
        self.yScroll2.grid(row=0, column=1, sticky=NS)
609
        self.xScroll2 = Scrollbar(self.rightListbox_frame, orient=HORIZONTAL)
610
        self.xScroll2.grid(row=1, column=0, sticky=EW)
222 Franz 611
 
1048 cbradney 612
        self.listbox2 = Listbox(self.rightListbox_frame,
613
            xscrollcommand=self.xScroll2.set,
614
            yscrollcommand=self.yScroll2.set,
615
            selectmode=EXTENDED,
616
            height=20, width=40)
617
        self.listbox2.grid(row=0, column=0, sticky=NSEW)
618
        self.xScroll2["command"] = self.listbox2.xview
619
        self.yScroll2["command"] = self.listbox2.yview
222 Franz 620
 
1048 cbradney 621
        def __listbox2SingleClick(event):
622
            """Similar to __listbox1SingleClick()."""
623
            self.listbox2.focus_set()
624
            __listbox2DoLogicCallback(self)
625
        self.listbox2.bind("<ButtonRelease-1>", __listbox2SingleClick)
222 Franz 626
 
1048 cbradney 627
        def __listbox2KeyRelease(event):
628
            if (event.keysym == "Down" or event.keysym == "Up"):
629
                __listbox2DoLogicCallback(self)
222 Franz 630
 
1048 cbradney 631
        def __listbox2DoLogicCallback(event):
632
            """Similar to __listbox1DoLogicCallback()."""        
633
            names = self.listbox2.curselection()
634
            if len(names) == 1:
635
                selectedFont = self.listbox2.get(names[0])
636
                self.__curSelectedItem(selectedFont)
637
            else:
638
                try:
639
                    app.previewPanel.delete(previewId)
640
                except:
641
                    pass
222 Franz 642
 
1048 cbradney 643
            # Now do the button logic...
644
            self.listbox1.selection_clear(0,END)
645
            self.__testUpDownState()
646
            if self.listbox2.size() > 0:
647
                self.__setSelButtonsActive(1, 0)
648
            else:
649
                self.__setSelButtonsActive(0, 0)
650
        self.listbox2.bind("<FocusIn>", __listbox2DoLogicCallback)
651
        self.listbox2.bind('<Any-KeyRelease>', __listbox2KeyRelease)
222 Franz 652
 
1048 cbradney 653
        def __listbox2DoubleClickCallback(event):
654
            """Similar to __listbox1DoubleClickCallback()."""
655
            self.__listSelectionToLeft()
656
        self.listbox2.bind("<Double-Button-1>", __listbox2DoubleClickCallback)
222 Franz 657
 
1048 cbradney 658
        # now draw the bottom font preview frame if required...
659
        if showPreviewPanel:
660
            self.preview_frame = Frame(self)
661
            self.preview_frame.grid(row=1, column=0, sticky=EW)
662
            self.previewPanel = Canvas(self.preview_frame, height=60, bg="white", bd=2, relief=SUNKEN)
663
            self.previewPanel.pack(fill=X)
222 Franz 664
 
1048 cbradney 665
        # now draw the bottom controls frame...
666
        self.controls_frame = Frame(self)
667
        self.controls_frame.grid(row=2, column=0, sticky=EW)
222 Franz 668
 
1048 cbradney 669
        # now the paper size radio buttons...
670
        self.paper = IntVar()
671
        self.radiobutton_frame = Frame(self.controls_frame, bd=1, relief=RIDGE)
672
        self.radiobutton_frame.grid(row=0, column=0, padx=10, pady=2)
673
        self.a4papersizeSelect = Radiobutton(self.radiobutton_frame, text="A4", variable=self.paper, value=1, command=self.__a4paperButtonClick)
674
        self.a4papersizeSelect.grid(row=0, column=0, padx=0, sticky=W)
675
        self.uspapersizeSelect = Radiobutton(self.radiobutton_frame, text="US Letter", variable=self.paper, value=2, command=self.__uspaperButtonClick)
676
        self.uspapersizeSelect.grid(row=1, column=0, padx=0, sticky=W)
677
        self.a4papersizeSelect.select()
222 Franz 678
 
1048 cbradney 679
        # now the TOC and page number selection buttons...
680
        self.wantToc = IntVar()
681
        self.wantPageNum = IntVar()
682
        self.togglebutton_frame = Frame(self.controls_frame, bd=1, relief=RIDGE)
683
        self.togglebutton_frame.grid(row=0, column=1, padx=10, pady=2)
684
        self.pagenumSelect = Checkbutton(self.togglebutton_frame, text="want page numbers", variable=self.wantPageNum, offvalue=0, onvalue=1)
685
        self.pagenumSelect.grid(row=0, column=0, padx=0, sticky=W)
686
        self.tocSelect = Checkbutton(self.togglebutton_frame, text="Print TOC", variable=self.wantToc, offvalue=0, onvalue=1)
687
        self.tocSelect.grid(row=1, column=0, padx=0, sticky=W)
688
        self.pagenumSelect.select()
689
        self.tocSelect.select()
222 Franz 690
 
1048 cbradney 691
        # now the binding offset and double sided selection buttons...
692
        self.wantBindingOffset = IntVar()
693
        self.wantDoubleSided = IntVar()
694
        self.bindingbutton_frame = Frame(self.controls_frame, bd=1, relief=RIDGE)
695
        self.bindingbutton_frame.grid(row=0, column=2, padx=10, pady=2)
696
        self.bindingoffsetSelect = Checkbutton(self.bindingbutton_frame, text="Extra offset for binding", variable=self.wantBindingOffset, offvalue=0, onvalue=1, command=self.__bindingoffsetSelectButtonClick)
697
        self.bindingoffsetSelect.grid(row=0, column=0, sticky=W)
698
        self.doublesidedSelect = Checkbutton(self.bindingbutton_frame, text="Double sided pages", variable=self.wantDoubleSided, offvalue=0, onvalue=1)
699
        self.doublesidedSelect.grid(row=1, column=0, rowspan=2, sticky=W)
222 Franz 700
 
1048 cbradney 701
        # now the ok and cancel buttons...
702
        self.cancelButton = Button(self.controls_frame, text="Cancel", command=self.__cancelButtonClick)
703
        self.cancelButton.grid(row=0, column=3, padx=5)
704
        self.okButton = Button(self.controls_frame, text="OK", state='disabled', command=self.__okButtonClick)
705
        self.okButton.grid(row=0, column=4, padx=5)
222 Franz 706
 
1048 cbradney 707
        # now create the bottom status bar frame and contents...
708
        self.status_frame = Frame(self)
709
        self.status_frame.grid(row=3, column=0, sticky=E+W)
710
        self.status0 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W)
711
        self.status0.pack(side=LEFT)
712
        self.status1 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W)
713
        self.status1.pack(side=LEFT)
714
        self.status2 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W)
715
        self.status2.pack(fill=X)
222 Franz 716
 
1048 cbradney 717
    def statusbarUpdate(self):
718
        available = self.listbox1.size()
719
        selected = self.listbox2.size()
720
        size = FloatType(selected)
721
        value = size / 3
722
        pages = IntType(value)                  # Get whole part of number
723
        value = value - pages                   # Remove whole number part
724
        if value > 0:                           # Test remainder
725
            pages = pages + 1                   # Had remainder so add a page
726
        self.status0['text'] = "Fonts available: %s    " % (available + selected)
727
        self.status1['text'] = "Fonts selected: %s    " % selected
728
        self.status2['text'] = "Sheets required: %s    " % pages
222 Franz 729
 
1048 cbradney 730
    def __listSelectionToRight(self):
731
        toMoveRight = ListType(self.listbox1.curselection())
732
        self.listbox1.selection_clear(0,END)
733
        toMoveRight.reverse()   # reverse list so we delete from bottom of listbox first
734
        tempList = []
735
        for i in toMoveRight:
736
            tempList.insert(0,self.listbox1.get(i)) # gets the actual strings (reverse again)
737
            self.listbox1.delete(i)
738
        for j in tempList:
739
            self.listbox2.insert(END, j)
740
        self.__setButtonsState()
741
        self.__setSelButtonsActive(0, 0)
742
        self.statusbarUpdate()
222 Franz 743
 
1048 cbradney 744
    def __listSelectionToLeft(self):
745
        toMoveLeft = ListType(self.listbox2.curselection())
746
        toMoveLeft.reverse()
747
        self.listbox2.selection_clear(0,END)
748
        for i in toMoveLeft:
749
            self.listbox1.insert(END, self.listbox2.get(i)) # Insert it at the end
750
            self.listbox2.delete(i)
751
        fontList = ListType(self.listbox1.get(0, END))      # Copy contents to a list type
752
        self.listbox1.delete(0, END)                        # Remove all contents
753
        fontList.sort()                                     # Use sort method of list
754
        for j in fontList:
755
            self.listbox1.insert(END, j)                    # Replace with sorted version
756
        self.__setButtonsState()
757
        self.__setSelButtonsActive(0, 0)
758
        self.statusbarUpdate()
222 Franz 759
 
1048 cbradney 760
    def __listAllToRight(self):
761
        fontList = self.listbox1.get(0, END)    # Get each font name into a list
762
        for i in fontList:
763
            self.listbox2.insert(END, i)        # Copy each one
764
        self.listbox1.delete(0, END)            # All done so empty the left listbox
765
        self.__setButtonsState()
766
        self.__setSelButtonsActive(0, 0)
767
        self.statusbarUpdate()
222 Franz 768
 
1048 cbradney 769
    def __listAllToLeft(self):
770
        # This quick way just clears both sides and reloads left listbox in correct order from scratch
771
        self.listbox1.delete(0, END)
772
        fontList = scribus.getFontNames()
773
        fontList.sort()
774
        for i in fontList:
775
            self.listbox1.insert(END, i)
776
        self.listbox2.delete(0, END)
777
        self.__setButtonsState()
778
        self.__setSelButtonsActive(0, 0)
779
        self.statusbarUpdate()
222 Franz 780
 
1048 cbradney 781
    def __setSelButtonsActive(self, selToRight, selToLeft):
782
        # The "selection" buttons are the ones with ">"  and "<"  on them
783
        if selToRight == 1:
784
            self.lsingleButton['state'] = NORMAL
785
        else:
786
            self.lsingleButton['state'] = DISABLED
787
        if selToLeft == 1:
788
            self.rsingleButton['state'] = NORMAL
789
        else:
790
            self.rsingleButton['state'] = DISABLED
222 Franz 791
 
1048 cbradney 792
    def __setAllButtonsActive(self, allToRight, allToLeft):
793
        # The "all" buttons are the ones with ">>"  and "<<"  on them
794
        if allToRight == 1:
795
            self.rdoubleButton['state'] = NORMAL
796
        else:
797
            self.rdoubleButton['state'] = DISABLED
798
        if allToLeft == 1:
799
            self.ldoubleButton['state'] = NORMAL
800
        else:
801
            self.ldoubleButton['state'] = DISABLED
222 Franz 802
 
1048 cbradney 803
    def __setButtonsState(self):
804
        if self.listbox2.size() > 0 and self.listbox1.size() > 0:
805
            self.__setAllButtonsActive(1, 1)
806
            self.okButton['state'] = NORMAL
807
        elif self.listbox2.size() == 0:
808
            self.__setAllButtonsActive(1, 0)
809
            self.okButton['state'] = DISABLED
810
        elif self.listbox1.size() == 0:
811
            self.__setAllButtonsActive(0, 1)
812
            self.okButton['state'] = NORMAL
222 Franz 813
 
1048 cbradney 814
    def __itemUp(self):
815
        """Test if one item is selected then move it up one position."""
816
        selection = self.listbox2.curselection()
817
        if len(selection) == 1:        
818
            indexId = IntType(selection[0]) # Get the first (only) item as integer type
819
            if indexId > 0:
820
                fontString = self.listbox2.get(indexId)
821
                self.listbox2.delete(indexId)
822
                newPos = indexId - 1
823
                self.listbox2.selection_clear(0, END)
824
                self.listbox2.insert(newPos, fontString)
825
                self.listbox2.see(newPos - 10)  # Scrolls listbox automatically into view if req.
826
                self.listbox2.selection_set(newPos)
827
                self.listbox2.activate(newPos)  # make focus follow selection
828
                self.__testUpDownState()  # note tests only after an item has been moved
222 Franz 829
 
1048 cbradney 830
    def __itemDown(self):
831
        """Test if one item is selected then move it down one position."""
832
        limit = self.listbox2.size()
833
        selection = self.listbox2.curselection()
834
        if len(selection) == 1:
835
            indexId = IntType(selection[0])
836
            if indexId < limit - 1:
837
                fontString = self.listbox2.get(indexId)
838
                self.listbox2.delete(indexId)
839
                newPos = indexId + 1
840
                self.listbox2.selection_clear(0, END)
841
                self.listbox2.insert(newPos, fontString)
842
                self.listbox2.see(newPos + 10)
843
                self.listbox2.selection_set(newPos)
844
                self.listbox2.activate(newPos)  # make focus follow selection
845
                self.__testUpDownState()
222 Franz 846
 
1048 cbradney 847
    def __setUpDownActive(self, up, down):
848
        """Just sets the buttons active or inactive
849
        See testUpDown() for actual evaluation"""
850
        if up == 1:
851
            self.itemupButton['state'] = NORMAL
852
        else:
853
            self.itemupButton['state'] = DISABLED
854
        if down == 1:
855
            self.itemdownButton['state'] = NORMAL
856
        else:
857
            self.itemdownButton['state'] = DISABLED
222 Franz 858
 
1048 cbradney 859
    def __testUpDownState(self):
860
        # Only ungray the up and down buttons when just a single item is
861
        # selected and then it should be up, down or both depending on its
862
        # position in the listbox. At all other times gray out both.
222 Franz 863
 
1048 cbradney 864
        # Get a count of how many items are currently selected...
865
        selection = list(self.listbox2.curselection())
866
        tcount = 0
867
        for sel in selection:
868
            tcount = tcount + 1
222 Franz 869
 
1048 cbradney 870
        position = 0
871
        if tcount == 1:
872
            position = IntType(selection[0])
222 Franz 873
 
1048 cbradney 874
        # If one selected and there is more than one item in the listbox then ok...
875
        if tcount == 1 and self.listbox2.size() > 1:
876
            # Now test the position of the selected line...
877
            if position > 0 and position < self.listbox2.size() - 1:    # Both
878
                self.__setUpDownActive(1, 1)
879
            # If not one less or lesser from the bottom (listbox.count-1?) then gray the down button.
880
            elif position == self.listbox2.size() - 1:                  # Up only
881
                self.__setUpDownActive(1, 0)
882
            # If not one or more from the top then gray up button.
883
            elif position == 0:                                         # Down only
884
                self.__setUpDownActive(0, 1)
885
        else:
886
            self.__setUpDownActive(0, 0)
222 Franz 887
 
1048 cbradney 888
    def __curSelectedItem(self, selectedFont):
889
        """Send the selected font to the preview function if preview available."""
890
        if showPreviewPanel:
891
            fontPreview(selectedFont)
222 Franz 892
 
1048 cbradney 893
    def quit(self):
894
        self.master.destroy()
222 Franz 895
 
1048 cbradney 896
    # create the button events...
897
    def __rsingleButtonClick(self):
898
        self.__listSelectionToRight()
751 subik 899
 
1048 cbradney 900
    def __rdoubleButtonClick(self):
901
        self.__listAllToRight()
902
 
903
    def __lsingleButtonClick(self):
904
        self.__listSelectionToLeft()
905
        self.__testUpDownState()
906
 
907
    def __ldoubleButtonClick(self):
908
        self.__listAllToLeft()
909
        self.__testUpDownState()
910
 
911
    def __itemupButtonClick(self):
912
        self.__itemUp()
913
 
914
    def __itemdownButtonClick(self):
915
        self.__itemDown()
916
 
917
    def __cancelButtonClick(self):
918
        self.master.destroy()
919
 
920
    def __bindingoffsetSelectButtonClick(self):
921
        setPageGeometries()
922
 
923
    def __a4paperButtonClick(self):
924
        setPageGeometries()
925
 
926
    def __uspaperButtonClick(self):
927
        setPageGeometries()
928
 
929
    def __okButtonClick(event):
930
        useSelection(app.listbox2.get(0, END))
931
 
932
 
933
def setupTk():
934
    """Create and setup the Tkinter app."""
935
    global root
936
    global app
937
    root = Tk()
938
    app = Application(root)
939
    app.master.title(WINDOWTITLE)
940
 
941
 
942
def initialiseGui():
943
    """Setup the default settings for the window."""
944
    # get and set the initial paper size to match default radiobutton selection
945
    setPageGeometries()
946
    # now get a list of all the fonts...
947
    fontList = scribus.getFontNames()
948
    fontList.sort()
949
    # and put the list in the GUI listbox...
950
    for i in fontList:
951
        app.listbox1.insert(END, i)
952
    setFixedFont()
953
    setPropFont()
954
    app.statusbarUpdate()    
955
 
956
 
957
def main(argv):
958
    """Application initialization, font checks and initial setup."""
959
    # first create our Tkinter app...
960
    setupTk()
961
 
962
    # Set up defaults...
963
    initialiseGui()
964
 
965
    # now show the fonts list and wait for user to make a choice...
966
    app.mainloop()
967
 
968
 
969
def main_wrapper(argv):
970
    """The main_wrapper() function disables redrawing, sets a sensible generic
971
    status bar message, and optionally sets up the progress bar. It then runs
972
    the main() function. Once everything finishes it cleans up after the main()
973
    function, making sure everything is sane before the script terminates."""
974
    try:
975
        scribus.statusMessage("Running script...")
976
        scribus.progressReset()
977
        main(argv)
978
    finally:
979
        # Exit neatly even if the script terminated with an exception,
980
        # so we leave the progress bar and status bar blank and make sure
981
        # drawing is enabled.
982
        if scribus.haveDoc():
983
            scribus.setRedraw(True)
984
        scribus.statusMessage("")
985
        scribus.progressReset()
986
 
987
 
988
# This code detects if the script is being run as a script, or imported as a module.
989
# It only runs main() if being run as a script. This permits you to import your script
990
# and control it manually for debugging.
991
if __name__ == '__main__':
992
    main_wrapper(sys.argv)
993