1#!/usr/bin/env python 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18# 19# **************************************************************************** 20 21""" 22****************************************************************************** 23 24DESCRIPTION & USAGE: 25This script needs Tkinter. It will create a GUI with an alphabetical list 26of fonts using the names as they will be shown in Scribus. User can select 27one or more fonts and create an example sheet(s) to print or create a PDF 28from. It is heavily commented to make it easier for the user to adjust it 29for his / her own needs. 30 31Note: this version needs read/write access to .scribus directory in users 32home. You will also need Python Imaging Library (PIL) installed. 33If your system does not meet these requirements then change showPreviewPanel 34to a value of 0. This will disable the new preview features. 35 36****************************************************************************** 37 38First release : 30/12/2003 39This release : v0.8.1tk (released 4th Dec 2005) 40Copyright : (C) 2003 - 2005 Steve Callcott 41Latest releases 42and support : www.firstwish.co.uk/sjc/scribus/index.php 43Maintainer : Steve Callcott 2003 - 2005 44Email : stotte@firstwish.co.uk 45 46For revision history see the ChangeLog file. 47Bugs and future plans are listed in the TODO file. 48See NEWS for new features since last version. 49 50WHATS NEW v0.8.2tk: 51A one liner change by Jean Ghali to line #734 to add the extra parameter missing. 52See: http://bugs.scribus.net/view.php?id=4377 53 54WHATS NEW v0.8.1tk: 55After reloading users saved preferences the status bar was not showing 56correct calculations. 57Changed text in settings menu. 58 59WHATS NEW v0.8tk Final: 60Cleaned up the checkbox labels and layout. 61 62WHATS NEW v0.8tk Preview 3: 63Calls the new Scribus zoomDocument() function to make the completed font 64sample document fit in Scribus window. 65 66Grey out "Start page number count from first page" when "Print TOC" is 67not checked as without a table of contents the first page would always 68start on the same page number making this option irrelevant. 69 70WHATS NEW v0.8tk Preview 2: 71Replaced the newDoc() with newDocument(). Have not put any fallback code 72for use with earlier Scribus versions. 73 74When using double sided option we now make use of Scribus ability to display 75pages side by side as default. You may need to zoom out to view the 76complete document width. 77 78WHATS NEW v0.8tk Preview 1: 79Rearanged the initialisation. If no fonts are found for the Table of 80Contents, page numbers and font sample labels, the script shows a 81message box listing the problem and a possible solution as well as a message 82to the console. 83 84A Scribus messagebox alerts the user if Tkinter is not found. Previously 85this message was only printed to the console. 86 87Now able to do a dummy run to calculate and report the amount of samples 88that will fit on a page. This enables the script to correctly calculate 89how many sheets will be required. Previously it was always assumed that 90there would be 3 sample blocks on a sheet. This is now not always the case. 91 92Added menu. Also added "about" and "settings" dialogs. 93 94Sample rows can be selected or unselected to save on paper. The settings are 95automatically saved when changed and can be set as user defaults. 96 97User can choose to have page numbers count from first page of the toc instead 98of the first page of samples. This can be helpful if wanting to quickly look 99up a font in the toc and then using the Scribus page navigator dialog to go to 100the actual page on the screen to view it without printing it out. 101 102Added initial support for a sample paragraph. The sample paragraph defaults 103to "off" due to the amount of space it uses on the page. 104 105Some widgets read their defaults from a config dictionary. 106 107Many code cleanups. Classes used for settings storage have been replaced with 108dictionaries to make it easier for users to customise. 109 110****************************************************************************** 111""" 112 113import sys 114import os 115import cPickle 116 117 118showPreviewPanel = 1 # change to 0 to permanently hide the preview 119TEMP_PATH = os.path.join(os.path.expanduser('~'), '.scribus') 120CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.scribus/fontsampler') 121 122 123try: 124 import scribus 125except ImportError,err: 126 print 'This Python script is written for the Scribus scripting interface.' 127 print 'It can only be run from within Scribus.' 128 sys.exit(1) 129 130 131try: 132 from Tkinter import * 133except ImportError,err: 134 print 'This script will not work without Tkinter' 135 scribus.messageBox('Error','This script will not work without Tkinter\nPlease install and try again', 136 scribus.ICON_WARNING) 137 sys.exit(1) 138 139 140if not os.path.exists(CONFIG_PATH): 141 try: 142 print 'Attempting to creating configuration file directory...' 143 os.mkdir(CONFIG_PATH) 144 print 'Success, now testing for write access of new directory...' 145 if os.access(CONFIG_PATH, os.W_OK): 146 print 'Write access ok.' 147 else: 148 print 'Error, unable to write to .scribus/fontsampler directory.' 149 except: 150 CONFIG_PATH = '' 151 print 'Failed to make configuration file directory,' 152 print 'do you have a .scribus directory in your home directory?' 153 print 'font sampler will not be able to save your preferences' 154 155 156try: 157 from PIL import Image 158except ImportError,err: 159 print 'You need to install Python Imaging Library (PIL).' 160 print 'If using gentoo then you need to emerge /dev-python/imaging' 161 print 'If using an RPM based linux distribution then you add python-imaging or similar.' 162 print 'Script will continue without the font preview panel.' 163 showPreviewPanel = 0 164 165 166try: 167 from PIL import ImageTk 168except ImportError,err: 169 print 'Module ImageTk not found, font preview disabled' 170 showPreviewPanel = 0 171 172 173if showPreviewPanel: 174 if not os.path.exists(TEMP_PATH): 175 print '.scribus folder not found, disabling font preview panel' 176 showPreviewPanel = 0 177 if not os.access(TEMP_PATH, os.W_OK): 178 print 'Unable to write to .scribus folder, disabling font preview panel' 179 showPreviewPanel = 0 180 181 182# A few globals for use later... 183gSamplePic = None 184gPreviewId = None 185 186#************************************************************************* 187 188WINDOW_TITLE = 'Font Sampler v0.8.1tk - Steve Callcott' 189SUPPORT_PAGE = 'www.firstwish.co.uk/sjc/scribus/index.php' 190 191fontsListFixed = ( 192 'Luxi Mono Regular', 193 'Nimbus Mono L Regular', 194 'Courier 10 Pitch Regular', 195 'Courier New Regular', 196 'Courier Regular', 197 'Andale Mono Regular', 198 'Larabiefont Regular' 199) 200 201fontsListProportional = ( 202 'Nimbus Sans L Regular', 203 'Luxi Sans Regular', 204 'Bitstream Vera Sans', 205 'Helvetica', 206 'Arial Regular' 207) 208 209defaultPrefs = { 210 'wantDoubleSided': 0, 211 'paperSize':'A4', # currently PAPER_LETTER or PAPER_A4 212 'wantTOC': 1, 213 'wantBindingOffset': 0, 214 'wantPageNumbers': 1, 215 'wantPageOneOnFirst': 0, 216 'wantAlphabet' : 1, 217 'want6Point' : 1, 218 'want8Point' : 1, 219 'want10Point' : 1, 220 'want12Point' : 1, 221 'want16Point' : 1, 222 'want20Point' : 1, 223 'want32Point' : 1, 224 'wantParagraph' : 0 # Uses a lot of space so default is off 225} 226 227userPrefs = {} 228 229geometriesList = [ 230 { 231 'paperName' : 'A4', 232 'paperSize' : scribus.PAPER_A4, 233 'paperWidth' : 595, 234 'paperHeight' : 842, 235 'paperTopMargin' : 60, 236 'paperBottomMargin' : 50, 237 'paperLeftMargin' : 50, 238 'paperRightMargin' : 50, 239 'paperBinding' : 16, 240 'tocRowsPerPage' : 57, 241 'paperPageNumVertOffset' : 16 242 }, 243 { 244 'paperName' : 'US Letter', 245 'paperSize' : scribus.PAPER_LETTER, 246 'paperWidth' : 612, 247 'paperHeight' : 792, 248 'paperTopMargin' : 27, 249 'paperBottomMargin' : 45, 250 'paperLeftMargin' : 50, 251 'paperRightMargin' : 50, 252 'paperBinding' : 18, 253 'tocRowsPerPage' : 56, 254 'paperPageNumVertOffset' : 16 255 } 256] 257 258# define our data dictionary and some of the data... 259dD = { 260 'tocHeaderTitle' : 'Table of Contents', 261 'tocCharsInRow' : 75, 262 'previewpanelFontHeight' : 28, 263 'previewpanelSampleText' : 'Woven silk pyjamas exchanged for blue quartz' 264} 265 266samplesHeader = { 267 'fontSize' : 16, 268 'lineSpace' : 15, 269 'textHeight' : 23 270} 271 272# Use \xBC etc to insert Hex ascii chars into the sample strings below. 273sampleAlphabet = { 274 'fontSize' : 10.5, 275 'lineSpace' : 12, 276 'textString' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#?$*&', 277 'textHeight' : 18 278} 279 280sample6Point = { 281 'fontSize' : 6, 282 'lineSpace' : 6, 283 'textString' : 'This line is in 6 point', 284 'textHeight' : 13 285} 286 287sample8Point = { 288 'fontSize' : 8, 289 'lineSpace' : 8, 290 'textString' : 'This line is in 8 point', 291 'textHeight' : 16 292} 293 294sample10Point = { 295 'fontSize' : 10, 296 'lineSpace' : 11, 297 'textString' : 'This line is in 10 point', 298 'textHeight' : 19 299} 300 301sample12Point = { 302 'fontSize' : 12, 303 'lineSpace' : 11, 304 'textString' : 'This line is in 12 point', 305 'textHeight' : 21 306} 307 308sample16Point = { 309 'fontSize' : 16, 310 'lineSpace' : 13, 311 'textString' : 'This line is in 16 point', 312 'textHeight' : 26 313} 314 315sample20Point = { 316 'fontSize' : 20, 317 'lineSpace' : 16, 318 'textString' : 'This line is in 20 point', 319 'textHeight' : 31 320} 321 322sample32Point = { 323 'fontSize' : 32, 324 'lineSpace' : 29, 325 'textString' : 'This line is in 32 point', 326 'textHeight' : 49 327} 328 329sampleParagraph = { 330 'fontSize' : 9, 331 'lineSpace' : 10.8, 332 'textHeight' : 175 333} 334 335sampleParagraphText = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut a sapien. \ 336Aliquam aliquet purus molestie dolor. Integer quis eros ut erat posuere dictum. \ 337Curabitur dignissim. Integer orci. Fusce vulputate lacus at ipsum. Quisque in libero \ 338nec mi laoreet volutpat. Aliquam eros pede, scelerisque quis, tristique cursus, \ 339placerat convallis, velit. Nam condimentum. Nulla ut mauris. Curabitur adipiscing, \ 340mauris non dictum aliquam, arcu risus dapibus diam, nec sollicitudin quam erat quis \ 341ligula. Aenean massa nulla, volutpat eu, accumsan et, fringilla eget, odio. \ 342Nulla placerat porta justo. Nulla vitae turpis.\n\nPraesent lacus.Lorem ipsum dolor sit \ 343amet, consectetuer adipiscing elit. Pellentesque habitant morbi tristique senectus \ 344et netus et malesuada fames ac turpis egestas. Quisque vel erat eget diam \ 345consectetuer iaculis. Cras ante velit, suscipit et, porta tempus, dignissim quis, \ 346magna. Vivamus viverra, turpis nec rhoncus ultricies, diam turpis eleifend nisl, a \ 347eleifend ante felis ac sapien. Integer bibendum. Suspendisse in mi non neque \ 348bibendum convallis. Suspendisse potenti. Sed sit amet purus at felis adipiscing \ 349aliquam. Vivamus et nisl sit amet mauris aliquet molestie. Integer tortor massa, \ 350aliquam a, lacinia nonummy, sagittis nec, eros.' 351 352#************************************************************************* 353 354def set_font_fixed(fontList): 355 """Find a matching font for the Table of Contents.""" 356 availableFonts = scribus.getFontNames() 357 found = 0 358 for f in fontList: 359 if found: 360 break 361 for i in availableFonts: 362 if not found: 363 if f == i: 364 return f 365 found = 1 366 break 367 if not found: 368 errorList = '' 369 for j in fontList: 370 errorList = errorList + j + '\n' 371 errorMessage ='No suitable fixed width font found.\nPlease install at least one of these fixed width fonts:\n'+errorList 372 print errorMessage 373 raise Exception(errorMessage) 374 375 376def set_font_proportional(fontList): 377 """Find a matching font for the page numbers and font names above samples.""" 378 availableFonts = scribus.getFontNames() 379 found = 0 380 for p in fontList: 381 if found: 382 break 383 for i in availableFonts: 384 if not found: 385 if p == i: 386 return p 387 found = 1 388 break 389 if not found: 390 errorList = '' 391 for j in fontList: 392 errorList = errorList + j + '\n' 393 errorMessage = 'No suitable proportional font found.\nPlease install at least one of these proportional fonts:\n'+errorList 394 print errorMessage 395 raise Exception(errorMessage) 396 397 398def save_user_conf(path): 399 """Save the data to the save file on the path specified by CONFIG_PATH. 400 401 Note initialisation unsets the CONFIG_PATH if it failed to verify or create""" 402 if not path == '': 403 try: 404 file = open(os.path.join(path,'fontsampler.conf'), 'w') 405 data = { 406 'a' : defaultPrefs, 407 'b' : userPrefs 408 } 409 cPickle.dump(data, file) 410 file.close() 411 except: 412 print 'failed to save data' 413 414 415def restore_user_conf(path): 416 """Restore the data from the save file on the path specified by CONFIG_PATH.""" 417 try: 418 file = open(os.path.join(path,'fontsampler.conf'), 'r') 419 data = cPickle.load(file) 420 file.close() 421 defaultPrefs.update(data['a']) 422 userPrefs.update(data['b']) 423 except: 424 userPrefs.update(defaultPrefs) 425 print 'failed to load saved data so using default values defined in the script' 426 427 428def set_page_geometry(dD, geometriesList, paperSize, wantBindingOffset): 429 """This is the experimental replacement paper size setting function. 430 431 Each paper size and other associated data are stored in a dictionary. 432 The dictionaries are stored in a list. We copy appropriate dictionary 433 and custom calculations into a work dictionary for use. 434 The advantage of this is its easier to add new paper definitions. 435 Returns a new dictionary, use .update to merge in new values into dD. 436 """ 437 try: 438 result={} 439 for i in geometriesList: 440 if i['paperName'] == paperSize: 441 dD.update(i) 442 443 result['paperLeftMarginOdd'] = dD['paperLeftMargin'] + \ 444 dD['paperBinding'] 445 result['paperRightMarginEven'] = dD['paperRightMargin'] + \ 446 dD['paperBinding'] 447 result['paperTextHeight'] = dD['paperHeight'] - \ 448 dD['paperTopMargin'] - \ 449 dD['paperBottomMargin'] 450 result['paperMargins'] = dD['paperLeftMargin'],dD['paperRightMargin'],dD['paperTopMargin'],dD['paperBottomMargin'] 451 452 # if we are adding a binding offset to the margins then we will have less width for our text... 453 if wantBindingOffset: 454 result['paperTextWidth'] = dD['paperWidth'] - \ 455 dD['paperLeftMargin'] - \ 456 dD['paperRightMargin'] - \ 457 dD['paperBinding'] - \ 458 2 459 else: 460 result['paperTextWidth'] = dD['paperWidth'] - \ 461 dD['paperLeftMargin'] - \ 462 dD['paperRightMargin'] - \ 463 2 464 return result 465 except: 466 errorMessage = 'set_page_geometry() failure: %s' % sys.exc_info()[1] 467 print errorMessage 468 469 470def set_odd_even(pageNum): 471 """ Sets the left margin position. 472 473 Checks the number passed to it and sets left margin accordingly. 474 Call once after each new page is created. 475 Returns 1 if even and 0 if odd page. 476 """ 477 if pageNum % 2 == 0: 478 isEvenPage = 1 # Even side 479 else: 480 isEvenPage = 0 # Odd side 481 482 if userPrefs['wantBindingOffset']: 483 if isEvenPage and userPrefs['wantDoubleSided']: # Even (when double sided) 484 dD['paperLeftSide'] = dD['paperLeftMargin'] + 1 485 else: # Odd side 486 dD['paperLeftSide'] = dD['paperLeftMarginOdd'] + 1 487 else: # No binding 488 dD['paperLeftSide'] = dD['paperLeftMargin'] + 1 489 return isEvenPage 490 491 492def draw_sample_row(font, fontSize, lineSpace, textString, x, y, w, h, getSizeOnly): 493 """Creates one row of samples or a header for the top of the block. 494 495 Called once by draw_sample_block() to create a block label then as many times 496 as required to create each actual sample found in the list of dictionaries 497 containing each samples definition. 498 """ 499 if not getSizeOnly: 500 f = scribus.createText(x, y, w, h) 501 scribus.insertText(textString, 0, f) 502 scribus.setFont(font, f) 503 scribus.setFontSize(fontSize, f) 504 scribus.setLineSpacing(lineSpace, f) 505 scribus.setTextAlignment(0, f) 506 return y + h + 1 507 508 509def draw_sample_block(fontName, x, y, w, getSizeOnly): 510 """Drawing of a complete sample block starts from here. 511 512 Iterates through each sample declared in the "samples" tuple. Places one 513 complete block using the font specified in fontname. 514 Note top line on page is drawn outside of this function. This ensures ease 515 of returning same height of every sample block. Line could have been drawn 516 at top inside this function and page finalised with line at bottom instead. 517 If getSizeOnly is true then returns the overall height of the entire text 518 block but without actually placing it. 519 """ 520 startPos = y 521 # Note there are 2 points of space before horizontal line at bottom of block. 522 # This 2 points will not appear at top of page so need to add it. 523 524 # set space below horizontal line to the top of the text block 525 y = y + 4 526 527 # (note there is one extra point inserted by addSampleRow() for each row generated)... 528 529 # first need a header... 530 y = draw_sample_row(dD['bookstylePropFont'], samplesHeader['fontSize'], samplesHeader['lineSpace'], fontName, x, y, w, samplesHeader['textHeight'], getSizeOnly) 531 532 if userPrefs['wantAlphabet']: 533 y = draw_sample_row(fontName, sampleAlphabet['fontSize'], sampleAlphabet['lineSpace'], sampleAlphabet['textString'], x, y, w, sampleAlphabet['textHeight'], getSizeOnly) 534 535 if userPrefs['want6Point']: 536 y = draw_sample_row(fontName, sample6Point['fontSize'], sample6Point['lineSpace'], sample6Point['textString'], x, y, w, sample6Point['textHeight'], getSizeOnly) 537 538 if userPrefs['want8Point']: 539 y = draw_sample_row(fontName, sample8Point['fontSize'], sample8Point['lineSpace'], sample8Point['textString'], x, y, w, sample8Point['textHeight'], getSizeOnly) 540 541 if userPrefs['want10Point']: 542 y = draw_sample_row(fontName, sample10Point['fontSize'], sample10Point['lineSpace'], sample10Point['textString'], x, y, w, sample10Point['textHeight'], getSizeOnly) 543 544 if userPrefs['want12Point']: 545 y = draw_sample_row(fontName, sample12Point['fontSize'], sample12Point['lineSpace'], sample12Point['textString'], x, y, w, sample12Point['textHeight'], getSizeOnly) 546 547 if userPrefs['want16Point']: 548 y = draw_sample_row(fontName, sample16Point['fontSize'], sample16Point['lineSpace'], sample16Point['textString'], x, y, w, sample16Point['textHeight'], getSizeOnly) 549 550 if userPrefs['want20Point']: 551 y = draw_sample_row(fontName, sample20Point['fontSize'], sample20Point['lineSpace'], sample20Point['textString'], x, y, w, sample20Point['textHeight'], getSizeOnly) 552 553 if userPrefs['want32Point']: 554 y = draw_sample_row(fontName, sample32Point['fontSize'], sample32Point['lineSpace'], sample32Point['textString'], x, y, w, sample32Point['textHeight'], getSizeOnly) 555 556 if userPrefs['wantParagraph']: 557 y = draw_sample_row(fontName, sampleParagraph['fontSize'], sampleParagraph['lineSpace'], sampleParagraphText, x, y, w, sampleParagraph['textHeight'], getSizeOnly) 558 559 y = y + 1 # one extra point of space above bottom Horiz. line 560 561 lineHeight = draw_horiz_line(y, x, w + x, getSizeOnly) 562 y = y + lineHeight 563 564 return y - startPos 565 566 567def insert_toc_row(fontName, pageNum, yPos, frame): 568 """Called once for each content line to be drawn in the text frame.""" 569 dotLine = "" 570 dotQuant = dD['tocCharsInRow'] - len(fontName) - len(str(pageNum)) + 1 571 for i in range(dotQuant): 572 dotLine = dotLine + '.' 573 oneLine = fontName + dotLine + str(pageNum) + "\n" 574 scribus.insertText(oneLine, yPos, frame) 575 yPos = yPos + len(oneLine) + 0 576 return yPos 577 578 579def build_toc_page_template(): 580 """Inserts empty toc template into the currently selected page.""" 581 # first put a header on the empty page... 582 textstring = dD['tocHeaderTitle'] 583 yPos = dD['paperTopMargin'] + 1 584 header = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], 35) 585 scribus.insertText(textstring, 0, header) 586 scribus.setFont(dD['bookstylePropFont'], header) 587 scribus.setFontSize(24, header) 588 scribus.setTextAlignment(1, header) 589 # now create a text frame for the table of contents... 590 yPos = yPos + 36 591 body = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], dD['paperHeight'] - yPos - dD['paperBottomMargin'] - 1) 592 scribus.setFont(dD['bookstyleFixedFont'], body) 593 scribus.setFontSize(10, body) 594 scribus.setLineSpacing(12, body) 595 return body 596 597 598def build_toc(tocList): 599 """Creates all the Table of Contents pages. 600 601 Calls tocPageFramesBuild() to write the header and empty frame for the 602 toc rows each time a new page is added. 603 Then calls tocRowAdd() to add each line to the toc frame. Creates new page 604 each time it completes last row on page. 605 """ 606 rowCount = 0 607 yPos = 0 608 tocPageNum = 1 609 tocPageCount = 1 610 611 scribus.newPage(tocPageNum) 612 isEvenPage = set_odd_even(tocPageNum) 613 body = build_toc_page_template() # create frames for new empty page 614 if isEvenPage == 0: 615 scribus.setTextAlignment(2, body) 616 else: 617 scribus.setTextAlignment(0, body) 618 for i in tocList: 619 if rowCount == dD['tocRowsPerPage']: # Need to build a new TOC page (count is from zero, not one) 620 tocPageNum = tocPageNum + 1 621 scribus.newPage(tocPageNum) 622 isEvenPage = set_odd_even(tocPageNum) 623 body = build_toc_page_template() 624 if not isEvenPage: 625 scribus.setTextAlignment(2, body) 626 else: 627 scribus.setTextAlignment(0, body) 628 rowCount = 0 629 yPos = 0 630 tocPageCount = tocPageCount + 1 631 yPos = insert_toc_row(i[0], i[1], yPos, body) 632 rowCount = rowCount + 1 633 if userPrefs['wantDoubleSided']: 634 if tocPageCount % 2 != 0: # Odd page 635 tocPageNum = tocPageNum + 1 636 scribus.newPage(tocPageNum) # Add an extra page if odd number 637 638 639def add_page_num(pageNum): 640 yPos = dD['paperHeight'] - \ 641 dD['paperBottomMargin'] - \ 642 dD['paperPageNumVertOffset'] 643 footer = scribus.createText(dD['paperLeftSide'], yPos, dD['paperTextWidth'], 15) 644 scribus.insertText('%s' % pageNum, 0, footer) 645 scribus.setFont(dD['bookstylePropFont'], footer) 646 scribus.setFontSize(9, footer) 647 scribus.setTextAlignment(1, footer) 648 scribus.setLineSpacing(10, footer) 649 650 651def create_empty_samplepage(pageNum, getSizeOnly): 652 """Creates a new page and increments page number by one. 653 654 Note getSizeOnly is now evaluated. Will still generate page number increment 655 but will not actually create the new page or place the number on the page.""" 656 if not getSizeOnly: 657 scribus.newPage(-1) 658 pageNum = pageNum + 1 659 set_odd_even(pageNum) 660 if not getSizeOnly: 661 if userPrefs['wantPageNumbers']: 662 add_page_num(pageNum) 663 return pageNum 664 665 666def draw_horiz_line(yPos, xStart, xEnd, getSizeOnly): 667 """Draws a line and returns the height. 668 669 If getSizeOnly is set then returns the height it would have 670 used but without actually creating a line. 671 """ 672 lineWidth = 1 673 if not getSizeOnly: 674 newLine = scribus.createLine(xStart, yPos, xEnd, yPos) 675 scribus.setLineWidth(lineWidth, newLine) 676 return lineWidth 677 678 679def draw_selection(fontList, getSizeOnly): 680 """Draws the sample blocks onto the Scribus canvas. 681 682 Measure one font sample block including any horizontal lines and extra 683 vertical spaces. 684 Get the amount of vertical space available for the text area between the 685 top line and top of page number area. 686 Use these two values to calculate how many complete sample blocks will fit 687 in the space available. This is the "pageBlocks" 688 Note we always draw the top horizontal line before placing the blocks. This 689 is taken into account when calculating the available text area. 690 Next, if "getSizeOnly" is false we create a page then create the sample 691 blocks while incrementing a counter until it matches the "pageBlocks". 692 Reset the counter and create new page. We keep going until we have processed 693 all the fonts in the selection list. 694 We update the Scribus progress bar as we create each font sample block. 695 The returned result is used to update some values in the status bar. 696 """ 697 progress = 1 698 scribus.progressReset() 699 scribus.progressTotal(len(fontList)) 700 tocList = [] 701 pageNum = 1 702 blockCounter = 0 703 counter = 0 704 facingPages = scribus.NOFACINGPAGES 705 706 # Just get blocks per page value... 707 set_odd_even(pageNum) 708 lineHeight = 1 # include the one point of space below top margin 709 lineHeight = lineHeight + draw_horiz_line(0, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], 1) 710 usuableArea = dD['paperHeight'] - \ 711 dD['paperTopMargin'] - \ 712 lineHeight - \ 713 dD['paperBottomMargin'] - \ 714 dD['paperPageNumVertOffset'] 715 716 blockHeight = draw_sample_block(fontList[0], dD['paperLeftSide'], 0, dD['paperTextWidth'], 1) 717 pageBlocks = int(usuableArea / blockHeight) 718 #print blockHeight 719 #print "Usuable area %s points high" % usuableArea 720 #print "Used space on page is %s points high" % (blockHeight * pageBlocks) 721 722 if not getSizeOnly: 723 # not a dummy run so start by setting up page numbering... 724 if userPrefs['wantPageOneOnFirst'] and userPrefs['wantTOC']: 725 tocPageCount = divmod(len(fontList), dD['tocRowsPerPage']) 726 pageNum = pageNum + tocPageCount[0] 727 if tocPageCount[1] != 0: 728 # (adding more to page number as not whole number) 729 pageNum = pageNum + 1 730 if userPrefs['wantDoubleSided']: 731 oddEvenTest = divmod(pageNum, 2) 732 if oddEvenTest[1] == 0: 733 # (adding extra one to start number as odd amount) 734 pageNum = pageNum + 1 735 if userPrefs['wantDoubleSided']: 736 facingPages = scribus.FACINGPAGES 737 # now create a new document with empty page and start building... 738 scribus.newDocument(dD['paperSize'], dD['paperMargins'], scribus.PORTRAIT, 1, scribus.UNIT_POINTS, facingPages, scribus.FIRSTPAGERIGHT, 1) 739 scribus.zoomDocument(-100) 740 # A new doc gives us a new page by default so set it up first... 741 set_odd_even(pageNum) 742 yPos = dD['paperTopMargin'] + 1 743 lineHeight = draw_horiz_line(yPos, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], getSizeOnly) 744 yPos = yPos + lineHeight 745 if userPrefs['wantPageNumbers']: 746 add_page_num(pageNum) 747 for i in fontList: 748 # Now place the actual sample block but create a new page if needed... 749 if counter == pageBlocks: 750 pageNum = create_empty_samplepage(pageNum, getSizeOnly) 751 yPos = dD['paperTopMargin'] + 1 752 lineHeight = draw_horiz_line(yPos, dD['paperLeftSide'], dD['paperLeftSide'] + dD['paperTextWidth'], getSizeOnly) 753 yPos = yPos + lineHeight 754 counter = 0 755 blockHeight = draw_sample_block(i, dD['paperLeftSide'], yPos, dD['paperTextWidth'], getSizeOnly) 756 yPos = yPos + blockHeight 757 # and also increment the Scribus progress bar... 758 scribus.progressSet(progress) 759 progress = progress + 1 760 # Add current font to TOC... 761 tocList.append([i, pageNum]) 762 counter = counter + 1 763 if userPrefs['wantTOC']: 764 # Insert table of contents - (before page numbering)... 765 build_toc(tocList) 766 scribus.gotoPage(1) 767 return pageBlocks 768 769 770def preview_font(app, fontName): 771 """Gets the named font and puts a sample in the preview panel. 772 773 Pick up the temp sample qpixmap file and display it in a canvas object 774 The temp file is put in the users ".scribus" folder and cleaned up on exit. 775 We create samplePic as a global as a workaround because the reference count 776 does not increase when we add the image to the canvas. Therefore python 777 garbage collection removes our image before we have even displayed it. 778 Note app.previewPanel is the actual canvas. 779 """ 780 global gSamplePic 781 global gPreviewId 782 scribus.renderFont(fontName, os.path.join(TEMP_PATH,'temp079r.bmp'),dD['previewpanelSampleText'],dD['previewpanelFontHeight']) 783 try: 784 tempPic = Image.open(os.path.join(TEMP_PATH,'temp079r.bmp')) 785 tempPic.save(os.path.join(TEMP_PATH,'temp079r.jpeg'),format='JPEG') 786 tempImage = Image.open(os.path.join(TEMP_PATH,'temp079r.jpeg')) 787 imgDimen = tempPic.getbbox() 788 gSamplePic = ImageTk.PhotoImage(tempImage) 789 # To center the image use "Half display height minus half the image height" 790 # preview panel is allegedly 56 (60 less a 2 pixel border top and bottom) 791 # need to be lower than that to look correct visually... 792 topEdge = (32 - (imgDimen[3] / 2)) 793 gPreviewId = app.previewPanel.create_image(5, topEdge, anchor=NW, image=gSamplePic) 794 os.remove(os.path.join(TEMP_PATH,'temp079r.bmp')) 795 os.remove(os.path.join(TEMP_PATH,'temp079r.jpeg')) 796 except IOError: 797 gSamplePic = None 798 gPreviewId = app.previewPanel.create_image(0, 0, anchor=NW, image=gSamplePic) 799 return 800 801 802class AboutDialog(Toplevel): 803 804 def __init__(self, parent): 805 Toplevel.__init__(self, parent) 806 self.transient(parent) 807 self.title('About') 808 self.parent = parent 809 self.result = None 810 self.resizable(0, 0) 811 812 infoLabel = Label(self, text=WINDOW_TITLE+'\nSupport page at %s' % SUPPORT_PAGE) 813 infoLabel.pack(padx=5, pady=5) 814 # now the frame for contents... 815 contentFrame = Frame(self) 816 self.btnOk = Button(contentFrame, text='OK', command=self.ok, default=ACTIVE) 817 self.btnOk.pack(side=LEFT, padx=5, pady=5) 818 contentFrame.pack() 819 self.bind('<Return>', self.ok) 820 self.grab_set() 821 self.protocol('WM_DELETE_WINDOW', self.ok) 822 self.initial_focus = self.btnOk 823 self.wait_window(self) 824 825 def ok(self, event=None): 826 self.withdraw() 827 self.update_idletasks() 828 self.parent.focus_set() 829 self.destroy() 830 831 832class ConfigurationDialog(Toplevel): 833 834 def __init__(self, parent): 835 Toplevel.__init__(self, parent) 836 self.transient(parent) 837 self.title('Configuration') 838 self.parent = parent 839 self.result = None 840 self.resizable(0, 0) 841 842 # Create outer frame... 843 self.topFrame = Frame(self, bd=1, relief=FLAT) 844 self.topFrame.grid(row=0, column=0, padx=5, pady=5) 845 846 self.paperSizeLabel = Label(self.topFrame, text='Sample Rows:') 847 self.paperSizeLabel.grid(row=0, column=0, sticky=W) 848 849 # This frame holds each sample selector... 850 self.sampleSelectFrame = Frame(self.topFrame, bd=1, relief=RIDGE) 851 self.sampleSelectFrame.grid(row=1, column=0, padx=0, pady=2) 852 853 # now create the sample selector widgets for the frame... 854 self.__wantAlphabet = IntVar() 855 self.btnWantAlphabet = Checkbutton(self.sampleSelectFrame, text='want alphabet row', variable=self.__wantAlphabet, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 856 self.btnWantAlphabet.grid(row=0, column=0, padx=10, pady=0, sticky=W) 857 if userPrefs['wantAlphabet']: 858 self.btnWantAlphabet.select() 859 860 self.__want6Point = IntVar() 861 self.btnWant6Point = Checkbutton(self.sampleSelectFrame, text='want 6 point row', variable=self.__want6Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 862 self.btnWant6Point.grid(row=1, column=0, padx=10, pady=0, sticky=W) 863 if userPrefs['want6Point']: 864 self.btnWant6Point.select() 865 866 self.__want8Point = IntVar() 867 self.btnWant8Point = Checkbutton(self.sampleSelectFrame, text='want 8 point row', variable=self.__want8Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 868 self.btnWant8Point.grid(row=2, column=0, padx=10, pady=0, sticky=W) 869 if userPrefs['want8Point']: 870 self.btnWant8Point.select() 871 872 self.__want10Point = IntVar() 873 self.btnWant10Point = Checkbutton(self.sampleSelectFrame, text='want 10 point row', variable=self.__want10Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 874 self.btnWant10Point.grid(row=3, column=0, padx=10, pady=0, sticky=W) 875 if userPrefs['want10Point']: 876 self.btnWant10Point.select() 877 878 self.__want12Point = IntVar() 879 self.btnWant12Point = Checkbutton(self.sampleSelectFrame, text='want 12 point row', variable=self.__want12Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 880 self.btnWant12Point.grid(row=4, column=0, padx=10, pady=0, sticky=W) 881 if userPrefs['want12Point']: 882 self.btnWant12Point.select() 883 884 self.__want16Point = IntVar() 885 self.btnWant16Point = Checkbutton(self.sampleSelectFrame, text='want 16 point row', variable=self.__want16Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 886 self.btnWant16Point.grid(row=5, column=0, padx=10, pady=0, sticky=W) 887 if userPrefs['want16Point']: 888 self.btnWant16Point.select() 889 890 self.__want20Point = IntVar() 891 self.btnWant20Point = Checkbutton(self.sampleSelectFrame, text='want 20 point row', variable=self.__want20Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 892 self.btnWant20Point.grid(row=6, column=0, padx=10, pady=0, sticky=W) 893 if userPrefs['want20Point']: 894 self.btnWant20Point.select() 895 896 self.__want32Point = IntVar() 897 self.btnWant32Point = Checkbutton(self.sampleSelectFrame, text='want 32 point row', variable=self.__want32Point, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 898 self.btnWant32Point.grid(row=7, column=0, padx=10, pady=0, sticky=W) 899 if userPrefs['want32Point']: 900 self.btnWant32Point.select() 901 902 self.__wantParagraph = IntVar() 903 self.btnParagraphSelect = Checkbutton(self.sampleSelectFrame, text='want sample paragraph', variable=self.__wantParagraph, offvalue=0, onvalue=1, command=self.__sampleSelectionClick) 904 self.btnParagraphSelect.grid(row=8, column=0, padx=10, pady=0, sticky=W) 905 if userPrefs['wantParagraph']: 906 self.btnParagraphSelect.select() 907 908 self.paperSizeLabel = Label(self.topFrame, text='Paper Sizes:') 909 self.paperSizeLabel.grid(row=2, column=0, sticky=W) 910 911 self.paperSizeFrame = Frame(self.topFrame, bd=1, relief=RIDGE) 912 self.paperSizeFrame.grid(row=3, column=0, padx=0, pady=2, sticky=W) 913 914 self.__paper = StringVar() 915 self.a4papersizeSelect = Radiobutton(self.paperSizeFrame, text='A4', variable=self.__paper, value='A4', command=self.__paperSelectionClick) 916 self.a4papersizeSelect.grid(row=1, column=0, padx=10, sticky=W) 917 self.uspapersizeSelect = Radiobutton(self.paperSizeFrame, text='US Letter', variable=self.__paper, value='US Letter', command=self.__paperSelectionClick) 918 self.uspapersizeSelect.grid(row=2, column=0, padx=10, sticky=W) 919 920 # set to match prefs... 921 if userPrefs['paperSize'] == 'US Letter': 922 self.uspapersizeSelect.select() 923 if userPrefs['paperSize'] == 'A4': 924 self.a4papersizeSelect.select() 925 926 self.btnFrame = Frame(self.topFrame) 927 self.btnFrame.grid(row=4, column=0, padx=10, pady=2) 928 self.btnOk = Button(self.btnFrame, text='OK', command=self.ok) 929 self.btnOk.grid(row=2, column=0, pady=5) 930 self.bind('<Return>', self.ok) 931 self.grab_set() 932 self.initial_focus = self.btnOk 933 self.wait_window(self) 934 935 936 def __sampleSelectionClick(self): 937 """Get and store all the selections. 938 939 Just assigns the lot at once. Not worth being picky and only 940 assigning values that have changed since last time. 941 """ 942 userPrefs['wantAlphabet'] = self.__wantAlphabet.get() 943 userPrefs['want6Point'] = self.__want6Point.get() 944 userPrefs['want8Point'] = self.__want8Point.get() 945 userPrefs['want10Point'] = self.__want10Point.get() 946 userPrefs['want12Point'] = self.__want12Point.get() 947 userPrefs['want16Point'] = self.__want16Point.get() 948 userPrefs['want20Point'] = self.__want20Point.get() 949 userPrefs['want32Point'] = self.__want32Point.get() 950 userPrefs['wantParagraph'] = self.__wantParagraph.get() 951 self.parent.statusbarUpdate() 952 953 def __paperSelectionClick(self): 954 userPrefs['paperSize'] = self.__paper.get() 955 self.parent.statusbarUpdate() 956 957 def ok(self, event=None): 958 dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset'])) 959 self.withdraw() 960 self.update_idletasks() 961 self.parent.focus_set() 962 self.destroy() 963 964 965class Application(Frame): 966 967 def __init__(self, master = None): 968 Frame.__init__(self, master) 969 970 self.grid() 971 972 # Remove maximise button and resize. Not good to allow resizable window 973 # because the listboxes are fixed width... 974 self.master.resizable(0, 0) 975 976 # build the menu... 977 menubar = Menu(self) 978 settingsmenu = Menu(menubar, tearoff=0) 979 settingsmenu.add_command(label='Configuration', command=self.__configurationDlgShow) 980 settingsmenu.add_separator() 981 settingsmenu.add_command(label='Save current settings', command=self.__saveCurrentSettingsAsDefaults) 982 settingsmenu.add_command(label='Load saved settings', command=self.__restoreCurrentSettingsFromDefault) 983 984 menubar.add_cascade(label='Settings', menu=settingsmenu) 985 helpmenu = Menu(menubar, tearoff=0) 986 helpmenu.add_command(label='About', command=self.__aboutDlgShow) 987 menubar.add_cascade(label='Help', menu=helpmenu) 988 # display menu... 989 self.master.config(menu=menubar) 990 991 # now start adding our widgets starting with the top frame... 992 self.listbox_frame = Frame(self) 993 self.listbox_frame.grid(row=0, column=0, sticky=EW) 994 995 # left hand listbox assembly 996 self.leftListbox_frame = Frame(self.listbox_frame, borderwidth=1, relief=SUNKEN) 997 self.leftListbox_frame.grid(row=1, column=0) 998 999 self.leftLabel = Label(self.listbox_frame, text='Available Fonts') 1000 self.leftLabel.grid(row=0, column=0, sticky=NS) 1001 1002 self.yScroll1 = Scrollbar(self.leftListbox_frame, orient=VERTICAL) 1003 self.yScroll1.grid(row=0, column=1, sticky=NS) 1004 self.xScroll1 = Scrollbar(self.leftListbox_frame, orient=HORIZONTAL) 1005 self.xScroll1.grid(row=1, column=0, sticky=EW) 1006 1007 self.listbox1 = Listbox(self.leftListbox_frame, 1008 xscrollcommand=self.xScroll1.set, 1009 yscrollcommand=self.yScroll1.set, 1010 selectmode=EXTENDED, 1011 height=20, width=40) 1012 self.listbox1.grid(row=0, column=0, sticky=NSEW) 1013 self.xScroll1['command'] = self.listbox1.xview 1014 self.yScroll1['command'] = self.listbox1.yview 1015 1016 def __listbox1KeyRelease(event): 1017 """Check if an Up or Down key has been pressed and released and 1018 if so the preview panel is refreshed. If the keys are held down 1019 the file system slows the scroll. Need a timer here to delay 1020 updates.""" 1021 if (event.keysym == 'Down' or event.keysym == 'Up'): 1022 __listbox1DoLogicCallback(self) 1023 1024 def __listbox1SingleClick(event): 1025 """Call this first when listbox1 is clicked with mouse to put focus 1026 into the listbox. Note we call when mouse click is released, not pressed, 1027 due to the fact that the listbox does not change the selection until the button 1028 is released.""" 1029 self.listbox1.focus_set() 1030 __listbox1DoLogicCallback(self) 1031 self.listbox1.bind('<ButtonRelease-1>', __listbox1SingleClick) 1032 1033 def __listbox1DoLogicCallback(event): 1034 """Decides if current selection should be previewed. 1035 1036 Start by counting items in selection list and if equal to one then 1037 show selected font, ignoring if more or less than one. Then also 1038 set up buttons logic depending on selection. We bind the FocusIn 1039 to this too so button logic and preview gets updated when focus 1040 enters the listbox. 1041 """ 1042 # note we are not making use of "self.listbox1.get(ACTIVE)" due to 1043 # it not getting the real active name. Always one selection behind 1044 # even though we are doing all this in the ButtonRelease event. 1045 # Have made a change here. If more than one font name is selected 1046 # then we just empty the preview. 1047 names = self.listbox1.curselection() 1048 if len(names) == 1: 1049 selectedFont = self.listbox1.get(names[0]) 1050 self.__curSelectedItem(selectedFont) 1051 else: 1052 try: 1053 app.previewPanel.delete(previewId) 1054 except: 1055 pass 1056 #else: 1057 #selectedFont = self.listbox1.get(ACTIVE) 1058 #print selectedFont # for testing 1059 #if selectedFont != "": 1060 #self.__curSelectedItem(selectedFont) 1061 1062 # Now do the button logic... 1063 self.listbox2.selection_clear(0,END) 1064 self.__setUpDownActive(0, 0) # Force a disable if in other box 1065 if self.listbox1.size() > 0: 1066 self.__setSelButtonsActive(0, 1) 1067 else: 1068 self.__setSelButtonsActive(0, 0) 1069 1070 self.listbox1.bind('<FocusIn>', __listbox1DoLogicCallback) 1071 self.listbox1.bind('<Any-KeyRelease>', __listbox1KeyRelease) 1072 1073 def __listbox1DoubleClickCallback(event): 1074 """The single click event will fire also when left listbox 1075 is double clicked but we are detecting the single click button up event.""" 1076 self.__listSelectionToRight() 1077 1078 self.listbox1.bind('<Double-Button-1>', __listbox1DoubleClickCallback) 1079 1080 # middle button frame assembly 1081 self.midbutton_frame = Frame(self.listbox_frame) 1082 self.midbutton_frame.grid(row=0, rowspan=2, column=1, sticky=NSEW) 1083 1084 self.rsingleButton = Button(self.midbutton_frame, state='disabled', text='>', command=self.__rsingleButtonClick) 1085 self.rsingleButton.grid(row=0, column=0, padx=5, pady=5, sticky=EW) 1086 self.rdoubleButton = Button(self.midbutton_frame, text='>>', command=self.__rdoubleButtonClick) 1087 self.rdoubleButton.grid(row=1, column=0, padx=5, pady=5, sticky=EW) 1088 1089 self.itemupButton = Button(self.midbutton_frame, state='disabled', text='Up', command=self.__itemupButtonClick) 1090 self.itemupButton.grid(row=2, column=0, padx=5, pady=5, sticky=EW) 1091 self.itemdownButton = Button(self.midbutton_frame, state='disabled', text='Down', command=self.__itemdownButtonClick) 1092 self.itemdownButton.grid(row=3, column=0, padx=5, pady=5, sticky=EW) 1093 1094 self.lsingleButton = Button(self.midbutton_frame, state='disabled', text='<', command=self.__lsingleButtonClick) 1095 self.lsingleButton.grid(row=4, column=0, padx=5, pady=5, sticky=EW) 1096 self.ldoubleButton = Button(self.midbutton_frame, state='disabled', text='<<', command=self.__ldoubleButtonClick) 1097 self.ldoubleButton.grid(row=5, column=0, padx=5, pady=5, sticky=EW) 1098 1099 # Right hand listbox assembly 1100 self.rightListbox_frame = Frame(self.listbox_frame, borderwidth=1, relief=SUNKEN) 1101 self.rightListbox_frame.grid(row=1, column=2) 1102 1103 self.rightLabel = Label(self.listbox_frame, text='Selected Fonts') 1104 self.rightLabel.grid(row=0, column=2, sticky=NS) 1105 1106 self.yScroll2 = Scrollbar(self.rightListbox_frame, orient=VERTICAL) 1107 self.yScroll2.grid(row=0, column=1, sticky=NS) 1108 self.xScroll2 = Scrollbar(self.rightListbox_frame, orient=HORIZONTAL) 1109 self.xScroll2.grid(row=1, column=0, sticky=EW) 1110 1111 self.listbox2 = Listbox(self.rightListbox_frame, 1112 xscrollcommand=self.xScroll2.set, 1113 yscrollcommand=self.yScroll2.set, 1114 selectmode=EXTENDED, 1115 height=20, width=40) 1116 self.listbox2.grid(row=0, column=0, sticky=NSEW) 1117 self.xScroll2['command'] = self.listbox2.xview 1118 self.yScroll2['command'] = self.listbox2.yview 1119 1120 def __listbox2SingleClick(event): 1121 """Similar to __listbox1SingleClick().""" 1122 self.listbox2.focus_set() 1123 __listbox2DoLogicCallback(self) 1124 self.listbox2.bind('<ButtonRelease-1>', __listbox2SingleClick) 1125 1126 def __listbox2KeyRelease(event): 1127 if (event.keysym == 'Down' or event.keysym == 'Up'): 1128 __listbox2DoLogicCallback(self) 1129 1130 def __listbox2DoLogicCallback(event): 1131 """Similar to __listbox1DoLogicCallback().""" 1132 names = self.listbox2.curselection() 1133 if len(names) == 1: 1134 selectedFont = self.listbox2.get(names[0]) 1135 self.__curSelectedItem(selectedFont) 1136 else: 1137 try: 1138 app.previewPanel.delete(previewId) 1139 except: 1140 pass 1141 1142 # Now do the button logic... 1143 self.listbox1.selection_clear(0,END) 1144 self.__testUpDownState() 1145 if self.listbox2.size() > 0: 1146 self.__setSelButtonsActive(1, 0) 1147 else: 1148 self.__setSelButtonsActive(0, 0) 1149 self.listbox2.bind('<FocusIn>', __listbox2DoLogicCallback) 1150 self.listbox2.bind('<Any-KeyRelease>', __listbox2KeyRelease) 1151 1152 def __listbox2DoubleClickCallback(event): 1153 """Similar to __listbox1DoubleClickCallback().""" 1154 self.__listSelectionToLeft() 1155 self.listbox2.bind('<Double-Button-1>', __listbox2DoubleClickCallback) 1156 1157 # now draw the bottom font preview frame if required... 1158 if showPreviewPanel: 1159 self.preview_frame = Frame(self) 1160 self.preview_frame.grid(row=1, column=0, sticky=EW) 1161 self.previewPanel = Canvas(self.preview_frame, height=60, bg='white', bd=2, relief=SUNKEN) 1162 self.previewPanel.pack(fill=X) 1163 1164 # now draw the bottom controls frame... 1165 self.controls_frame = Frame(self) 1166 self.controls_frame.grid(row=2, column=0, sticky=EW) 1167 1168 # create a container... 1169 self.button_frame1 = Frame(self.controls_frame, bd=1, relief=RIDGE) 1170 self.button_frame1.grid(row=0, column=0, padx=10, pady=2) 1171 # create and add page number selection button... 1172 self.__wantPageNum = IntVar() 1173 self.pagenumSelect = Checkbutton(self.button_frame1, text='Print page numbers', variable=self.__wantPageNum, offvalue=0, onvalue=1, command=self.__pageNumberSelectButtonClick) 1174 self.pagenumSelect.grid(row=0, column=0, padx=0, sticky=W) 1175 1176 # create a container... 1177 self.button_frame2 = Frame(self.controls_frame, bd=1, relief=RIDGE) 1178 self.button_frame2.grid(row=0, column=1, padx=10, pady=2) 1179 # create and add the TOC selector... 1180 self.__wantToc = IntVar() 1181 self.tocSelect = Checkbutton(self.button_frame2, text='Print table of contents', variable=self.__wantToc, offvalue=0, onvalue=1, command=self.__tocSelectButtonClick) 1182 self.tocSelect.grid(row=0, column=0, padx=0, sticky=W) 1183 # create and add page one on first selector... 1184 self.__wantPageOneOnFirst = IntVar() 1185 self.btnPageOneOnFirst = Checkbutton(self.button_frame2, text='Page count includes TOC', variable=self.__wantPageOneOnFirst, offvalue=0, onvalue=1, command=self.__wantPageOneOnFirstClick) 1186 self.btnPageOneOnFirst.grid(row=1, column=0, padx=0, sticky=W) 1187 1188 # create a container... 1189 self.button_frame3 = Frame(self.controls_frame, bd=1, relief=RIDGE) 1190 self.button_frame3.grid(row=0, column=2, padx=10, pady=2) 1191 # create and add the binding offset... 1192 self.__wantBindingOffset = IntVar() 1193 self.bindingoffsetSelect = Checkbutton(self.button_frame3, text='Extra offset for binding', variable=self.__wantBindingOffset, offvalue=0, onvalue=1, command=self.__bindingoffsetSelectButtonClick) 1194 self.bindingoffsetSelect.grid(row=0, column=0, sticky=W) 1195 # create and add the double sided selection buttons... 1196 self.__wantDoubleSided = IntVar() 1197 self.doublesidedSelect = Checkbutton(self.button_frame3, text='Double sided pages', variable=self.__wantDoubleSided, offvalue=0, onvalue=1, command=self.__doubleSidedSelectButtonClick) 1198 self.doublesidedSelect.grid(row=1, column=0, rowspan=2, sticky=W) 1199 1200 # now the ok and cancel buttons... 1201 self.cancelButton = Button(self.controls_frame, text='Cancel', command=self.__cancelButtonClick) 1202 self.cancelButton.grid(row=0, column=3, padx=5) 1203 self.okButton = Button(self.controls_frame, text='OK', state='disabled', command=self.__okButtonClick) 1204 self.okButton.grid(row=0, column=4, padx=5) 1205 1206 # now create the bottom status bar frame and contents... 1207 self.status_frame = Frame(self) 1208 self.status_frame.grid(row=3, column=0, sticky=E+W) 1209 self.status0 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) 1210 self.status0.pack(side=LEFT) 1211 self.status1 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) 1212 self.status1.pack(side=LEFT) 1213 self.status2 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) 1214 self.status2.pack(side=LEFT) 1215 self.status3 = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) 1216 self.status3.pack(side=LEFT) 1217 self.statusPaperSize = Label(self.status_frame, bd=1, relief=SUNKEN, anchor=W) 1218 self.statusPaperSize.pack(fill=X) 1219 1220 def statusbarUpdate(self): 1221 """Draws the status bar contents. 1222 1223 Note "draw_selection()" does a dummy run to count the amount of sample 1224 blocks on a sheet. 1225 TODO: Statusbar setting and recalculation should be separated. Just recalc 1226 and refresh panels as required instead of all of them each time. 1227 """ 1228 available = self.listbox1.size() 1229 selected = self.listbox2.size() 1230 size = FloatType(selected) 1231 blocksPerSheet = draw_selection(scribus.getFontNames(), 1) 1232 value = size / blocksPerSheet 1233 pages = IntType(value) # Get whole part of number 1234 value = value - pages # Remove whole number part 1235 if value > 0: # Test remainder 1236 pages = pages + 1 # Had remainder so add a page 1237 self.status0['text'] = 'Fonts available: %s ' % (available + selected) 1238 self.status1['text'] = 'Fonts selected: %s ' % selected 1239 self.status2['text'] = 'Sheets required: %s ' % pages 1240 self.status3['text'] = 'Fonts per sheet: %s ' % blocksPerSheet 1241 self.statusPaperSize['text'] = 'Paper size: %s ' % userPrefs['paperSize'] 1242 1243 def __listSelectionToRight(self): 1244 toMoveRight = ListType(self.listbox1.curselection()) 1245 self.listbox1.selection_clear(0,END) 1246 toMoveRight.reverse() # reverse list so we delete from bottom of listbox first 1247 tempList = [] 1248 for i in toMoveRight: 1249 tempList.insert(0,self.listbox1.get(i)) # gets the actual strings (reverse again) 1250 self.listbox1.delete(i) 1251 for j in tempList: 1252 self.listbox2.insert(END, j) 1253 self.__setButtonsState() 1254 self.__setSelButtonsActive(0, 0) 1255 self.statusbarUpdate() 1256 1257 def __listSelectionToLeft(self): 1258 toMoveLeft = ListType(self.listbox2.curselection()) 1259 toMoveLeft.reverse() 1260 self.listbox2.selection_clear(0,END) 1261 for i in toMoveLeft: 1262 self.listbox1.insert(END, self.listbox2.get(i)) # Insert it at the end 1263 self.listbox2.delete(i) 1264 fontList = ListType(self.listbox1.get(0, END)) # Copy contents to a list type 1265 self.listbox1.delete(0, END) # Remove all contents 1266 fontList.sort() # Use sort method of list 1267 for j in fontList: 1268 self.listbox1.insert(END, j) # Replace with sorted version 1269 self.__setButtonsState() 1270 self.__setSelButtonsActive(0, 0) 1271 self.statusbarUpdate() 1272 1273 def __listAllToRight(self): 1274 fontList = self.listbox1.get(0, END) # Get each font name into a list 1275 for i in fontList: 1276 self.listbox2.insert(END, i) # Copy each one 1277 self.listbox1.delete(0, END) # All done so empty the left listbox 1278 self.__setButtonsState() 1279 self.__setSelButtonsActive(0, 0) 1280 self.statusbarUpdate() 1281 1282 def __listAllToLeft(self): 1283 """Moves all selected fonts back to the left hand pane. 1284 1285 Note we just clear both panes then reload the left listbox in correct 1286 order from scratch as this is probably quicker than moving each 1287 item individually. 1288 """ 1289 self.listbox1.delete(0, END) 1290 fontList = scribus.getFontNames() 1291 fontList.sort() 1292 for i in fontList: 1293 self.listbox1.insert(END, i) 1294 self.listbox2.delete(0, END) 1295 self.__setButtonsState() 1296 self.__setSelButtonsActive(0, 0) 1297 self.statusbarUpdate() 1298 1299 def __setSelButtonsActive(self, selToRight, selToLeft): 1300 # The "selection" buttons are the ones with ">" and "<" on them 1301 if selToRight == 1: 1302 self.lsingleButton['state'] = NORMAL 1303 else: 1304 self.lsingleButton['state'] = DISABLED 1305 if selToLeft == 1: 1306 self.rsingleButton['state'] = NORMAL 1307 else: 1308 self.rsingleButton['state'] = DISABLED 1309 1310 def __setAllButtonsActive(self, allToRight, allToLeft): 1311 # The "all" buttons are the ones with ">>" and "<<" on them 1312 if allToRight == 1: 1313 self.rdoubleButton['state'] = NORMAL 1314 else: 1315 self.rdoubleButton['state'] = DISABLED 1316 if allToLeft == 1: 1317 self.ldoubleButton['state'] = NORMAL 1318 else: 1319 self.ldoubleButton['state'] = DISABLED 1320 1321 def __setButtonsState(self): 1322 if self.listbox2.size() > 0 and self.listbox1.size() > 0: 1323 self.__setAllButtonsActive(1, 1) 1324 self.okButton['state'] = NORMAL 1325 elif self.listbox2.size() == 0: 1326 self.__setAllButtonsActive(1, 0) 1327 self.okButton['state'] = DISABLED 1328 elif self.listbox1.size() == 0: 1329 self.__setAllButtonsActive(0, 1) 1330 self.okButton['state'] = NORMAL 1331 1332 def __itemUp(self): 1333 """Test if one item is selected then move it up one position.""" 1334 selection = self.listbox2.curselection() 1335 if len(selection) == 1: 1336 indexId = IntType(selection[0]) # Get the first (only) item as integer type 1337 if indexId > 0: 1338 fontString = self.listbox2.get(indexId) 1339 self.listbox2.delete(indexId) 1340 newPos = indexId - 1 1341 self.listbox2.selection_clear(0, END) 1342 self.listbox2.insert(newPos, fontString) 1343 self.listbox2.see(newPos - 10) # Scrolls listbox automatically into view if req. 1344 self.listbox2.selection_set(newPos) 1345 self.listbox2.activate(newPos) # make focus follow selection 1346 self.__testUpDownState() # note tests only after an item has been moved 1347 1348 def __itemDown(self): 1349 """Test if one item is selected then move it down one position.""" 1350 limit = self.listbox2.size() 1351 selection = self.listbox2.curselection() 1352 if len(selection) == 1: 1353 indexId = IntType(selection[0]) 1354 if indexId < limit - 1: 1355 fontString = self.listbox2.get(indexId) 1356 self.listbox2.delete(indexId) 1357 newPos = indexId + 1 1358 self.listbox2.selection_clear(0, END) 1359 self.listbox2.insert(newPos, fontString) 1360 self.listbox2.see(newPos + 10) 1361 self.listbox2.selection_set(newPos) 1362 self.listbox2.activate(newPos) # make focus follow selection 1363 self.__testUpDownState() 1364 1365 def __setUpDownActive(self, up, down): 1366 """Just sets the buttons active or inactive. 1367 1368 See testUpDown() for the actual evaluation 1369 """ 1370 if up == 1: 1371 self.itemupButton['state'] = NORMAL 1372 else: 1373 self.itemupButton['state'] = DISABLED 1374 if down == 1: 1375 self.itemdownButton['state'] = NORMAL 1376 else: 1377 self.itemdownButton['state'] = DISABLED 1378 1379 def __testUpDownState(self): 1380 """Only enable the up and down buttons when just a single item is selected. 1381 1382 Enable should be applied to up, down or both depending on its 1383 position in the listbox. At all other times disable both. 1384 """ 1385 # Get a count of how many items are currently selected... 1386 selection = list(self.listbox2.curselection()) 1387 tcount = 0 1388 for sel in selection: 1389 tcount = tcount + 1 1390 1391 position = 0 1392 if tcount == 1: 1393 position = IntType(selection[0]) 1394 1395 # If one selected and there is more than one item in the listbox then ok... 1396 if tcount == 1 and self.listbox2.size() > 1: 1397 # Now test the position of the selected line... 1398 if position > 0 and position < self.listbox2.size() - 1: # Both 1399 self.__setUpDownActive(1, 1) 1400 # If not one less or lesser from the bottom (listbox.count-1?) then gray the down button. 1401 elif position == self.listbox2.size() - 1: # Up only 1402 self.__setUpDownActive(1, 0) 1403 # If not one or more from the top then gray up button. 1404 elif position == 0: # Down only 1405 self.__setUpDownActive(0, 1) 1406 else: 1407 self.__setUpDownActive(0, 0) 1408 1409 def __curSelectedItem(self, selectedFont): 1410 """Send the selected font to the preview function if preview available.""" 1411 if showPreviewPanel: 1412 preview_font(self, selectedFont) 1413 1414 # create the button events... 1415 def __rsingleButtonClick(self): 1416 self.__listSelectionToRight() 1417 1418 def __rdoubleButtonClick(self): 1419 self.__listAllToRight() 1420 1421 def __lsingleButtonClick(self): 1422 self.__listSelectionToLeft() 1423 self.__testUpDownState() 1424 1425 def __ldoubleButtonClick(self): 1426 self.__listAllToLeft() 1427 self.__testUpDownState() 1428 1429 def __itemupButtonClick(self): 1430 self.__itemUp() 1431 1432 def __itemdownButtonClick(self): 1433 self.__itemDown() 1434 1435 def __tocSelectButtonClick(self): 1436 userPrefs['wantTOC'] = self.__wantToc.get() 1437 if userPrefs['wantTOC']: 1438 self.btnPageOneOnFirst['state'] = NORMAL 1439 else: 1440 self.btnPageOneOnFirst['state'] = DISABLED 1441 1442 def __pageNumberSelectButtonClick(self): 1443 userPrefs['wantPageNumbers'] = self.__wantPageNum.get() 1444 1445 def __bindingoffsetSelectButtonClick(self): 1446 userPrefs['wantBindingOffset'] = self.__wantBindingOffset.get() 1447 dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset'])) 1448 1449 def __doubleSidedSelectButtonClick(self): 1450 userPrefs['wantDoubleSided'] = self.__wantDoubleSided.get() 1451 1452 def __wantPageOneOnFirstClick(self): 1453 userPrefs['wantPageOneOnFirst'] = self.__wantPageOneOnFirst.get() 1454 1455 def __cancelButtonClick(self): 1456 """We exit the app here if user presses cancel.""" 1457 self.master.destroy() 1458 1459 def __okButtonClick(self): 1460 """User presses ok, so lets create the pages.""" 1461 save_user_conf(CONFIG_PATH) 1462 draw_selection(self.listbox2.get(0, END), 0) 1463 self.master.destroy() 1464 1465 def __configurationDlgShow(self): 1466 """Opens the configuration dialog where user can set up the options""" 1467 configs = ConfigurationDialog(self) 1468 self.statusbarUpdate() 1469 1470 def __saveCurrentSettingsAsDefaults(self): 1471 """Stores current settings as defaults.""" 1472 defaultPrefs.update(userPrefs) 1473 save_user_conf(CONFIG_PATH) 1474 1475 def __restoreCurrentSettingsFromDefault(self): 1476 """Restores current settings from defaults.""" 1477 userPrefs.update(defaultPrefs) 1478 self.initialiseWidgets() 1479 self.statusbarUpdate() 1480 1481 def initialiseWidgets(self): 1482 if userPrefs['wantPageNumbers']: 1483 self.pagenumSelect.select() 1484 else: 1485 self.pagenumSelect.deselect() 1486 if userPrefs['wantTOC']: 1487 self.tocSelect.select() 1488 self.btnPageOneOnFirst['state'] = NORMAL 1489 else: 1490 self.tocSelect.deselect() 1491 self.btnPageOneOnFirst['state'] = DISABLED 1492 if userPrefs['wantBindingOffset']: 1493 self.bindingoffsetSelect.select() 1494 else: 1495 self.bindingoffsetSelect.deselect() 1496 if userPrefs['wantDoubleSided']: 1497 self.doublesidedSelect.select() 1498 else: 1499 self.doublesidedSelect.deselect() 1500 if userPrefs['wantPageOneOnFirst']: 1501 self.btnPageOneOnFirst.select() 1502 else: 1503 self.btnPageOneOnFirst.deselect() 1504 1505 def __aboutDlgShow(self): 1506 """Brings up a dialog with support url etc.""" 1507 about = AboutDialog(self) 1508 1509 1510def setup_tk(): 1511 """Create and setup the Tkinter app.""" 1512 root = Tk() 1513 app = Application(root) 1514 app.master.title(WINDOW_TITLE) 1515 1516 # now get a list of all the fonts Scribus knows about... 1517 fontList = scribus.getFontNames() 1518 fontList.sort() 1519 # and load the list into the GUI listbox... 1520 for i in fontList: 1521 app.listbox1.insert(END, i) 1522 app.sampleBlocksPerPage = draw_selection(scribus.getFontNames(), 1) 1523 # now set the status bar message... 1524 app.statusbarUpdate() 1525 # set up widgets using data from userPrefs... 1526 app.initialiseWidgets() 1527 return app 1528 1529def initialisation(): 1530 """Test for suitable fonts and on success creates tkinter app.""" 1531 try: 1532 dD['bookstyleFixedFont'] = set_font_fixed(fontsListFixed) 1533 dD['bookstylePropFont'] = set_font_proportional(fontsListProportional) 1534 except: 1535 scribus.messageBox('Font problem', 1536 '%s' % sys.exc_info()[1], 1537 scribus.ICON_WARNING) 1538 sys.exit(1) 1539 # load users saved defaults... 1540 restore_user_conf(CONFIG_PATH) 1541 # get and set the initial paper size to match default radiobutton selection... 1542 dD.update(set_page_geometry(dD, geometriesList, userPrefs['paperSize'], userPrefs['wantBindingOffset'])) 1543 # Made it this far so its time to create our Tkinter app... 1544 app = setup_tk() 1545 # now show the main window and wait for user to do something... 1546 app.mainloop() 1547 1548 1549def main(argv): 1550 """Application initialization, font checks and initial setup.""" 1551 initialisation() 1552 1553 1554def main_wrapper(argv): 1555 """The main_wrapper() function disables redrawing, sets a sensible generic 1556 status bar message, and optionally sets up the progress bar. It then runs 1557 the main() function. Once everything finishes it cleans up after the main() 1558 function, making sure everything is sane before the script terminates.""" 1559 try: 1560 scribus.statusMessage('Running script...') 1561 scribus.progressReset() 1562 main(argv) 1563 finally: 1564 # Exit neatly even if the script terminated with an exception, 1565 # so we leave the progress bar and status bar blank and make sure 1566 # drawing is enabled. 1567 if scribus.haveDoc() > 0: 1568 scribus.setRedraw(True) 1569 scribus.statusMessage('') 1570 scribus.progressReset() 1571 1572 1573# This code detects if the script is being run as a script, or imported as a module. 1574# It only runs main() if being run as a script. This permits you to import your script 1575# and control it manually for debugging. 1576if __name__ == '__main__': 1577 main_wrapper(sys.argv) 1578 1579