Subversion Repositories Scribus

Rev

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