1from paida.paida_core.PAbsorber import * 2from paida.paida_core.IFillStyle import * 3from paida.paida_core.ILineStyle import * 4from paida.paida_core.ITextStyle import * 5 6from Tkinter import Tk, Toplevel, Button, PhotoImage, Frame, Canvas, Scrollbar, VERTICAL, HORIZONTAL 7import Tkinter 8import tkFont 9try: 10 import threading 11except ImportError: 12 import dummy_threading as threading 13import time 14import math 15 16N = Tkinter.N 17NE = Tkinter.NE 18E = Tkinter.E 19SE = Tkinter.SE 20S = Tkinter.S 21SW = Tkinter.SW 22W = Tkinter.W 23NW = Tkinter.NW 24CENTER = Tkinter.CENTER 25 26def createRoot(): 27 global _guiRoot 28 _guiRoot = _Root() 29 _guiRoot.setDaemon(True) 30 31def startRoot(): 32 global _guiRoot 33 _guiRoot.start() 34 35def getRoot(): 36 global _guiRoot 37 return _guiRoot 38 39def getFontList(_defaultCandidates): 40 _fontRoot = Tk() 41 _fontRoot.withdraw() 42 _fontRoot.tk.call('tk', 'useinputmethods', 'False') 43 _fontRoot.tk.call('tk', 'scaling', '1.0') 44 fontList = list(tkFont.families(_fontRoot)) 45 fontList.sort() 46 defaultFont = Button(_fontRoot).cget('font') 47 48 if not defaultFont in fontList: 49 fontList.append(defaultFont) 50 for _defaultCandidate in _defaultCandidates: 51 if _defaultCandidate in fontList: 52 defaultFont = _defaultCandidate 53 54 _fontRoot.destroy() 55 return fontList, defaultFont 56 57 58 59class _Root(threading.Thread): 60 def __init__(self): 61 threading.Thread.__init__(self) 62 self._setRootCondition(threading.Condition()) 63 64 def run(self): 65 rootCondition = self._getRootCondition() 66 rootCondition.acquire() 67 self._setRoot(Tk()) 68 root = self._getRoot() 69 root.withdraw() 70 root.tk.call('tk', 'useinputmethods', 'False') 71 root.tk.call('tk', 'scaling', '1.0') 72 root.grid() 73 74 self._trees = [] 75 self._plotters = [] 76 self._requestedTrees = [] 77 self._requestedPlotters = [] 78 self._setQuitLoop(False) 79 80 self._setLock(threading.RLock()) 81 self._setTreeCondition(threading.Condition()) 82 self._setPlotterCondition(threading.Condition()) 83 84 rootCondition.notifyAll() 85 rootCondition.release() 86 self._mainloop() 87 88 while 1: 89 if self._getQuitLoop(): 90 rootCondition = self._getRootCondition() 91 rootCondition.acquire() 92 ### Wait other threads. 93 lock = self._getLock() 94 lock.acquire() 95 lock.release() 96 rootCondition.notifyAll() 97 rootCondition.release() 98 break 99 root.update() 100 time.sleep(0.1) 101 102 def _mainloop(self): 103 lock = self._getLock() 104 if lock.acquire(blocking = 0): 105 self._check() 106 lock.release() 107 self._getRoot().after(300, self._mainloop) 108 109 def _setLock(self, lock): 110 self._lock = lock 111 112 def _getLock(self): 113 return self._lock 114 115 def _setRootCondition(self, Condition): 116 self._rootCondition = Condition 117 118 def _getRootCondition(self): 119 return self._rootCondition 120 121 def _setTreeCondition(self, Condition): 122 self._treeCondition = Condition 123 124 def _getTreeCondition(self): 125 return self._treeCondition 126 127 def _setPlotterCondition(self, Condition): 128 self._plotterCondition = Condition 129 130 def _getPlotterCondition(self): 131 return self._plotterCondition 132 133 def _setQuitLoop(self, boolean): 134 self._quitLoop = boolean 135 136 def _getQuitLoop(self): 137 return self._quitLoop 138 139 def _setRoot(self, root): 140 self._root = root 141 142 def _getRoot(self): 143 return self._root 144 145 def _appendTree(self, tree): 146 self._trees.append(tree) 147 148 def _getTrees(self): 149 return self._trees 150 151 def _removeTree(self, tree): 152 self._getTrees().remove(tree) 153 154 def _appendPlotter(self, plotter): 155 self._plotters.append(plotter) 156 157 def _getPlotters(self): 158 return self._plotters 159 160 def _removePlotter(self, plotter): 161 self._getPlotters().remove(plotter) 162 163 def _requestTree(self): 164 treeCondition = self._getTreeCondition() 165 treeCondition.acquire() 166 bridge = [] 167 self._requestedTrees.append(bridge) 168 treeCondition.wait() 169 treeCondition.release() 170 return bridge[0][0] 171 172 def _requestPlotter(self, viewWidth, viewHeight, width, height): 173 plotterCondition = self._getPlotterCondition() 174 plotterCondition.acquire() 175 bridge = [] 176 self._requestedPlotters.append((bridge, viewWidth, viewHeight, width, height)) 177 plotterCondition.wait() 178 plotterCondition.release() 179 return bridge[0][0] 180 181 def _check(self): 182 self._updateTrees() 183 self._updatePlotters() 184 185 def _updateTrees(self): 186 if self._requestedTrees: 187 treeCondition = self._getTreeCondition() 188 treeCondition.acquire() 189 for bridge in self._requestedTrees: 190 _tree = _Tree(self._getLock()) 191 bridge.append([_tree]) 192 self._appendTree(_tree) 193 _tree.update() 194 self._requestedTrees = [] 195 treeCondition.notifyAll() 196 treeCondition.release() 197 return 198 199 for tree in self._getTrees(): 200 tree.update() 201 202 def _updatePlotters(self): 203 if self._requestedPlotters: 204 plotterCondition = self._getPlotterCondition() 205 plotterCondition.acquire() 206 for (bridge, viewWidth, viewHeight, width, height) in self._requestedPlotters: 207 _plotter = _Plotter(self._getLock(), viewWidth, viewHeight, width, height) 208 bridge.append([_plotter]) 209 self._appendPlotter(_plotter) 210 _plotter.update() 211 self._requestedPlotters = [] 212 plotterCondition.notifyAll() 213 plotterCondition.release() 214 return 215 216 for plotter in self._getPlotters(): 217 plotter.update() 218 219class _Base: 220 def __init__(self, lock): 221 self._canvasCommands = [] 222 self._sizeCommands = [] 223 self.setLock(lock) 224 225 ### Create widges. 226 self.setRoot(Toplevel()) 227 root = self.getRoot() 228 root.tk.call('tk', 'useinputmethods', 'False') 229 root.grid_rowconfigure(0, weight = 1) 230 root.grid_columnconfigure(0, weight = 1) 231 self.setFrame(Frame(root)) 232 frame = self.getFrame() 233 frame.grid() 234 self.setCanvas(Canvas(frame)) 235 canvas = self.getCanvas() 236 canvas.scrollX = Scrollbar(frame, orient = HORIZONTAL) 237 canvas.scrollY = Scrollbar(frame, orient = VERTICAL) 238 canvas.scrollX.grid(column = '0', row = '1', sticky= E + W) 239 canvas.scrollY.grid(column = '1', row = '0', sticky= N + S) 240 canvas.configure(xscrollcommand = self.xscroll) 241 canvas.configure(yscrollcommand = self.yscroll) 242 canvas.scrollX.configure(command = self.xview) 243 canvas.scrollY.configure(command = self.yview) 244 canvas.grid(column = '0', row = '0', sticky = N + E + S + W) 245 246 self._setFontCondition(threading.Condition()) 247 textStyle = ITextStyle() 248 textStyle.setBold(False) 249 textStyle.setUnderlined(False) 250 self._fontMeasurement = self._createTkFont(textStyle) 251 252 self.setShow(True) 253 self.setTitle('') 254 255 def _sizeChanged(self, event): 256 self.getLock().acquire() 257 self._canvasCommands.append([self.canvas_sizeChanged, [event], {}]) 258 self.getLock().release() 259 260 def canvas_sizeChanged(self, event): 261 root = self.getRoot() 262 frame = self.getFrame() 263 canvas = self.getCanvas() 264 if (root is None) or (frame is None) or (canvas is None): 265 return 266 267 frame.unbind('<Configure>') 268 canvas.configure(xscrollcommand = self.canvas_xscroll) 269 canvas.configure(yscrollcommand = self.canvas_yscroll) 270 canvas.scrollX.configure(command = self.canvas_xview) 271 canvas.scrollY.configure(command = self.canvas_yview) 272 273 pad = 5 274 padX = int(canvas.scrollX.cget('width')) + pad 275 padY = int(canvas.scrollY.cget('width')) + pad 276 x = root.winfo_width() 277 y = root.winfo_height() 278 canvas.configure(width = x - padX, height = y - padY) 279 root.update_idletasks() 280 281 canvas.configure(xscrollcommand = self.xscroll) 282 canvas.configure(yscrollcommand = self.yscroll) 283 canvas.scrollX.configure(command = self.xview) 284 canvas.scrollY.configure(command = self.yview) 285 frame.bind('<Configure>', self._sizeChanged) 286 287 def _setFontCondition(self, condition): 288 self._fontCondition = condition 289 290 def _getFontCondition(self): 291 return self._fontCondition 292 293 def getNCanvasCommands(self): 294 return len(self._canvasCommands) 295 296 def setRoot(self, root): 297 self._root = root 298 299 def getRoot(self): 300 return self._root 301 302 def setFrame(self, frame): 303 self._frame = frame 304 305 def getFrame(self): 306 return self._frame 307 308 def setCanvas(self, canvas): 309 self._canvas = canvas 310 311 def getCanvas(self): 312 return self._canvas 313 314 def setLock(self, lock): 315 self._lock = lock 316 317 def getLock(self): 318 return self._lock 319 320 def xscroll(self, *args): 321 self.getLock().acquire() 322 self._canvasCommands.append([self.canvas_xscroll, args, {}]) 323 self.getLock().release() 324 325 def yscroll(self, *args): 326 self.getLock().acquire() 327 self._canvasCommands.append([self.canvas_yscroll, args, {}]) 328 self.getLock().release() 329 330 def xview(self, *args): 331 self.getLock().acquire() 332 self._canvasCommands.append([self.canvas_xview, args, {}]) 333 self.getLock().release() 334 335 def yview(self, *args): 336 self.getLock().acquire() 337 self._canvasCommands.append([self.canvas_yview, args, {}]) 338 self.getLock().release() 339 340 def canvas_xscroll(self, *args1): 341 canvas = self.getCanvas() 342 if canvas is not None: 343 canvas.scrollX.set(*args1) 344 345 def canvas_yscroll(self, *args1): 346 canvas = self.getCanvas() 347 if canvas is not None: 348 canvas.scrollY.set(*args1) 349 350 def canvas_xview(self, *args1): 351 canvas = self.getCanvas() 352 if canvas is not None: 353 canvas.xview(*args1) 354 355 def canvas_yview(self, *args1): 356 canvas = self.getCanvas() 357 if canvas is not None: 358 canvas.yview(*args1) 359 360 def canvas_title(self, title): 361 self.getFrame().master.title(title) 362 self._title = title 363 364 def canvas_show(self, boolean): 365 if boolean == True: 366 self.getRoot().deiconify() 367 else: 368 self.getRoot().withdraw() 369 self._show = boolean 370 371 def canvas_terminate(self): 372 self.getCanvas().destroy() 373 self.setCanvas(None) 374 self.getFrame().destroy() 375 self.setFrame(None) 376 self.getRoot().destroy() 377 self.setRoot(None) 378 379 self._fontMeasurement = None 380 381 def setTitle(self, title): 382 self.getLock().acquire() 383 self._canvasCommands.append([self.canvas_title, [title], {}]) 384 self.getLock().release() 385 386 def getTitle(self): 387 return self._title 388 389 def setShow(self, boolean): 390 self.getLock().acquire() 391 self._canvasCommands.append([self.canvas_show, [boolean], {}]) 392 self.getLock().release() 393 394 def getShow(self): 395 return self._show 396 397 def _createTkFont(self, textStyle): 398 fontFamily = textStyle.font() 399 fontSize = int(textStyle.fontSize()) 400 if textStyle.isBold(): 401 fontWeight = 'bold' 402 else: 403 fontWeight = 'normal' 404 if textStyle.isItalic(): 405 fontSlant = 'italic' 406 else: 407 fontSlant = 'roman' 408 if textStyle.isUnderlined(): 409 fontUnderline = 1 410 else: 411 fontUnderline = 0 412 return tkFont.Font(family=fontFamily, size=fontSize, weight=fontWeight, slant=fontSlant, underline=fontUnderline) 413 414 def _configureTkFont(self, font, textStyle): 415 fontFamily = textStyle.font() 416 fontSize = int(textStyle.fontSize()) 417 if textStyle.isBold(): 418 fontWeight = 'bold' 419 else: 420 fontWeight = 'normal' 421 if textStyle.isItalic(): 422 fontSlant = 'italic' 423 else: 424 fontSlant = 'roman' 425 if textStyle.isUnderlined(): 426 fontUnderline = 1 427 else: 428 fontUnderline = 0 429 font.configure(family=fontFamily, size=fontSize, weight=fontWeight, slant=fontSlant, underline=fontUnderline) 430 return font 431 432 def _getFontTuple(self, textStyle): 433 fontFamily = textStyle.font() 434 fontSize = str(int(textStyle.fontSize())) 435 options = '' 436 if textStyle.isBold(): 437 options += 'bold' 438 else: 439 options += 'normal' 440 if textStyle.isItalic(): 441 options += ' italic' 442 else: 443 options += ' roman' 444 if textStyle.isUnderlined(): 445 options += ' underline' 446 else: 447 pass 448 return (fontFamily, fontSize, options) 449 450 def _getFontMeasurements(self, textDataList, bridge): 451 fontCondition = self._getFontCondition() 452 fontCondition.acquire() 453 self._canvasCommands.append([self.canvas_fontMeasurements, [textDataList, bridge], {}]) 454 fontCondition.wait() 455 fontCondition.release() 456 457 def canvas_fontMeasurements(self, textDataList, bridge): 458 fontCondition = self._getFontCondition() 459 fontCondition.acquire() 460 result = [] 461 fontMeasurement = self._fontMeasurement 462 for textStyle, text in textDataList: 463 fontMeasurement = self._configureTkFont(fontMeasurement, textStyle) 464 result.append([fontMeasurement.measure(text), fontMeasurement.metrics('linespace')]) 465 bridge.append(result) 466 fontCondition.notifyAll() 467 fontCondition.release() 468 469 def update(self): 470 self.getLock().acquire() 471 for [method, args1, args2] in self._canvasCommands: 472 method(*args1, **args2) 473 else: 474 self._canvasCommands = [] 475 self.getLock().release() 476 477class _Tree(_Base): 478 _folderIconString = 'R0lGODlhDgAPAIIAAA4ODkhz///U1ABV/46r/wAAAAAAAAAAACH5BAEAAAIALAAAAAAOAA8AAAhX\nAAUIHAgAwMCDBAEECFAQoYCCCyMyNChQocSLBiFelFgQAAGNHAEMKEigpMaCA1KSLGlSZEqVHll+\nfPlyJUuXNG2apKnyoUycPSvGxNkQYceRFB0KdRgQADs=\n' 479 _fileIconString = 'R0lGODlhCgAKAIIAACVX/7HH/9Tj/2uP/////wAAAAAAAAAAACH5BAEAAAQALAAAAAAKAAoAAAg0\nAAkIHEiQAICDCAkiRDhAgMCFBwcEcAgRgESKEC8azDhR4ICPIDsSEBCgpEmHAgWoXEkgIAA7\n' 480 481 def __init__(self, lock): 482 _Base.__init__(self, lock) 483 self.getCanvas().configure(bg='white', width=300) 484 485 self._folderImage = PhotoImage(data = self._folderIconString) 486 self._folderImageWidth = self._folderImage.width() 487 self._folderImageHeight = self._folderImage.height() 488 self._fileImage = PhotoImage(data = self._fileIconString) 489 self._fileImageWidth = self._fileImage.width() 490 self._fileImageHeight = self._fileImage.height() 491 492 textStyle = ITextStyle() 493 textStyle.setBold(False) 494 textStyle.setUnderlined(False) 495 self._fontNormal = self._createTkFont(textStyle) 496 textStyle.setBold(True) 497 textStyle.setUnderlined(True) 498 self._fontSelected = self._createTkFont(textStyle) 499 500 self.getFrame().bind('<Configure>', self._sizeChanged) 501 502 def terminate(self): 503 self.getLock().acquire() 504 self._canvasCommands.append([self.canvas_terminate, [], {}]) 505 self.getLock().release() 506 507 def canvas_terminate(self): 508 getRoot()._removeTree(self) 509 510 _Base.canvas_terminate(self) 511 512 self._folderImage = None 513 self._fileImage = None 514 self._fontNormal = None 515 self._fontSelected = None 516 517 def redrawTree(self, block, itree): 518 if self.getLock().acquire(block): 519 canvasCommands = self._canvasCommands 520 command = [self.canvas_redrawTree, [itree], {}] 521 try: 522 while 1: 523 canvasCommands.remove(command) 524 except ValueError: 525 pass 526 canvasCommands.append(command) 527 self.getLock().release() 528 529 def canvas_redrawTree(self, itree): 530 canvas = self.getCanvas() 531 canvas.delete(['allItems']) 532 pwd = itree._getPwd() 533 self.redrawTreeWalker(itree, pwd, canvas, '/', 10, 10) 534 result = canvas.bbox('all') 535 if result != None: 536 cx1, cy1, cx2, cy2 = result 537 canvas.configure(scrollregion = (0, 0, cx2 + 10, cy2 + 10)) 538 539 def redrawTreeWalker(self, itree, pwd, canvas, directoryPath, x, y): 540 spaceX = 16 541 spaceY = 4 542 stringSpaceX = 4 543 fileX = x + self._fileImageWidth + stringSpaceX 544 fontNormal = self._fontNormal 545 fileImage = self._fileImage 546 tags = ['allItems'] 547 objects = itree._listObjects(directoryPath) 548 for object in objects: 549 if object._instance: 550 canvas.create_image(x, y, image = fileImage, anchor = W, tags = tags) 551 canvas.create_text(fileX, y, text = object.name(), font = fontNormal, anchor = W , tags = tags) 552 y += spaceY + self._fileImageHeight 553 else: 554 ### Subdirectory. 555 canvas.create_image(x, y, image = self._folderImage, anchor = W, tags = tags) 556 if object == pwd: 557 canvas.create_text(x + self._folderImageWidth + stringSpaceX, y, text = object.name(), font = self._fontSelected, anchor = W , tags=tags) 558 else: 559 canvas.create_text(x + self._folderImageWidth + stringSpaceX, y, text = object.name(), font = fontNormal, anchor = W , tags=tags) 560 y += spaceY + self._folderImageHeight 561 x2, y = self.redrawTreeWalker(itree, pwd, canvas, '%s/%s' % (directoryPath, object.name()), x + spaceX, y) 562 return x, y 563 564class _Plotter(_Base): 565 def __init__(self, lock, viewWidth, viewHeight, width, height): 566 _Base.__init__(self, lock) 567 canvas = self.getCanvas() 568 canvas.configure(bg='white') 569 self.setImageIOCondition(threading.Condition()) 570 571 self._legendsFont = self._createTkFont(ITextStyle()) 572 self._statisticsFont = self._createTkFont(ITextStyle()) 573 self._textsFont = self._createTkFont(ITextStyle()) 574 self._canvasFont = self._createTkFont(ITextStyle()) 575 self._canvasExponentBaseFont = self._createTkFont(ITextStyle()) 576 self._canvasExponentIndexFont = self._createTkFont(ITextStyle()) 577 578 self.setViewWidth(canvas.winfo_pixels(viewWidth)) 579 self.setViewHeight(canvas.winfo_pixels(viewHeight)) 580 self.setScrollRegion(0, 0, canvas.winfo_pixels(width), canvas.winfo_pixels(height)) 581 582 self.getFrame().bind('<Configure>', self._sizeChanged) 583 584 def _requestRegion(self, serialNumber, allTags, x0, y0, x1, y1): 585 ### Nothing to do for Tkinter GUI. 586 pass 587 588 def _convertToPixelX(self, length): 589 return self.getCanvas().winfo_pixels(length) 590 591 def _convertToPixelY(self, length): 592 return self.getCanvas().winfo_pixels(length) 593 594 def setImageIOCondition(self, condition): 595 self._imageIOCondition = condition 596 597 def getImageIOCondition(self): 598 return self._imageIOCondition 599 600 def setScrollRegion(self, *args): 601 self.getLock().acquire() 602 self._canvasCommands.append([self.canvas_scrollRegion, args, {}]) 603 self.getLock().release() 604 605 def getScrollRegion(self): 606 return self._scrollRegion 607 608 def setViewWidth(self, viewWidth): 609 self.getLock().acquire() 610 self._canvasCommands.append([self.canvas_viewWidth, [viewWidth], {}]) 611 self.getLock().release() 612 613 def getViewWidth(self): 614 return self._viewWidth 615 616 def setViewHeight(self, viewHeight): 617 self.getLock().acquire() 618 self._canvasCommands.append([self.canvas_viewHeight, [viewHeight], {}]) 619 self.getLock().release() 620 621 def getViewHeight(self): 622 return self._viewHeight 623 624 def refresh(self): 625 pass 626 627 def delete(self, *args): 628 self.getLock().acquire() 629 self._canvasCommands.append([self.canvas_delete, args, {}]) 630 self.getLock().release() 631 632 def create_styledText(self, *args1, **args2): 633 self.getLock().acquire() 634 self._canvasCommands.append([self.canvas_create_styledText, args1, args2]) 635 self.getLock().release() 636 637 def create_styledExponent(self, *args1, **args2): 638 self.getLock().acquire() 639 self._canvasCommands.append([self.canvas_create_styledExponent, args1, args2]) 640 self.getLock().release() 641 642 def create_styledOval(self, *args1, **args2): 643 self.getLock().acquire() 644 self._canvasCommands.append([self.canvas_create_styledOval, args1, args2]) 645 self.getLock().release() 646 647 def create_styledRectangle(self, *args1, **args2): 648 self.getLock().acquire() 649 self._canvasCommands.append([self.canvas_create_styledRectangle, args1, args2]) 650 self.getLock().release() 651 652 def create_styledLine(self, *args1, **args2): 653 self.getLock().acquire() 654 self._canvasCommands.append([self.canvas_create_styledLine, args1, args2]) 655 self.getLock().release() 656 657 def create_styledPolygon(self, *args1, **args2): 658 self.getLock().acquire() 659 self._canvasCommands.append([self.canvas_create_styledPolygon, args1, args2]) 660 self.getLock().release() 661 662 def create_styledMarker(self, *args1, **args2): 663 self.getLock().acquire() 664 self._canvasCommands.append([self.canvas_create_styledMarker, args1, args2]) 665 self.getLock().release() 666 667 def create_styledTextsBox(self, *args1, **args2): 668 self.getLock().acquire() 669 self._canvasCommands.append([self.canvas_create_styledTextsBox, args1, args2]) 670 self.getLock().release() 671 672 def create_styledLegendsBox(self, *args1, **args2): 673 self.getLock().acquire() 674 self._canvasCommands.append([self.canvas_create_styledLegendsBox, args1, args2]) 675 self.getLock().release() 676 677 def create_styledStatisticsBox(self, *args1, **args2): 678 self.getLock().acquire() 679 self._canvasCommands.append([self.canvas_create_styledStatisticsBox, args1, args2]) 680 self.getLock().release() 681 682 def setPostscript(self, fileName, landscape): 683 imageIOCondition = self.getImageIOCondition() 684 imageIOCondition.acquire() 685 self._canvasCommands.append([self.canvas_postscript, [fileName, landscape], {}]) 686 imageIOCondition.wait() 687 imageIOCondition.release() 688 689 def setPostscriptStrings(self, landscape, bridge): 690 imageIOCondition = self.getImageIOCondition() 691 imageIOCondition.acquire() 692 self._canvasCommands.append([self.canvas_postscriptStrings, [landscape, bridge], {}]) 693 imageIOCondition.wait() 694 imageIOCondition.release() 695 696 def terminate(self): 697 self.getLock().acquire() 698 self._canvasCommands.append([self.canvas_terminate, [], {}]) 699 self.getLock().release() 700 701 def canvas_terminate(self): 702 getRoot()._removePlotter(self) 703 704 _Base.canvas_terminate(self) 705 706 self._legendsFont = None 707 self._statisticsFont = None 708 self._textsFont = None 709 self._canvasFont = None 710 self._canvasExponentBaseFont = None 711 self._canvasExponentIndexFont = None 712 713 def canvas_scrollRegion(self, x0, y0, x1, y1): 714 canvas = self.getCanvas() 715 cx0 = canvas.winfo_pixels(x0) 716 cy0 = canvas.winfo_pixels(y0) 717 cx1 = canvas.winfo_pixels(x1) 718 cy1 = canvas.winfo_pixels(y1) 719 self._scrollRegion = (cx0, cy0, cx1, cy1) 720 canvas.configure(scrollregion = (cx0, cy0, cx1, cy1)) 721 722 def canvas_viewWidth(self, viewWidth): 723 canvas = self.getCanvas() 724 self._viewWidth = canvas.winfo_pixels(viewWidth) 725 screenWidth = canvas.winfo_screenwidth() 726 canvas.configure(width = min(self._viewWidth, screenWidth)) 727 728 def canvas_viewHeight(self, viewHeight): 729 canvas = self.getCanvas() 730 self._viewHeight = canvas.winfo_pixels(viewHeight) 731 padY = 80 732 screenHeight = canvas.winfo_screenheight() - padY 733 canvas.configure(height = min(self._viewHeight, screenHeight)) 734 735 def canvas_create_styledLegendsBox(self, infoStyle, region, layout, legends, tags): 736 self.canvas_delete(tags) 737 textStyle = infoStyle.textStyle() 738 fontData = self._configureTkFont(self._legendsFont, textStyle) 739 fontWidth = fontData.measure('W') 740 fontHeight = fontData.metrics('linespace') 741 fontHalf = fontData.metrics('ascent') / 2.0 742 743 longestDescription = 0 744 for [style, description] in legends: 745 longestDescription = max(longestDescription, fontData.measure(description)) 746 longestStyle = fontWidth 747 748 xLower, xUpper = region._getAxisRangeX() 749 yLower, yUpper = region._getAxisRangeY() 750 regionLengthX = region._getRegionLengthX() 751 regionLengthY = region._getRegionLengthY() 752 tabX = max(5, int(0.014 * regionLengthX)) + 1 753 tabY = max(5, int(0.014 * regionLengthY)) + 1 754 spacerX = max(2, fontWidth / 2) 755 spacerY = max(2, fontHeight / 4) 756 boxOffsetX = self._convertToPixelX(layout._parameterData('legendsBoxOffsetX')) 757 boxOffsetY = self._convertToPixelY(layout._parameterData('legendsBoxOffsetY')) 758 boxAnchor = layout._parameterData('legendsBoxAnchor') 759 if boxAnchor == 'N': 760 boxX = (xLower + xUpper) / 2.0 - (longestStyle + spacerX + longestDescription) / 2.0 - tabX + boxOffsetX 761 boxY = yLower + boxOffsetY 762 elif boxAnchor == 'NE': 763 boxX = xUpper - longestStyle - spacerX - longestDescription - tabX * 2 + boxOffsetX 764 boxY = yLower + boxOffsetY 765 elif boxAnchor == 'E': 766 boxX = xUpper - longestStyle - spacerX - longestDescription - tabX * 2 + boxOffsetX 767 boxY = (yLower + yUpper) / 2.0 - (len(legends) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY 768 elif boxAnchor == 'SE': 769 boxX = xUpper - longestStyle - spacerX - longestDescription - tabX * 2 + boxOffsetX 770 boxY = yUpper - (len(legends) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 771 elif boxAnchor == 'S': 772 boxX = (xLower + xUpper) / 2.0 - (longestStyle + spacerX + longestDescription) / 2.0 - tabX + boxOffsetX 773 boxY = yUpper - (len(legends) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 774 elif boxAnchor == 'SW': 775 boxX = xLower + boxOffsetX 776 boxY = yUpper - (len(legends) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 777 elif boxAnchor == 'W': 778 boxX = xLower + boxOffsetX 779 boxY = (yLower + yUpper) / 2.0 - (len(legends) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY 780 elif boxAnchor == 'NW': 781 boxX = xLower + boxOffsetX 782 boxY = yLower + boxOffsetY 783 else: 784 raise RuntimeException() 785 styleX = boxX + tabX 786 descriptionX = styleX + longestStyle + spacerX 787 lineY = boxY + tabY 788 789 boxWidth = tabX * 2 + longestStyle + spacerX + longestDescription 790 boxHeight = len(legends) * (fontHeight + spacerY) - spacerY + tabY * 2 791 fillStyle = infoStyle._parameterData('fillStyle') 792 lineStyle = infoStyle._parameterData('lineStyle') 793 self.canvas_create_styledRectangle(lineStyle, fillStyle, tags, boxX, boxY, boxX + boxWidth, boxY + boxHeight) 794 for [style, description] in legends: 795 style = style._createCopy() 796 if style.__class__.__name__ == 'IFillStyle': 797 originalColor = lineStyle.color() 798 lineStyle.setColor(style.color()) 799 self.canvas_create_styledRectangle(lineStyle, style, tags, styleX, lineY, styleX + fontWidth, lineY + fontHeight) 800 lineStyle.setColor(originalColor) 801 elif style.__class__.__name__ == 'ILineStyle': 802 self.canvas_create_styledLine(style, tags, styleX, lineY + fontHalf, styleX + fontWidth, lineY + fontHalf) 803 elif style.__class__.__name__ == 'IMarkerStyle': 804 originalSize = style._parameterData('size') 805 style.setParameter('size', fontWidth) 806 self.canvas_create_styledMarker(style, tags, styleX + fontWidth / 2.0, lineY + fontHalf) 807 style.setParameter('size', originalSize) 808 else: 809 raise RuntimeException() 810 self.canvas_create_styledText(textStyle, tags, descriptionX, lineY, description, NW) 811 lineY += fontHeight + spacerY 812 813 def canvas_create_styledStatisticsBox(self, infoStyle, region, layout, statisticsData, tags): 814 self.canvas_delete(tags) 815 textStyle = infoStyle.textStyle() 816 fontData = self._configureTkFont(self._statisticsFont, textStyle) 817 fontWidth = fontData.measure('W') 818 fontHeight = fontData.metrics('linespace') 819 820 longestName = 0 821 longestData = 0 822 for [name, data] in statisticsData: 823 longestName = max(longestName, fontData.measure(name)) 824 longestData = max(longestData, fontData.measure(data)) 825 826 xLower, xUpper = region._getAxisRangeX() 827 yLower, yUpper = region._getAxisRangeY() 828 regionLengthX = region._getRegionLengthX() 829 regionLengthY = region._getRegionLengthY() 830 tabX = max(5, int(0.014 * regionLengthX)) + 1 831 tabY = max(5, int(0.014 * regionLengthY)) + 1 832 spacerX = max(2, fontWidth / 2) 833 spacerY = max(2, fontHeight / 4) 834 boxOffsetX = self._convertToPixelX(layout._parameterData('statisticsBoxOffsetX')) 835 boxOffsetY = self._convertToPixelY(layout._parameterData('statisticsBoxOffsetY')) 836 boxAnchor = layout._parameterData('statisticsBoxAnchor') 837 if boxAnchor == 'N': 838 boxX = (xLower + xUpper) / 2.0 - (longestName + spacerX + longestData) / 2.0 - tabX + boxOffsetX 839 boxY = yLower + boxOffsetY 840 elif boxAnchor == 'NE': 841 boxX = xUpper - longestName - spacerX - longestData - tabX * 2 + boxOffsetX 842 boxY = yLower + boxOffsetY 843 elif boxAnchor == 'E': 844 boxX = xUpper - longestName - spacerX - longestData - tabX * 2 + boxOffsetX 845 boxY = (yLower + yUpper) / 2.0 - (len(statisticsData) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY 846 elif boxAnchor == 'SE': 847 boxX = xUpper - longestName - spacerX - longestData - tabX * 2 + boxOffsetX 848 boxY = yUpper - (len(statisticsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 849 elif boxAnchor == 'S': 850 boxX = (xLower + xUpper) / 2.0 - (longestName + spacerX + longestData) / 2.0 - tabX + boxOffsetX 851 boxY = yUpper - (len(statisticsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 852 elif boxAnchor == 'SW': 853 boxX = xLower + boxOffsetX 854 boxY = yUpper - (len(statisticsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 855 elif boxAnchor == 'W': 856 boxX = xLower + boxOffsetX 857 boxY = (yLower + yUpper) / 2.0 - (len(statisticsData) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY 858 elif boxAnchor == 'NW': 859 boxX = xLower + boxOffsetX 860 boxY = yLower + boxOffsetY 861 else: 862 raise RuntimeException() 863 nameX = boxX + tabX 864 dataX = nameX + longestName + spacerX 865 lineY = boxY + tabY 866 867 boxWidth = tabX * 2 + longestName + spacerX + longestData 868 boxHeight = len(statisticsData) * (fontHeight + spacerY) - spacerY + tabY * 2 869 fillStyle = infoStyle._parameterData('fillStyle') 870 lineStyle = infoStyle._parameterData('lineStyle') 871 self.canvas_create_styledRectangle(lineStyle, fillStyle, tags, boxX, boxY, boxX + boxWidth, boxY + boxHeight) 872 for [name, data] in statisticsData: 873 self.canvas_create_styledText(textStyle, tags, nameX, lineY, name, NW) 874 self.canvas_create_styledText(textStyle, tags, dataX, lineY, data, NW) 875 lineY += fontHeight + spacerY 876 877 def canvas_create_styledTextsBox(self, infoStyle, region, layout, textsData, tags): 878 self.canvas_delete(tags) 879 textStyle = infoStyle.textStyle() 880 fontData = self._configureTkFont(self._textsFont, textStyle) 881 fontWidth = fontData.measure('W') 882 fontHeight = fontData.metrics('linespace') 883 884 longestData = 0 885 for line in textsData: 886 longestData = max(longestData, fontData.measure(line)) 887 888 xLower, xUpper = region._getAxisRangeX() 889 yLower, yUpper = region._getAxisRangeY() 890 regionLengthX = region._getRegionLengthX() 891 regionLengthY = region._getRegionLengthY() 892 tabX = max(5, int(0.014 * regionLengthX)) + 1 893 tabY = max(5, int(0.014 * regionLengthY)) + 1 894 spacerX = max(2, fontWidth / 2) 895 spacerY = max(2, fontHeight / 4) 896 boxOffsetX = self._convertToPixelX(layout._parameterData('textsBoxOffsetX')) 897 boxOffsetY = self._convertToPixelY(layout._parameterData('textsBoxOffsetY')) 898 boxAnchor = layout._parameterData('textsBoxAnchor') 899 if boxAnchor == 'N': 900 boxX = (xLower + xUpper) / 2.0 - longestData / 2.0 - tabX + boxOffsetX 901 boxY = yLower + boxOffsetY 902 elif boxAnchor == 'NE': 903 boxX = xUpper - longestData - tabX * 2 + boxOffsetX 904 boxY = yLower + boxOffsetY 905 elif boxAnchor == 'E': 906 boxX = xUpper - longestData - tabX * 2 + boxOffsetX 907 boxY = (yLower + yUpper) / 2.0 - (len(textsData) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY 908 elif boxAnchor == 'SE': 909 boxX = xUpper - longestData - tabX * 2 + boxOffsetX 910 boxY = yUpper - (len(textsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 911 elif boxAnchor == 'S': 912 boxX = (xLower + xUpper) / 2.0 - longestData / 2.0 - tabX + boxOffsetX 913 boxY = yUpper - (len(textsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 914 elif boxAnchor == 'SW': 915 boxX = xLower + boxOffsetX 916 boxY = yUpper - (len(textsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY 917 elif boxAnchor == 'W': 918 boxX = xLower + boxOffsetX 919 boxY = (yLower + yUpper) / 2.0 - (len(textsData) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY 920 elif boxAnchor == 'NW': 921 boxX = xLower + boxOffsetX 922 boxY = yLower + boxOffsetY 923 else: 924 raise RuntimeException() 925 dataX = boxX + tabX 926 lineY = boxY + tabY 927 928 boxWidth = tabX * 2 + longestData 929 boxHeight = len(textsData) * (fontHeight + spacerY) - spacerY + tabY * 2 930 fillStyle = infoStyle._parameterData('fillStyle') 931 lineStyle = infoStyle._parameterData('lineStyle') 932 self.canvas_create_styledRectangle(lineStyle, fillStyle, tags, boxX, boxY, boxX + boxWidth, boxY + boxHeight) 933 for line in textsData: 934 self.canvas_create_styledText(textStyle, tags, dataX, lineY, line, NW) 935 lineY += fontHeight + spacerY 936 937 def canvas_postscript(self, fileName, landscape): 938 postscriptCondition = self.getImageIOCondition() 939 postscriptCondition.acquire() 940 x = self.getScrollRegion()[2] 941 y = self.getScrollRegion()[3] 942 self.getCanvas().postscript(file = fileName, width = x, height = y, rotate = landscape) 943 postscriptCondition.notifyAll() 944 postscriptCondition.release() 945 946 def canvas_postscriptStrings(self, landscape, bridge): 947 postscriptCondition = self.getImageIOCondition() 948 postscriptCondition.acquire() 949 x = self.getScrollRegion()[2] 950 y = self.getScrollRegion()[3] 951 bridge.append([self.getCanvas().postscript(pagewidth = x, pageheight = y, rotate = landscape)]) 952 postscriptCondition.notifyAll() 953 postscriptCondition.release() 954 955 def canvas_create_styledOval(self, lineStyle, fillStyle, tags, x0, y0, x1, y1): 956 self.getCanvas().create_oval(x0, y0, x1, y1, fill=fillStyle.color(), outline = lineStyle.color(), width = lineStyle.thickness(), tags = tags) 957 958 def canvas_create_styledRectangle(self, lineStyle, fillStyle, tags, x0, y0, x1, y1): 959 lineType = lineStyle.lineType() 960 thickness = lineStyle.thickness() 961 962 if lineType == 'solid': 963 self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, tags = tags) 964 elif lineType == 'dot': 965 self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '.', tags = tags) 966 elif lineType == 'dash': 967 self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-', tags = tags) 968 elif lineType == 'dash-dot': 969 self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-.', tags = tags) 970 elif lineType == 'dash-dot-dot': 971 self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-..', tags = tags) 972 else: 973 raise RuntimeException() 974 975 def canvas_create_styledLine(self, lineStyle, tags, *points): 976 lineType = lineStyle.lineType() 977 thickness = lineStyle.thickness() 978 979 if lineType == 'solid': 980 self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, tags = tags) 981 elif lineType == 'dot': 982 self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, dash = '.', tags = tags) 983 elif lineType == 'dash': 984 self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, dash = '-', tags = tags) 985 elif lineType == 'dash-dot': 986 self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, dash = '-.', tags = tags) 987 elif lineType == 'dash-dot-dot': 988 self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, dash = '-..', tags = tags) 989 else: 990 raise RuntimeException() 991 992 def canvas_create_styledPolygon(self, lineStyle, fillStyle, tags, *points): 993 lineType = lineStyle.lineType() 994 thickness = lineStyle.thickness() 995 996 if lineType == 'solid': 997 self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, tags = tags) 998 elif lineType == 'dot': 999 self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '.', tags = tags) 1000 elif lineType == 'dash': 1001 self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-', tags = tags) 1002 elif lineType == 'dash-dot': 1003 self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-.', tags = tags) 1004 elif lineType == 'dash-dot-dot': 1005 self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-..', tags = tags) 1006 else: 1007 raise RuntimeException() 1008 1009 def canvas_create_styledMarker(self, markerStyle, tags, x, y): 1010 shape = markerStyle.shape() 1011 shapeSize = markerStyle._parameterData('size') 1012 shapeSizeCanvasX = self._convertToPixelX(shapeSize) 1013 shapeSizeCanvasY = self._convertToPixelY(shapeSize) 1014 1015 lineStyle = ILineStyle() 1016 lineStyle.setColor(markerStyle.color()) 1017 fillStyle = IFillStyle() 1018 fillStyle.setColor('') 1019 1020 if shape == '': 1021 return 1022 elif shape == 'circle': 1023 x0 = x - shapeSizeCanvasX / 2.0 1024 y0 = y - shapeSizeCanvasY / 2.0 1025 x1 = x0 + shapeSizeCanvasX 1026 y1 = y0 + shapeSizeCanvasY 1027 self.canvas_create_styledOval(lineStyle, fillStyle, tags, x0, y0, x1, y1) 1028 elif shape == 'square': 1029 x0 = x - shapeSizeCanvasX / 2.0 1030 y0 = y - shapeSizeCanvasY / 2.0 1031 x1 = x0 + shapeSizeCanvasX 1032 y1 = y0 + shapeSizeCanvasY 1033 self.canvas_create_styledRectangle(lineStyle, fillStyle, tags, x0, y0, x1, y1) 1034 elif shape == 'diamond': 1035 x0 = x 1036 y0 = y - shapeSizeCanvasY / 2.0 1037 x1 = x - shapeSizeCanvasX / 2.0 1038 y1 = y 1039 x2 = x 1040 y2 = y0 + shapeSizeCanvasY 1041 x3 = x1 + shapeSizeCanvasX 1042 y3 = y 1043 self.canvas_create_styledLine(lineStyle, tags, x0, y0, x1, y1, x2, y2, x3, y3, x0, y0) 1044 elif shape == 'triangle': 1045 sqrt3 = math.sqrt(3) 1046 x0 = x 1047 y0 = y - shapeSizeCanvasY / sqrt3 1048 x1 = x - shapeSizeCanvasX / 2.0 1049 y1 = y + shapeSizeCanvasY / sqrt3 / 2.0 1050 x2 = x1 + shapeSizeCanvasX 1051 y2 = y1 1052 self.canvas_create_styledLine(lineStyle, tags, x0, y0, x1, y1, x2, y2, x0, y0) 1053 elif shape == 'cross': 1054 x0 = x - shapeSizeCanvasX / 2.0 1055 y0 = y - shapeSizeCanvasY / 2.0 1056 x1 = x0 + shapeSizeCanvasX 1057 y1 = y0 + shapeSizeCanvasY 1058 self.canvas_create_styledLine(lineStyle, tags, x0, y0, x1, y1) 1059 self.canvas_create_styledLine(lineStyle, tags, x0, y1, x1, y0) 1060 1061 def canvas_create_styledText(self, textStyle, tags, x, y, textData, anchor): 1062 self.getCanvas().create_text(x, y, text = textData, fill = textStyle.color(), font = self._getFontTuple(textStyle), anchor = anchor, tags = tags) 1063 1064 def canvas_delete(self, *args1): 1065 self.getCanvas().delete(*args1) 1066 1067 def canvas_create_styledExponent(self, textStyle, tags, x, y, a, b, anchor, fontRatio, overOffsetRatio): 1068 canvas = self.getCanvas() 1069 widthSpacer = 1 1070 indexTextStyle = textStyle._createCopy() 1071 indexTextStyle.setFontSize(textStyle.fontSize() * fontRatio) 1072 fontDataBase = self._configureTkFont(self._canvasExponentBaseFont, textStyle) 1073 fontDataIndex = self._configureTkFont(self._canvasExponentIndexFont, indexTextStyle) 1074 widthBase = fontDataBase.measure(a) 1075 widthIndex = fontDataIndex.measure(b) 1076 widthAll = widthBase + widthIndex + widthSpacer 1077 heightBase = fontDataBase.metrics('linespace') 1078 heightIndex = fontDataIndex.metrics('linespace') 1079 heightAll = heightBase + heightIndex * overOffsetRatio 1080 heightCap = heightAll - heightBase 1081 textColor = textStyle.color() 1082 if anchor == N: 1083 xBase = x - widthAll / 2 1084 yBase = y + heightCap 1085 elif anchor == NE: 1086 xBase = x - widthAll 1087 yBase = y + heightCap 1088 elif anchor == E: 1089 xBase = x - widthAll 1090 yBase = y + heightAll / 2 - heightBase 1091 elif anchor == SE: 1092 xBase = x - widthAll 1093 yBase = y - heightBase 1094 elif anchor == S: 1095 xBase = x - widthAll / 2 1096 yBase = y - heightBase 1097 elif anchor == SW: 1098 xBase = x 1099 yBase = y - heightBase 1100 elif anchor == W: 1101 xBase = x 1102 yBase = y + heightAll / 2 - heightBase 1103 elif anchor == NW: 1104 xBase = x 1105 yBase = y + heightCap 1106 else: 1107 raise RuntimeException() 1108 xIndex = xBase + widthBase + widthSpacer 1109 yIndex = yBase - heightCap 1110 self.canvas_create_styledText(textStyle, tags, xBase, yBase, a, NW) 1111 self.canvas_create_styledText(indexTextStyle, tags, xIndex, yIndex, b, NW) 1112