def addCanvasMenuRootScrollSkein(self, repository, skein, suffix, title):
		'Add the canvas, menu bar, scroll bar, skein panes, tableau repository, root and skein.'
		self.imagesDirectoryPath = archive.getFabmetheusUtilitiesPath('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.highlightThickness = 3
		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.showGcode.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(2, 99)
		self.gridPosition.master = self.root
		self.gcodeStringVar = settings.Tkinter.StringVar(self.root)
		self.gcodeLabel = settings.Tkinter.Label(self.root, anchor = settings.Tkinter.W, textvariable = self.gcodeStringVar)
		self.gcodeLabel.grid(row = 0, column = 5, columnspan = 93, sticky = settings.Tkinter.W)
		from fabmetheus_utilities.hidden_scrollbar import HiddenScrollbar
		self.xScrollbar = 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 = HiddenScrollbar(self.root)
		self.yScrollbar.grid(row = 2, rowspan = 96, column = 99, sticky = settings.Tkinter.N + settings.Tkinter.S)
		self.canvasHeight = self.root.winfo_screenheight() - repository.screenVerticalInset.value
		self.canvasWidth = 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 = self.highlightThickness, width = self.canvasWidth, height = self.canvasHeight, scrollregion = scrollRegionBoundingBox)
		self.canvas.grid(row = 2, rowspan = 96, 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 = archive.getAbsoluteFolderPath(os.path.dirname(__file__), 'export_canvas_plugins')
		exportCanvasPluginFileNames = archive.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 addToDialog( self, gridPosition ):
		"Add this to the dialog."
#http://www.pythonware.com/library/tkinter/introduction/x5453-patterns.htm
		self.root = gridPosition.master
		gridPosition.increment()
		scrollbar = HiddenScrollbar( gridPosition.master )
		self.listbox = settings.Tkinter.Listbox( gridPosition.master, selectmode = settings.Tkinter.SINGLE, yscrollcommand = scrollbar.set )
		self.listbox.bind( '<ButtonRelease-1>', self.buttonReleaseOne )
		gridPosition.master.bind( '<FocusIn>', self.focusIn )
		scrollbar.config( command = self.listbox.yview )
		self.listbox.grid( row = gridPosition.row, column = 0, sticky = settings.Tkinter.N + settings.Tkinter.S )
		scrollbar.grid( row = gridPosition.row, column = 1, sticky = settings.Tkinter.N + settings.Tkinter.S )
		self.setStateToValue()
		self.repository.saveListenerTable[ 'updateProfileSaveListeners' ] = updateProfileSaveListeners
Esempio n. 3
0
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 = settings.getPathInFabmetheus(os.path.join("fabmetheus_utilities", "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 = 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 = 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("<Return>", 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("<Return>", 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("<Button-1>", self.button1)
        self.canvas.bind("<ButtonRelease-1>", self.buttonRelease1)
        self.canvas.bind("<KeyPress-Down>", self.keyPressDown)
        self.canvas.bind("<KeyPress-Left>", self.keyPressLeft)
        self.canvas.bind("<KeyPress-Right>", self.keyPressRight)
        self.canvas.bind("<KeyPress-Up>", self.keyPressUp)
        self.canvas.bind("<Motion>", self.motion)
        self.canvas.bind("<Return>", self.keyPressReturn)
        self.canvas.bind("<Shift-ButtonRelease-1>", self.shiftButtonRelease1)
        self.canvas.bind("<Shift-Motion>", self.shiftMotion)
        self.layerEntry.bind("<Destroy>", 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("<Return>", 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 < 0.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
        excessExtent = int(self.xScrollbar["width"]) * 21 / 15
        screenSize = self.skein.screenSize
        xScrollbarCanvasPortion = getScrollbarCanvasPortion(self.xScrollbar)
        newScreenHorizontalInset = int(
            self.root.winfo_screenwidth() - round(xScrollbarCanvasPortion * screenSize.real) + excessExtent
        )
        if xScrollbarCanvasPortion < 0.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 * screenSize.imag) + excessExtent
        )
        if yScrollbarCanvasPortion < 0.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()
Esempio n. 4
0
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 = archive.getFabmetheusUtilitiesPath('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.highlightThickness = 3
        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.showGcode.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(2, 99)
        self.gridPosition.master = self.root
        self.gcodeStringVar = settings.Tkinter.StringVar(self.root)
        self.gcodeLabel = settings.Tkinter.Label(
            self.root,
            anchor=settings.Tkinter.W,
            textvariable=self.gcodeStringVar)
        self.gcodeLabel.grid(row=0,
                             column=5,
                             columnspan=93,
                             sticky=settings.Tkinter.W)
        from fabmetheus_utilities.hidden_scrollbar import HiddenScrollbar
        self.xScrollbar = 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 = HiddenScrollbar(self.root)
        self.yScrollbar.grid(row=2,
                             rowspan=96,
                             column=99,
                             sticky=settings.Tkinter.N + settings.Tkinter.S)
        self.canvasHeight = self.root.winfo_screenheight(
        ) - repository.screenVerticalInset.value
        self.canvasWidth = 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=self.highlightThickness,
            width=self.canvasWidth,
            height=self.canvasHeight,
            scrollregion=scrollRegionBoundingBox)
        self.canvas.grid(row=2,
                         rowspan=96,
                         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)
        exportCanvasPluginFileNames = archive.getPluginFileNamesFromDirectoryPath(
            getPluginsDirectoryPath())
        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('<Return>', 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('<Return>', 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('<Button-1>', self.button1)
        self.canvas.bind('<ButtonRelease-1>', self.buttonRelease1)
        self.canvas.bind('<Configure>', self.setInsetToCanvas)
        self.canvas.bind('<KeyPress-Down>', self.keyPressDown)
        self.canvas.bind('<KeyPress-Left>', self.keyPressLeft)
        self.canvas.bind('<KeyPress-Right>', self.keyPressRight)
        self.canvas.bind('<KeyPress-Up>', self.keyPressUp)
        self.canvas.bind('<Motion>', self.motion)
        self.canvas.bind('<Return>', self.keyPressReturn)
        self.canvas.bind('<Shift-ButtonRelease-1>', self.shiftButtonRelease1)
        self.canvas.bind('<Shift-Motion>', self.shiftMotion)
        self.layerEntry.bind('<Destroy>', 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 = archive.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('<Return>', 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 cancel(self, event=None):
        'Set all entities to their saved state.'
        settings.cancelRepository(self.repository)

    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.setLayerIndex(self.repository.layer.value - 1)
        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.'
        if not self.repository.showGcode.value:
            return
        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.getRoundedToPlacesString(
            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 scroll pane top left.'
        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 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 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 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 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 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 save(self):
        'Set the setting values to the display, save the new values.'
        for menuEntity in self.repository.menuEntities:
            if menuEntity in self.repository.preferences:
                menuEntity.setToDisplay()
        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()

    def setInsetToCanvas(self, event=None):
        'Set the repository insets to the canvas.'
        if self.root.state() != 'normal':
            return
        excessExtent = self.highlightThickness + self.highlightThickness
        screenHorizontalInset = self.repository.screenHorizontalInset
        screenVerticalInset = self.repository.screenVerticalInset
        oldHorizontalValue = screenHorizontalInset.value
        oldVerticalValue = screenVerticalInset.value
        screenHorizontalInset.value = self.root.winfo_screenwidth(
        ) - self.canvas.winfo_width() + excessExtent
        if not self.yScrollbar.visible:
            screenHorizontalInset.value += self.yScrollbar.winfo_reqwidth()
        screenHorizontalInset.setStateToValue()
        screenVerticalInset.value = self.root.winfo_screenheight(
        ) - self.canvas.winfo_height() + excessExtent
        if not self.xScrollbar.visible:
            screenVerticalInset.value += self.xScrollbar.winfo_reqheight()
        screenVerticalInset.setStateToValue()
        if oldHorizontalValue != screenHorizontalInset.value or oldVerticalValue != screenVerticalInset.value:
            self.repository.setToDisplaySave()

    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()
        if len(coloredLines) < 1:
            print(
                'Warning, there are no coloredLines in setLineButtonsState in tableau for the layer:'
            )
            print(self.repository.layer.value)
            return
        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)
        self.repository.line.value = max(self.repository.line.value, 0)
        self.repository.line.value = min(self.repository.line.value,
                                         len(coloredLines) - 1)
        gcodeString = ''
        if self.repository.showGcode.value:
            gcodeString = 'Gcode: ' + coloredLines[
                self.repository.line.value].displayString
        self.gcodeStringVar.set(gcodeString)
        self.canvas.delete('selection_line')
        self.getDrawnSelectedColoredLine(
            coloredLines[self.repository.line.value])
        settings.setEntryText(self.lineEntry, self.repository.line.value)

    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.setLayerIndex(self.repository.layer.value + 1)
        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()
Esempio n. 5
0
 def addCanvasMenuRootScrollSkein(self, repository, skein, suffix, title):
     "Add the canvas, menu bar, scroll bar, skein panes, tableau repository, root and skein."
     self.imagesDirectoryPath = archive.getFabmetheusUtilitiesPath('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 = 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 = 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 = archive.getAbsoluteFolderPath(
         os.path.dirname(__file__), 'export_canvas_plugins')
     exportCanvasPluginFileNames = archive.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)