""" Tableau has a couple of base classes for analyze viewers. """ from __future__ import absolute_import #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module. import __init__ from skeinforge_tools.analyze_plugins.analyze_utilities import zoom_in from skeinforge_tools.analyze_plugins.analyze_utilities import zoom_out from skeinforge_tools.skeinforge_utilities import euclidean from skeinforge_tools.skeinforge_utilities import gcodec from skeinforge_tools.skeinforge_utilities import settings import math import os __author__ = "Enrique Perez (perez_enrique@yahoo.com)" __date__ = "$Date: 2008/21/04 $" __license__ = "GPL 3.0" def getGeometricDifference( first, second ): "Get the geometric difference of the two numbers." return max( first, second ) / min( first, second ) def getGridHorizontalFrame( gridPosition ): "Get the grid horizontal object with a frame from the grid position." gridHorizontal = settings.GridHorizontal( 0, 0 ) gridHorizontal.master = settings.Tkinter.Frame( gridPosition.master, borderwidth = 1, padx = 3, relief = 'raised' ) gridHorizontal.master.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.E ) return gridHorizontal def getLengthMinusOneMinimumOne( elementList ): "Get the length of the length minus one, minimum one." return max( 1, len( elementList ) - 1 ) def getScrollbarCanvasPortion( scrollbar ): "Get the canvas portion of the scrollbar." scrollbarBeginEnd = scrollbar.get() return scrollbarBeginEnd[ 1 ] - scrollbarBeginEnd[ 0 ] def setStateNormalDisabled( active, widget ): "Set the state of the widget to normal if active and disabled if inactive." if active: widget.config( state = settings.Tkinter.NORMAL ) else: widget.config( state = settings.Tkinter.DISABLED ) class ColoredLine: "A colored index line." def __init__( self, begin, colorName, displayString, end, tagString ): "Set the color name and corners." self.begin = begin self.colorName = colorName self.displayString = displayString self.end = end self.tagString = tagString def __repr__( self ): "Get the string representation of this colored index line." return '%s, %s, %s, %s' % ( self.colorName, self.begin, self.end, self.tagString ) class ExportCanvasDialog: "A class to display the export canvas repository dialog." def addPluginToMenu( self, canvas, fileName, menu, name, suffix ): "Add the display command to the menu." self.canvas = canvas self.fileName = fileName self.name = name self.suffix = suffix menu.add_command( label = settings.getEachWordCapitalized( self.name ), command = self.display ) def display( self ): "Display the export canvas repository dialog." for repositoryDialog in settings.globalRepositoryDialogListTable: if repositoryDialog.repository.lowerName == self.name: repositoryDialog.setCanvasFileNameSuffix( self.canvas, self.skein.fileName, self.suffix ) settings.liftRepositoryDialogs( settings.globalRepositoryDialogListTable[ repositoryDialog ] ) return exportCanvasPluginsFolderPath = gcodec.getAbsoluteFolderPath( os.path.dirname( __file__ ), 'export_canvas_plugins' ) pluginModule = gcodec.getModuleWithDirectoryPath( exportCanvasPluginsFolderPath, self.name ) if pluginModule == None: return None pluginRepository = pluginModule.getNewRepository() pluginRepository.setCanvasFileNameSuffix( self.canvas, self.fileName, self.suffix ) settings.getDisplayedDialogFromConstructor( pluginRepository ) class TableauRepository: "The viewer base repository class." def addAnimation( self ): "Add the animation settings." self.frameList = settings.FrameList().getFromValue( 'Frame List', self, [] ) self.animationLineQuickening = settings.FloatSpinUpdate().getFromValue( 0.5, 'Animation Line Quickening (ratio):', self, 4.5, 1.0 ) self.animationSlideShowRate = settings.FloatSpinUpdate().getFromValue( 1.0, 'Animation Slide Show Rate (layers/second):', self, 5.0, 2.0 ) def addScaleScreenSlide( self ): "Add the scale, screen and slide show settings." self.scale = settings.FloatSpinNotOnMenu().getFromValue( 10.0, 'Scale (pixels per millimeter):', self, 50.0, 15.0 ) self.screenHorizontalInset = settings.IntSpin().getFromValue( 80, 'Screen Horizontal Inset (pixels):', self, 1000, 100 ) self.screenVerticalInset = settings.IntSpin().getFromValue( 120, 'Screen Vertical Inset (pixels):', self, 1000, 200 ) def setToDisplaySave( self, event = None ): "Set the setting values to the display, save the new values." for menuEntity in self.menuEntities: if menuEntity in self.archive: menuEntity.setToDisplay() settings.writeSettings( self ) class TableauWindow: def activateMouseModeTool( self ): "Activate the mouse mode tool." self.repository.setToDisplaySave() self.canvas.focus_set() self.createMouseModeTool() self.mouseTool.update() def addCanvasMenuRootScrollSkein( self, repository, skein, suffix, title ): "Add the canvas, menu bar, scroll bar, skein panes, tableau repository, root and skein." self.imagesDirectoryPath = os.path.join( settings.getSkeinforgeDirectoryPath(), 'images' ) self.movementTextID = None self.mouseInstantButtons = [] self.photoImages = {} self.repository = repository self.root = settings.Tkinter.Tk() self.gridPosition = settings.GridVertical( 0, 1 ) self.gridPosition.master = self.root self.root.title( os.path.basename( skein.fileName ) + ' - ' + title ) self.rulingExtent = 24 self.rulingTargetSeparation = 150.0 self.screenSize = skein.screenSize self.skein = skein self.skeinPanes = skein.skeinPanes self.suffix = suffix self.timerID = None repository.animationSlideShowRate.value = max( repository.animationSlideShowRate.value, 0.01 ) repository.animationSlideShowRate.value = min( repository.animationSlideShowRate.value, 85.0 ) repository.drawArrows.setUpdateFunction( self.setWindowToDisplaySaveUpdate ) repository.goAroundExtruderOffTravel.setUpdateFunction( self.setWindowToDisplaySavePhoenixUpdate ) repository.layerExtraSpan.setUpdateFunction( self.setWindowToDisplaySaveUpdate ) repository.widthOfSelectionThread.setUpdateFunction( self.setWindowToDisplaySaveUpdate ) repository.widthOfTravelThread.setUpdateFunction( self.setWindowToDisplaySaveUpdate ) repository.window = self for menuRadio in repository.mouseMode.menuRadios: fileName = menuRadio.name.lower() fileName = fileName.replace( ' ', '_' ) + '.ppm' menuRadio.mouseButton = self.getPhotoButtonGridIncrement( menuRadio.invoke, fileName, self.gridPosition ) self.gridPosition = settings.GridHorizontal( 1, 99 ) self.gridPosition.master = self.root self.xScrollbar = settings.HiddenScrollbar( self.root, orient = settings.Tkinter.HORIZONTAL ) self.xScrollbar.grid( row = 98, column = 2, columnspan = 96, sticky = settings.Tkinter.E + settings.Tkinter.W ) self.yScrollbar = settings.HiddenScrollbar( self.root ) self.yScrollbar.grid( row = 1, rowspan = 97, column = 99, sticky = settings.Tkinter.N + settings.Tkinter.S ) self.canvasHeight = min( int( skein.screenSize.imag ), self.root.winfo_screenheight() - repository.screenVerticalInset.value ) self.canvasWidth = min( int( skein.screenSize.real ), self.root.winfo_screenwidth() - repository.screenHorizontalInset.value ) scrollRegionBoundingBox = ( 0, 0, int( skein.screenSize.real ), int( skein.screenSize.imag ) ) self.canvas = settings.Tkinter.Canvas( self.root, highlightthickness = 3, width = self.canvasWidth, height = self.canvasHeight, scrollregion = scrollRegionBoundingBox ) self.canvas.grid( row = 1, rowspan = 97, column = 2, columnspan = 96, sticky = settings.Tkinter.E + settings.Tkinter.W + settings.Tkinter.N + settings.Tkinter.S ) self.fileHelpMenuBar = settings.FileHelpMenuBar( self.root ) self.exportMenu = settings.Tkinter.Menu( self.fileHelpMenuBar.fileMenu, tearoff = 0 ) self.fileHelpMenuBar.fileMenu.add_cascade( label = "Export", menu = self.exportMenu, underline = 0 ) exportCanvasPluginsFolderPath = gcodec.getAbsoluteFolderPath( os.path.dirname( __file__ ), 'export_canvas_plugins' ) exportCanvasPluginFileNames = gcodec.getPluginFileNamesFromDirectoryPath( exportCanvasPluginsFolderPath ) for exportCanvasPluginFileName in exportCanvasPluginFileNames: ExportCanvasDialog().addPluginToMenu( self.canvas, skein.fileName, self.exportMenu, exportCanvasPluginFileName, suffix ) self.fileHelpMenuBar.fileMenu.add_separator() self.fileHelpMenuBar.completeMenu( self.close, repository, self.save, self ) def addLayer( self, gridPosition ): "Add the layer frame items." self.diveButton = self.getPhotoButtonGridIncrement( self.dive, 'dive.ppm', gridPosition ) self.soarButton = self.getPhotoButtonGridIncrement( self.soar, 'soar.ppm', gridPosition ) gridPosition.increment() settings.Tkinter.Label( gridPosition.master, text = 'Layer:' ).grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) gridPosition.increment() self.limitIndex() self.layerEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.layerEntryReturnPressed, from_ = 0, increment = 1, to = getLengthMinusOneMinimumOne( self.skeinPanes ) ) self.layerEntry.bind( '', self.layerEntryReturnPressed ) self.layerEntry.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) def addLine( self, gridPosition ): "Add the line frame items." self.lineDiveButton = self.getPhotoButtonGridIncrement( self.lineDive, 'dive.ppm', gridPosition ) self.lineSoarButton = self.getPhotoButtonGridIncrement( self.lineSoar, 'soar.ppm', gridPosition ) gridPosition.increment() settings.Tkinter.Label( gridPosition.master, text = 'Line:' ).grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) gridPosition.increment() self.lineEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.lineEntryReturnPressed, from_ = 0, increment = 1, to = getLengthMinusOneMinimumOne( self.getColoredLines() ) ) self.lineEntry.bind( '', self.lineEntryReturnPressed ) self.lineEntry.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) def addMouseInstantTool( self, fileName, gridPosition, mouseInstantTool ): "Add the mouse instant tool and derived photo button." mouseInstantTool.getReset( self ) photoButton = self.getPhotoButtonGridIncrement( mouseInstantTool.click, fileName, gridPosition ) mouseInstantTool.mouseButton = photoButton self.mouseInstantButtons.append( photoButton ) def addMouseToolsBind( self ): "Add the mouse tool and bind button one clicked, button one released and motion." self.xScrollbar.config( command = self.relayXview ) self.yScrollbar.config( command = self.relayYview ) self.canvas[ 'xscrollcommand' ] = self.xScrollbar.set self.canvas[ 'yscrollcommand' ] = self.yScrollbar.set settings.CloseListener( self, self.destroyAllDialogWindows ).listenToWidget( self.canvas ) self.canvasScreenCenter = 0.5 * complex( float( self.canvasWidth ) / float( self.screenSize.real ), float( self.canvasHeight ) / float( self.screenSize.imag ) ) self.addPhotoImage( 'stop.ppm', self.gridPosition ) self.gridPosition.increment() self.addLayer( getGridHorizontalFrame( self.gridPosition ) ) self.gridPosition.increment() self.addLine( getGridHorizontalFrame( self.gridPosition ) ) self.gridPosition.increment() self.addScale( getGridHorizontalFrame( self.gridPosition ) ) self.gridPosition = settings.GridVertical( self.gridPosition.columnStart + 1, self.gridPosition.row ) self.gridPosition.master = self.root for name in self.repository.frameList.value: entity = self.getEntityFromName( name ) if entity != None: self.gridPosition.incrementGivenNumberOfColumns( 3 ) entity.addToDialog( getGridHorizontalFrame( self.gridPosition ) ) for menuRadio in self.repository.mouseMode.menuRadios: menuRadio.mouseTool = menuRadio.getNewMouseToolFunction().getReset( self ) self.mouseTool = menuRadio.mouseTool self.createMouseModeTool() self.canvas.bind( '', self.button1 ) self.canvas.bind( '', self.buttonRelease1 ) self.canvas.bind( '', self.keyPressDown ) self.canvas.bind( '', self.keyPressLeft ) self.canvas.bind( '', self.keyPressRight ) self.canvas.bind( '', self.keyPressUp ) self.canvas.bind( '', self.motion ) self.canvas.bind( '', self.keyPressReturn ) self.canvas.bind( '', self.shiftButtonRelease1 ) self.canvas.bind( '', self.shiftMotion ) self.layerEntry.bind( '', self.cancelTimer ) self.root.grid_columnconfigure( 44, weight = 1 ) self.root.grid_rowconfigure( 44, weight = 1 ) self.resetPeriodicButtonsText() self.repository.animationLineQuickening.setUpdateFunction( self.repository.setToDisplaySave ) self.repository.animationSlideShowRate.setUpdateFunction( self.repository.setToDisplaySave ) self.repository.screenHorizontalInset.setUpdateFunction( self.redisplayWindowUpdate ) self.repository.screenVerticalInset.setUpdateFunction( self.redisplayWindowUpdate ) rankZeroSeperation = self.getRulingSeparationWidthPixels( 0 ) zoom = self.rulingTargetSeparation / rankZeroSeperation self.rank = euclidean.getRank( zoom ) rankTop = self.rank + 1 seperationBottom = self.getRulingSeparationWidthPixels( self.rank ) seperationTop = self.getRulingSeparationWidthPixels( rankTop ) bottomDifference = getGeometricDifference( self.rulingTargetSeparation, seperationBottom ) topDifference = getGeometricDifference( self.rulingTargetSeparation, seperationTop ) if topDifference < bottomDifference: self.rank = rankTop self.rulingSeparationWidthMillimeters = euclidean.getIncrementFromRank( self.rank ) self.canvas.focus_set() def addPhotoImage( self, fileName, gridPosition ): "Get a PhotoImage button, grid the button and increment the grid position." photoImage = None try: photoImage = settings.Tkinter.PhotoImage( file = os.path.join( self.imagesDirectoryPath, fileName ), master = gridPosition.master ) except: print( 'Image %s was not found in the images directory, so a text button will be substituted.' % fileName ) untilDotFileName = gcodec.getUntilDot( fileName ) self.photoImages[ untilDotFileName ] = photoImage return untilDotFileName def addScale( self, gridPosition ): "Add the line frame items." self.addMouseInstantTool( 'zoom_out.ppm', gridPosition, zoom_out.getNewMouseTool() ) self.addMouseInstantTool( 'zoom_in.ppm', gridPosition, zoom_in.getNewMouseTool() ) gridPosition.increment() settings.Tkinter.Label( gridPosition.master, text = 'Scale:' ).grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) gridPosition.increment() self.scaleEntry = settings.Tkinter.Spinbox( gridPosition.master, command = self.scaleEntryReturnPressed, from_ = 10.0, increment = 5.0, to = 100.0 ) self.scaleEntry.bind( '', self.scaleEntryReturnPressed ) self.scaleEntry.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) def addSettingsMenuSetWindowGeometry( self, center ): "Add the settings menu, center the scroll region, update, and set the window geometry." self.settingsMenu = settings.Tkinter.Menu( self.fileHelpMenuBar.menuBar, tearoff = 0 ) self.fileHelpMenuBar.addMenuToMenuBar( "Settings", self.settingsMenu ) settings.addMenuEntitiesToMenuFrameable( self.settingsMenu, self.repository.menuEntities ) self.relayXview( settings.Tkinter.MOVETO, center.real - self.canvasScreenCenter.real ) self.relayYview( settings.Tkinter.MOVETO, center.imag - self.canvasScreenCenter.imag ) self.root.withdraw() self.root.update_idletasks() movedGeometryString = '%sx%s+%s' % ( self.root.winfo_reqwidth(), self.root.winfo_reqheight(), '0+0' ) self.root.geometry( movedGeometryString ) def button1( self, event ): "The button was clicked." self.mouseTool.button1( event ) def buttonRelease1( self, event ): "The button was released." self.mouseTool.buttonRelease1( event ) def cancelTimer( self, event = None ): "Cancel the timer and set it to none." if self.timerID != None: self.canvas.after_cancel ( self.timerID ) self.timerID = None def cancelTimerResetButtons( self ): "Cancel the timer and set it to none." self.cancelTimer() self.resetPeriodicButtonsText() def close( self, event = None ): "The dialog was closed." try: self.root.after( 1, self.root.destroy ) # to get around 'Font Helvetica -12 still in cache.' segmentation bug, instead of simply calling self.root.destroy() except: pass def createMouseModeTool( self ): "Create the mouse mode tool." self.destroyMouseToolRaiseMouseButtons() for menuRadio in self.repository.mouseMode.menuRadios: if menuRadio.value: self.mouseTool = menuRadio.mouseTool menuRadio.mouseButton[ 'relief' ] = settings.Tkinter.SUNKEN def destroyAllDialogWindows( self ): "Destroy all the dialog windows." settings.writeSettings( self.repository ) return for menuEntity in self.repository.menuEntities: lowerName = menuEntity.name.lower() if lowerName in settings.globalRepositoryDialogListTable: globalRepositoryDialogValues = settings.globalRepositoryDialogListTable[ lowerName ] for globalRepositoryDialogValue in globalRepositoryDialogValues: settings.quitWindow( globalRepositoryDialogValue.root ) def destroyMouseToolRaiseMouseButtons( self ): "Destroy the mouse tool and raise the mouse buttons." self.mouseTool.destroyEverything() for menuRadio in self.repository.mouseMode.menuRadios: menuRadio.mouseButton[ 'relief' ] = settings.Tkinter.RAISED for mouseInstantButton in self.mouseInstantButtons: mouseInstantButton[ 'relief' ] = settings.Tkinter.RAISED def dive( self ): "Dive, go down periodically." oldDiveButtonText = self.diveButton[ 'text' ] self.cancelTimerResetButtons() if oldDiveButtonText == 'stop': return self.diveCycle() def diveCycle( self ): "Start the dive cycle." self.cancelTimer() self.repository.layer.value -= 1 self.update() if self.repository.layer.value < 1: self.resetPeriodicButtonsText() return self.setButtonImageText( self.diveButton, 'stop' ) self.timerID = self.canvas.after( self.getSlideShowDelay(), self.diveCycle ) def getAnimationLineDelay( self, coloredLine ): "Get the animation line delay in milliseconds." # maybe later, add animation along line # nextLayerIndex = self.repository.layer.value # nextLineIndex = self.repository.line.value + 1 # coloredLinesLength = len( self.getColoredLines() ) # self.skein.feedRateMinute # if nextLineIndex >= coloredLinesLength: # if nextLayerIndex + 1 < len( self.skeinPanes ): # nextLayerIndex += 1 # nextLineIndex = 0 # else: # nextLineIndex = self.repository.line.value splitLine = gcodec.getSplitLineBeforeBracketSemicolon( coloredLine.displayString ) self.skein.feedRateMinute = gcodec.getFeedRateMinute( self.skein.feedRateMinute, splitLine ) feedRateSecond = self.skein.feedRateMinute / 60.0 coloredLineLength = abs( coloredLine.end - coloredLine.begin ) / self.repository.scale.value duration = coloredLineLength / feedRateSecond animationLineDelay = int( round( 1000.0 * duration / self.repository.animationLineQuickening.value ) ) return max( animationLineDelay, 1 ) def getDrawnLineText( self, location, tags, text ): "Get the line text drawn on the canvas." anchorTowardCenter = settings.Tkinter.N if location.imag > float( self.canvasHeight ) * 0.1: anchorTowardCenter = settings.Tkinter.S if location.real > float( self.canvasWidth ) * 0.7: anchorTowardCenter += settings.Tkinter.E else: anchorTowardCenter += settings.Tkinter.W return self.canvas.create_text( int( location.real ), int( location.imag ), anchor = anchorTowardCenter, tags = tags, text = text ) def getEntityFromName( self, name ): "Get the entity of the given name." for entity in self.repository.displayEntities: if entity.name == name: return entity return None def getPhotoButtonGridIncrement( self, commandFunction, fileName, gridPosition ): "Get a PhotoImage button, grid the button and increment the grid position." gridPosition.increment() untilDotFileName = self.addPhotoImage( fileName, gridPosition ) photoImage = self.photoImages[ untilDotFileName ] photoButton = settings.Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', command = commandFunction, text = untilDotFileName ) if photoImage != None: photoButton[ 'image' ] = photoImage photoButton.grid( row = gridPosition.row, column = gridPosition.column, sticky = settings.Tkinter.W ) return photoButton def getRoundedRulingText( self, extraDecimalPlaces, number ): "Get the rounded ruling text." rulingText = euclidean.getRoundedToDecimalPlacesString( extraDecimalPlaces - math.floor( math.log10( self.rulingSeparationWidthMillimeters ) ), number ) if self.rulingSeparationWidthMillimeters < .99: return rulingText if rulingText[ - len( '.0' ) : ] == '.0': return rulingText[ : - len( '.0' ) ] return rulingText def getRulingSeparationWidthPixels( self, rank ): "Get the separation width in pixels." return euclidean.getIncrementFromRank( rank ) * self.skein.scale def getScrollPaneCenter( self ): "Get the center of the scroll pane." return self.getScrollPaneFraction() + self.canvasScreenCenter def getScrollPaneFraction( self ): "Get the center of the scroll pane." return complex( self.xScrollbar.get()[ 0 ], self.yScrollbar.get()[ 0 ] ) def getSlideShowDelay( self ): "Get the slide show delay in milliseconds." slideShowDelay = int( round( 1000.0 / self.repository.animationSlideShowRate.value ) ) return max( slideShowDelay, 1 ) def getUpdateSkeinPanes( self ): "Get the update skein panes." layerPlusExtraSpan = self.repository.layer.value + self.repository.layerExtraSpan.value layersFrom = max( 0, min( self.repository.layer.value, layerPlusExtraSpan ) ) layersTo = min( len( self.skeinPanes ), max( self.repository.layer.value, layerPlusExtraSpan ) + 1 ) return self.skeinPanes[ layersFrom : layersTo ] def isLineBelowZeroSetLayer( self ): "Determine if the line index is below zero, and if so set the layer index." if self.repository.line.value >= 0: return False self.repository.line.value = 0 if self.repository.layer.value > 0: self.setLayerIndex( self.repository.layer.value - 1 ) return True return False def isLineBeyondListSetLayer( self ): "Determine if the line index is beyond the end of the list, and if so set the layer index." coloredLinesLength = len( self.getColoredLines() ) if self.repository.line.value < coloredLinesLength: return False self.repository.line.value = coloredLinesLength - 1 if self.repository.layer.value < len( self.skeinPanes ) - 1: self.setLayerIndex( self.repository.layer.value + 1 ) return True return False def keyPressDown( self, event ): "The down arrow was pressed." self.mouseTool.keyPressDown( event ) def keyPressLeft( self, event ): "The left arrow was pressed." self.mouseTool.keyPressLeft( event ) def keyPressReturn( self, event ): "The return key was pressed." self.mouseTool.keyPressReturn( event ) def keyPressRight( self, event ): "The right arrow was pressed." self.mouseTool.keyPressRight( event ) def keyPressUp( self, event ): "The up arrow was pressed." self.mouseTool.keyPressUp( event ) def layerEntryReturnPressed( self, event = None ): "The layer index entry return was pressed." self.setLayerIndex( int( self.layerEntry.get() ) ) def limitIndex( self ): "Limit the index so it is not below zero or above the top." self.repository.layer.value = max( 0, self.repository.layer.value ) self.repository.layer.value = min( len( self.skeinPanes ) - 1, self.repository.layer.value ) def limitIndexSetArrowMouseDeleteCanvas( self ): "Limit the index, set the arrow type, and delete all the canvas items." self.limitIndex() self.arrowType = None if self.repository.drawArrows.value: self.arrowType = 'last' self.canvas.delete( settings.Tkinter.ALL ) def lineEntryReturnPressed( self, event = None ): "The line index entry return was pressed." self.repository.line.value = int( self.lineEntry.get() ) if self.isLineBelowZeroSetLayer(): return if self.isLineBeyondListSetLayer(): return self.cancelTimerResetButtons() self.updateMouseToolIfSelection() self.setLineButtonsState() def lineDive( self ): "Line dive, go down periodically." oldLineDiveButtonText = self.lineDiveButton[ 'text' ] self.cancelTimerResetButtons() if oldLineDiveButtonText == 'stop': return self.lineDiveCycle() def lineDiveCycle( self ): "Start the line dive cycle." self.cancelTimer() self.repository.line.value -= 1 if self.repository.line.value < 0: self.repository.line.value = 0 if self.repository.layer.value == 0: self.resetPeriodicButtonsText() self.setLineButtonsState() return self.setLayerIndex( self.repository.layer.value - 1 ) else: self.updateMouseToolIfSelection() self.setLineButtonsState() self.setButtonImageText( self.lineDiveButton, 'stop' ) coloredLine = self.getColoredLines()[ self.repository.line.value ] self.timerID = self.canvas.after( self.getAnimationLineDelay( coloredLine ), self.lineDiveCycle ) def lineSoar( self ): "Line soar, go up periodically." oldLineSoarButtonText = self.lineSoarButton[ 'text' ] self.cancelTimerResetButtons() if oldLineSoarButtonText == 'stop': return self.lineSoarCycle() def lineSoarCycle( self ): "Start the line soar cycle." self.cancelTimer() self.repository.line.value += 1 coloredLinesLength = len( self.getColoredLines() ) if self.repository.line.value >= coloredLinesLength: self.repository.line.value = coloredLinesLength - 1 if self.repository.layer.value > len( self.skeinPanes ) - 2: self.resetPeriodicButtonsText() self.setLineButtonsState() return self.setLayerIndex( self.repository.layer.value + 1 ) else: self.updateMouseToolIfSelection() self.setLineButtonsState() self.setButtonImageText( self.lineSoarButton, 'stop' ) coloredLine = self.getColoredLines()[ self.repository.line.value ] self.timerID = self.canvas.after( self.getAnimationLineDelay( coloredLine ), self.lineSoarCycle ) def motion( self, event ): "The mouse moved." self.mouseTool.motion( event ) def phoenixUpdate( self ): "Update the skein, and deiconify a new window and destroy the old." self.updateNewDestroyOld( self.getScrollPaneCenter() ) def relayXview( self, *args ): "Relay xview changes." self.canvas.xview( *args ) def relayYview( self, *args ): "Relay yview changes." self.canvas.yview( *args ) def resetPeriodicButtonsText( self ): "Reset the text of the periodic buttons." self.setButtonImageText( self.diveButton, 'dive' ) self.setButtonImageText( self.soarButton, 'soar' ) self.setButtonImageText( self.lineDiveButton, 'dive' ) self.setButtonImageText( self.lineSoarButton, 'soar' ) def redisplayWindowUpdate( self, event = None ): "Deiconify a new window and destroy the old." self.repository.setToDisplaySave() self.getCopy().updateDeiconify( self.getScrollPaneCenter() ) self.root.after( 1, self.root.destroy ) # to get around 'Font Helvetica -12 still in cache.' segmentation bug, instead of simply calling self.root.destroy() def save( self ): "Set the setting values to the display, save the new values." for menuEntity in self.repository.menuEntities: if menuEntity in self.repository.archive: menuEntity.setToDisplay() self.setInsetToDisplay() settings.writeSettings( self.repository ) def scaleEntryReturnPressed( self, event = None ): "The scale entry return was pressed." self.repository.scale.value = float( self.scaleEntry.get() ) self.phoenixUpdate() def setButtonImageText( self, button, text ): "Set the text of the e periodic buttons." photoImage = self.photoImages[ text ] if photoImage != None: button[ 'image' ] = photoImage button[ 'text' ] = text def setDisplayLayerIndex( self ): "Set the display of the layer index entry field and buttons." coloredLines = self.getColoredLines() isAboveFloor = self.repository.layer.value > 0 isBelowCeiling = self.repository.layer.value < len( self.skeinPanes ) - 1 setStateNormalDisabled( isAboveFloor, self.diveButton ) setStateNormalDisabled( isBelowCeiling, self.soarButton ) self.setLineButtonsState() settings.setEntryText( self.layerEntry, self.repository.layer.value ) settings.setEntryText( self.lineEntry, self.repository.line.value ) settings.setEntryText( self.scaleEntry, self.repository.scale.value ) self.mouseTool.update() self.setInsetToDisplay() def setInsetToDisplay( self ): "Set the archive to the display." if self.root.state() != 'normal': return xScrollbarCanvasPortion = getScrollbarCanvasPortion( self.xScrollbar ) newScreenHorizontalInset = int( self.root.winfo_screenwidth() - round( xScrollbarCanvasPortion * self.skein.screenSize.real ) ) if xScrollbarCanvasPortion < .99: self.repository.screenHorizontalInset.value = newScreenHorizontalInset else: self.repository.screenHorizontalInset.value = min( self.repository.screenHorizontalInset.value, newScreenHorizontalInset ) yScrollbarCanvasPortion = getScrollbarCanvasPortion( self.yScrollbar ) newScreenVerticalInset = int( self.root.winfo_screenheight() - round( yScrollbarCanvasPortion * self.skein.screenSize.imag ) ) if yScrollbarCanvasPortion < .99: self.repository.screenVerticalInset.value = newScreenVerticalInset else: self.repository.screenVerticalInset.value = min( self.repository.screenVerticalInset.value, newScreenVerticalInset ) def setLayerIndex( self, layerIndex ): "Set the layer index." self.cancelTimerResetButtons() oldLayerIndex = self.repository.layer.value self.repository.layer.value = layerIndex self.limitIndex() coloredLines = self.getColoredLines() if self.repository.layer.value < oldLayerIndex: self.repository.line.value = len( coloredLines ) - 1 self.lineEntry[ 'to' ] = getLengthMinusOneMinimumOne( coloredLines ) if self.repository.layer.value > oldLayerIndex: self.repository.line.value = 0 self.lineEntry[ 'to' ] = getLengthMinusOneMinimumOne( coloredLines ) self.update() def setLineButtonsState( self ): "Set the state of the line buttons." coloredLines = self.getColoredLines() isAboveFloor = self.repository.layer.value > 0 isBelowCeiling = self.repository.layer.value < len( self.skeinPanes ) - 1 setStateNormalDisabled( isAboveFloor or self.repository.line.value > 0, self.lineDiveButton ) setStateNormalDisabled( isBelowCeiling or self.repository.line.value < len( coloredLines ) - 1, self.lineSoarButton ) def setWindowNewMouseTool( self, getNewMouseToolFunction, mouseTool ): "Set the getNewMouseTool function and the update function." mouseTool.getNewMouseToolFunction = getNewMouseToolFunction mouseTool.setUpdateFunction( self.activateMouseModeTool ) def setWindowToDisplaySavePhoenixUpdate( self, event = None ): "Set the setting values to the display, save the new values, then call the update function." self.repository.setToDisplaySave() self.phoenixUpdate() def setWindowToDisplaySaveUpdate( self, event = None ): "Set the setting values to the display, save the new values, then call the update function." self.repository.setToDisplaySave() self.update() def shiftButtonRelease1( self, event ): "The button was released while the shift key was pressed." self.mouseTool.buttonRelease1( event, True ) def shiftMotion( self, event ): "The mouse moved." self.mouseTool.motion( event, True ) def soar( self ): "Soar, go up periodically." oldSoarButtonText = self.soarButton[ 'text' ] self.cancelTimerResetButtons() if oldSoarButtonText == 'stop': return self.soarCycle() def soarCycle( self ): "Start the soar cycle." self.cancelTimer() self.repository.layer.value += 1 self.update() if self.repository.layer.value > len( self.skeinPanes ) - 2: self.resetPeriodicButtonsText() return self.setButtonImageText( self.soarButton, 'stop' ) self.timerID = self.canvas.after( self.getSlideShowDelay(), self.soarCycle ) def updateDeiconify( self, center = complex( 0.5, 0.5 ) ): "Update and deiconify the window." self.addSettingsMenuSetWindowGeometry( center ) self.update() self.root.deiconify() def updateMouseToolIfSelection( self ): "Update the mouse tool if it is a selection tool." if self.mouseTool == None: return if self.mouseTool.isSelectionTool(): self.mouseTool.update() def updateNewDestroyOld( self, scrollPaneCenter ): "Update and deiconify a window and destroy the old." self.getCopyWithNewSkein().updateDeiconify( scrollPaneCenter ) self.root.after( 1, self.root.destroy ) # to get around 'Font Helvetica -12 still in cache.' segmentation bug, instead of simply calling self.root.destroy()