Subversion Repositories Scribus

Rev

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