diff --git a/AutoTowersGenerator.py b/AutoTowersGenerator.py index 70f0a96..c65eae9 100644 --- a/AutoTowersGenerator.py +++ b/AutoTowersGenerator.py @@ -1,6 +1,6 @@ +from functools import cached_property import glob import os -import platform import traceback # Import the correct version of PyQt @@ -81,7 +81,7 @@ def __init__(self): - @property + @cached_property def _pluginDir(self)->str: ''' Returns the path to the plugin directory ''' @@ -89,7 +89,7 @@ def _pluginDir(self)->str: - @property + @cached_property def _openScadSourcePath(self)->str: ''' Returns the path to the OpenSCAD source models''' @@ -97,7 +97,7 @@ def _openScadSourcePath(self)->str: - @property + @cached_property def _qmlDir(self)->str: ''' Returns the location of the QML dialog files directory ''' @@ -105,7 +105,7 @@ def _qmlDir(self)->str: - @property + @cached_property def _stlDir(self)->str: ''' Returns the directory where STL files are stored ''' @@ -113,7 +113,7 @@ def _stlDir(self)->str: - @property + @cached_property def _tempDir(self)->str: ''' Returns the directory to use for temporary files ''' @@ -121,7 +121,7 @@ def _tempDir(self)->str: - @property + @cached_property def _pluginSettingsFilePath(self)->str: ''' Returns the path to the plugin settings file ''' @@ -129,64 +129,57 @@ def _pluginSettingsFilePath(self)->str: - _cachedRemoveModelsButton = None - - @property + @cached_property def _removeAutoTowerButton(self)->QObject: ''' Returns the button used to remove the Auto Tower from the scene ''' - if self._cachedRemoveModelsButton is None: - self._cachedRemoveModelsButton = self._createDialog('RemoveModelsButton.qml') - return self._cachedRemoveModelsButton - + return self._createDialog('RemoveModelsButton.qml') - _cachedPluginSettingsDialog = None - @property + @cached_property def _pluginSettingsDialog(self)->QObject: ''' Returns the settings dialog ''' - if self._cachedPluginSettingsDialog is None: - self._cachedPluginSettingsDialog = self._createDialog('PluginSettingsDialog.qml') - return self._cachedPluginSettingsDialog + return self._createDialog('PluginSettingsDialog.qml') - _cachedSettingsVerificationDialog = None - - @property + @cached_property def _settingsVerificationDialog(self)->QObject: ''' Returns a dialog asking the user whether they want to continue with incompatible settings ''' - if self._cachedSettingsVerificationDialog is None: - self._cachedSettingsVerificationDialog = self._createDialog('SettingsVerificationDialog.qml') - return self._cachedSettingsVerificationDialog - + return self._createDialog('SettingsVerificationDialog.qml') - _cachedWaitDialog = None - - @property + @cached_property def _waitDialog(self)->QObject: ''' Returns the dialog used to tell the user that generating a model may take a long time ''' - if self._cachedWaitDialog is None: - self._cachedWaitDialog = self._createDialog('WaitDialog.qml') - return self._cachedWaitDialog + return self._createDialog('WaitDialog.qml') - _cachedOpenScadInterface = None - @property + @cached_property def _openScadInterface(self)->OpenScadInterface: ''' Provides lazy instantiation of the OpenScad interface ''' - if self._cachedOpenScadInterface is None: - self._cachedOpenScadInterface = OpenScadInterface(self._pluginName, self._tempDir) + return OpenScadInterface(self._pluginName, self._tempDir) + + + + @cached_property + def _gcodeProcessedMarker(self)->str: + return f';{self._pluginName}: Post-processed by {self._pluginName} version {self.pluginVersion}' - return self._cachedOpenScadInterface + + + @cached_property + def _pluginName(self)->str: + ''' Just a useless wrapper around getPluginId ''' + + return self.getPluginId() @@ -196,14 +189,6 @@ def autoTowerGenerated(self)->bool: ''' Used to show or hide the button for removing the generated Auto Tower ''' return not self._autoTowerOperation is None - - - - @property - def _pluginName(self)->str: - ''' Returns the plugin's name ''' - - return self.getPluginId() @@ -233,6 +218,8 @@ def setOpenScadPathSetting(self, value)->None: self._openScadPathSettingChanged.emit() + + @pyqtProperty(str, notify=_openScadPathSettingChanged, fset=setOpenScadPathSetting) def openScadPathSetting(self)->str: # If the OpenSCAD path has not been set, use the default from the OpenSCAD interface @@ -272,6 +259,7 @@ def enableLcdMessagesSetting(self)->bool: return self._pluginSettings.GetValue('enable lcd messages', False) + _enableAdvancedGcodeCommentsSetting = True _enableAdvancedGcodeCommentsSettingChanged = pyqtSignal() @@ -284,6 +272,21 @@ def setAdvancedGcodeCommentsSetting(self, value:bool)->None: def enableAdvancedGcodeCommentsSetting(self)->bool: return self._pluginSettings.GetValue('advanced gcode comments', True) + + _enableDescriptiveFileNamesSetting = True + + _enableDescriptiveFileNamesSettingChanged = pyqtSignal() + + def setEnableDescriptiveFileNamesSetting(self, value:bool)->None: + self._pluginSettings.SetValue('descriptive file names', value) + self._enableDescriptiveFileNamesSettingChanged.emit() + + @pyqtProperty(bool, notify=_enableDescriptiveFileNamesSettingChanged, fset=setEnableDescriptiveFileNamesSetting) + def enableDescriptiveFileNamesSetting(self)->bool: + return self._pluginSettings.GetValue('descriptive file names', True) + + + @pyqtSlot() def removeButtonClicked(self)->None: ''' Called when the remove button is clicked to remove the generated Auto Tower from the scene''' @@ -472,6 +475,25 @@ def _importStl(self, controller, towerName, stlFilePath, postProcessingCallback) # The dialog is no longer needed self._waitDialog.hide() + # Some printers cannot handle long, descriptive file names + # If descriptive file names have been disabled, truncate the tower name + # Google suggests 20 characters to be a safe limit + # Ideally, truncation should happen when the tower name is first + # generated by the tower controller, but that involves a lot of changes + # This is lazy but effective + if self.enableDescriptiveFileNamesSetting == False: + towerName = towerName.replace('Preset ', '') + towerName = towerName.replace('Custom', '') + towerName = towerName.replace('Tower', '') + towerName = towerName.replace('Bed Level Pattern', 'LVL') + towerName = towerName.replace('Distance', 'DST') + towerName = towerName.replace('Flow', 'FLW') + towerName = towerName.replace('Retraction', 'RT') + towerName = towerName.replace('Speed', 'SPD') + towerName = towerName.replace('Temp', 'TMP') + towerName = towerName.replace(' ', '') + towerName = towerName[:20] + # Rename the print job CuraApplication.getInstance().getPrintInformation().setJobName(towerName) @@ -596,14 +618,12 @@ def _postProcessCallback(self, output_device)->None: # If there is no g-code for the current build plate, there's nothing more to do return - try: - gcodeProcessedMarker = f';{self._pluginName}: Post-processed by {self._pluginName} version {self.pluginVersion}' - + try: # Proceed if the g-code has not already been post-processed - if gcodeProcessedMarker not in gcode[0]: + if self._gcodeProcessedMarker not in gcode[0]: # Mark the g-code as having been post-processed - gcode[0] += gcodeProcessedMarker + '\n' + gcode[0] += self._gcodeProcessedMarker + '\n' # Call the tower controller post-processing callback to modify the g-code try: diff --git a/Controllers/FanTowerController.py b/Controllers/FanTowerController.py index 4ad57bc..b07dabe 100644 --- a/Controllers/FanTowerController.py +++ b/Controllers/FanTowerController.py @@ -126,7 +126,7 @@ def _generateCustomFanTower(self)->None: } # Determine the tower name - towerName = f'Custom Fan Tower - Fan Speed {startFanPercent}-{endFanPercent}x{fanPercentChange}' + towerName = f'Custom Fan Tower - Speed {startFanPercent}-{endFanPercent}x{fanPercentChange}' # Send the filename and parameters to the STL generation callback self._generateStlCallback(self, towerName, openScadFilename, openScadParameters, self.postProcess) diff --git a/Models/FanTowerModel.py b/Models/FanTowerModel.py index dcfc503..2c3c37f 100644 --- a/Models/FanTowerModel.py +++ b/Models/FanTowerModel.py @@ -21,7 +21,7 @@ class FanTowerModel(ModelBase): # The available fan tower presets _presetsTable = [ - {'name': catalog.i18nc("@model", "Fan Tower - 0-100%") , 'filename': 'Fan Tower - Fan 0-100.stl', 'start percent': '0', 'percent change': '20',} + {'name': catalog.i18nc("@model", "Fan Tower - 0-100%") , 'filename': 'Fan Tower - 0-100.stl', 'start percent': '0', 'percent change': '20',} ] diff --git a/Models/FlowTowerModel.py b/Models/FlowTowerModel.py index fb0d898..6a7c549 100644 --- a/Models/FlowTowerModel.py +++ b/Models/FlowTowerModel.py @@ -21,8 +21,8 @@ class FlowTowerModel(ModelBase): # The available flow tower presets _presetsTable = [ - {'name': catalog.i18nc("@model", "Flow Tower - Flow 115-85") , 'filename': 'Flow Tower - Flow 115-85.stl', 'icon': 'flowtower_icon.png', 'start flow': '115', 'flow change': '-5', 'tower design': 'Standard'}, - {'name': catalog.i18nc("@model", "Flow Tower (Spiral) - Flow 115-85") , 'filename': 'Flow Tower Spiral - Flow 115-85.stl', 'icon': 'spiral_flowtower_icon.png', 'start flow': '115', 'flow change': '-5', 'tower design': 'Spiral'}, + {'name': catalog.i18nc("@model", "Flow Tower - Flow 115-85") , 'filename': 'Flow Tower - 115-85.stl', 'icon': 'flowtower_icon.png', 'start flow': '115', 'flow change': '-5', 'tower design': 'Standard'}, + {'name': catalog.i18nc("@model", "Flow Tower (Spiral) - 115-85") , 'filename': 'Flow Tower Spiral - Flow 115-85.stl', 'icon': 'spiral_flowtower_icon.png', 'start flow': '115', 'flow change': '-5', 'tower design': 'Spiral'}, ] # The available flow tower designs diff --git a/Models/RetractTowerModel.py b/Models/RetractTowerModel.py index 3dfd17a..274c411 100644 --- a/Models/RetractTowerModel.py +++ b/Models/RetractTowerModel.py @@ -21,14 +21,14 @@ class RetractTowerModel(ModelBase): # The available retract tower presets _presetsTable = [ - {'name': catalog.i18nc("@model", "Retract Tower - Retract Distance 0.4-1.2") , 'filename': 'Retract Tower - Retract Distance 0.4-1.2.stl', 'start value': '0.4', 'value change': '0.1', 'tower type': 'Distance'}, - {'name': catalog.i18nc("@model", "Retract Tower - Retract Distance 1.2-2.0") , 'filename': 'Retract Tower - Retract Distance 1.2-2.0.stl', 'start value': '1.2', 'value change': '0.1', 'tower type': 'Distance'}, - {'name': catalog.i18nc("@model", "Retract Tower - Retract Distance 1-6") , 'filename': 'Retract Tower - Retract Distance 1-6.stl', 'start value': '1', 'value change': '1', 'tower type': 'Distance'}, - {'name': catalog.i18nc("@model", "Retract Tower - Retract Distance 4-9") , 'filename': 'Retract Tower - Retract Distance 4-9.stl', 'start value': '4', 'value change': '1', 'tower type': 'Distance'}, - {'name': catalog.i18nc("@model", "Retract Tower - Retract Distance 7-12") , 'filename': 'Retract Tower - Retract Distance 7-12.stl', 'start value': '7', 'value change': '1', 'tower type': 'Distance'}, - {'name': catalog.i18nc("@model", "Retract Tower - Retract Speed 10-50") , 'filename': 'Retract Tower - Retract Speed 10-50.stl', 'start value': '10', 'value change': '10', 'tower type': 'Speed'}, - {'name': catalog.i18nc("@model", "Retract Tower - Retract Speed 35-75") , 'filename': 'Retract Tower - Retract Speed 35-75.stl', 'start value': '35', 'value change': '10', 'tower type': 'Speed'}, - {'name': catalog.i18nc("@model", "Retract Tower - Retract Speed 60-100") , 'filename': 'Retract Tower - Retract Speed 60-100.stl', 'start value': '60', 'value change': '10', 'tower type': 'Speed'}, + {'name': catalog.i18nc("@model", "Retract Tower - Distance 0.4-1.2") , 'filename': 'Retract Tower - Retract Distance 0.4-1.2.stl', 'start value': '0.4', 'value change': '0.1', 'tower type': 'Distance'}, + {'name': catalog.i18nc("@model", "Retract Tower - Distance 1.2-2.0") , 'filename': 'Retract Tower - Retract Distance 1.2-2.0.stl', 'start value': '1.2', 'value change': '0.1', 'tower type': 'Distance'}, + {'name': catalog.i18nc("@model", "Retract Tower - Distance 1-6") , 'filename': 'Retract Tower - Retract Distance 1-6.stl', 'start value': '1', 'value change': '1', 'tower type': 'Distance'}, + {'name': catalog.i18nc("@model", "Retract Tower - Distance 4-9") , 'filename': 'Retract Tower - Retract Distance 4-9.stl', 'start value': '4', 'value change': '1', 'tower type': 'Distance'}, + {'name': catalog.i18nc("@model", "Retract Tower - Distance 7-12") , 'filename': 'Retract Tower - Retract Distance 7-12.stl', 'start value': '7', 'value change': '1', 'tower type': 'Distance'}, + {'name': catalog.i18nc("@model", "Retract Tower - Speed 10-50") , 'filename': 'Retract Tower - Retract Speed 10-50.stl', 'start value': '10', 'value change': '10', 'tower type': 'Speed'}, + {'name': catalog.i18nc("@model", "Retract Tower - Speed 35-75") , 'filename': 'Retract Tower - Retract Speed 35-75.stl', 'start value': '35', 'value change': '10', 'tower type': 'Speed'}, + {'name': catalog.i18nc("@model", "Retract Tower - Speed 60-100") , 'filename': 'Retract Tower - Retract Speed 60-100.stl', 'start value': '60', 'value change': '10', 'tower type': 'Speed'}, ] _towerTypesTable = [ diff --git a/Models/SpeedTowerModel.py b/Models/SpeedTowerModel.py index 529a60b..3ee2987 100644 --- a/Models/SpeedTowerModel.py +++ b/Models/SpeedTowerModel.py @@ -21,9 +21,9 @@ class SpeedTowerModel(ModelBase): # The available speed tower presets _presetsTable = [ - {'name': catalog.i18nc("@model", "Speed Tower - Print Speed 20-100"), 'filename': 'Speed Tower - Print Speed 20-100.stl', 'start speed': '20', 'speed change': '20', 'tower type': 'Print Speed'}, - {'name': catalog.i18nc("@model", "Speed Tower - Print Speed 50-150"), 'filename': 'Speed Tower - Print Speed 50-150.stl', 'start speed': '50', 'speed change': '20', 'tower type': 'Print Speed'}, - {'name': catalog.i18nc("@model", "Speed Tower - Print Speed 100-200"), 'filename': 'Speed Tower - Print Speed 100-200.stl', 'start speed': '100', 'speed change': '20', 'tower type': 'Print Speed'}, + {'name': catalog.i18nc("@model", "Speed Tower - 20-100"), 'filename': 'Speed Tower - Print Speed 20-100.stl', 'start speed': '20', 'speed change': '20', 'tower type': 'Print Speed'}, + {'name': catalog.i18nc("@model", "Speed Tower - 50-150"), 'filename': 'Speed Tower - Print Speed 50-150.stl', 'start speed': '50', 'speed change': '20', 'tower type': 'Print Speed'}, + {'name': catalog.i18nc("@model", "Speed Tower - 100-200"), 'filename': 'Speed Tower - Print Speed 100-200.stl', 'start speed': '100', 'speed change': '20', 'tower type': 'Print Speed'}, ] # The speed tower types that can been created diff --git a/Resources/QML/QT5/PluginSettingsDialog.qml b/Resources/QML/QT5/PluginSettingsDialog.qml index 5b511e0..1aed775 100644 --- a/Resources/QML/QT5/PluginSettingsDialog.qml +++ b/Resources/QML/QT5/PluginSettingsDialog.qml @@ -117,6 +117,16 @@ UM.Dialog { id: enableAdvancedGcodeComments checked: manager.enableAdvancedGcodeCommentsSetting + } + + Label + { + text: "Descriptive File Names" + } + CheckBox + { + id: enableDescriptiveFileNames + checked: manager.enableDescriptiveFileNamesSetting } } } @@ -138,6 +148,7 @@ UM.Dialog manager.openScadPathSetting = openScadPath.text manager.enableLcdMessagesSetting = enableLcdMessages.checked manager.enableAdvancedGcodeCommentsSetting = enableAdvancedGcodeComments.checked + manager.enableDescriptiveFileNamesSetting = enableDescriptiveFileNames.checked manager.correctPrintSettings = correctPrintSettings.checked } } diff --git a/Resources/QML/QT6/PluginSettingsDialog.qml b/Resources/QML/QT6/PluginSettingsDialog.qml index 6a4349a..ea4865d 100644 --- a/Resources/QML/QT6/PluginSettingsDialog.qml +++ b/Resources/QML/QT6/PluginSettingsDialog.qml @@ -169,6 +169,27 @@ UM.Dialog { text: catalog.i18nc("@tooltip", "If enabled, this option allows more comments to be added to the modified GCode.
The use of more comments allows better control of the modifications made, but increases the size of the final code.") visible: enable_advanced_gcode_comments_mouse_area.containsMouse + } + + UM.Label + { + text: catalog.i18nc("@label", "Descriptive File Names") + MouseArea + { + id: enable_descriptive_file_names_mouse_area + anchors.fill: parent + hoverEnabled: true + } + } + UM.CheckBox + { + id: enableDescriptiveFileNames + checked: manager.enableDescriptiveFileNamesSetting + } + UM.ToolTip + { + text: catalog.i18nc("@tooltip", "If enabled, gcode will be created with descriptive file names.
These file names may be too long for some printers to handle and can be deselected if needed.") + visible: enable_descriptive_file_names_mouse_area.containsMouse } } } @@ -192,6 +213,7 @@ UM.Dialog manager.openScadPathSetting = openScadPath.text manager.enableLcdMessagesSetting = enableLcdMessages.checked manager.enableAdvancedGcodeCommentsSetting = enableAdvancedGcodeComments.checked + manager.enableDescriptiveFileNamesSetting = enableDescriptiveFileNames.checked manager.correctPrintSettings = correctPrintSettings.checked } diff --git a/Resources/i18n/autotowers.pot b/Resources/i18n/autotowers.pot index 3a6c3b5..e859212 100644 --- a/Resources/i18n/autotowers.pot +++ b/Resources/i18n/autotowers.pot @@ -792,6 +792,14 @@ msgid "" "made, but increases the size of the final code." msgstr "" +#: Resources/QML/QT6/PluginSettingsDialog.qml:191 +msgctxt "@tooltip" +msgid "" +"If enabled, gcode will be created with descriptive file names.
These file " +"names may be too long for some printers to handle and can be deselected if " +"needed." +msgstr "" + #: Resources/QML/QT6/FlowTowerDialog.qml:14 msgctxt "@title" msgid "Flow Tower" diff --git a/Resources/i18n/fr_FR/autotowers.po b/Resources/i18n/fr_FR/autotowers.po index d15e142..4b52024 100644 --- a/Resources/i18n/fr_FR/autotowers.po +++ b/Resources/i18n/fr_FR/autotowers.po @@ -882,6 +882,17 @@ msgstr "" "Gcode modifié.
L'utilisation de plus de commentaires permet un meilleur " "contrôle des modifications apportées, mais augmente la taille du code final." +#: Resources/QML/QT6/PluginSettingsDialog.qml:191 +msgctxt "@tooltip" +msgid "" +"If enabled, gcode will be created with descriptive file names.
These file " +"names may be too long for some printers to handle and can be deselected if " +"needed." +msgstr "" +"Si elle est activée, le gcode sera créé avec des noms de fichiers " +"descriptifs.
Ces noms de fichiers peuvent être trop longs à gérer pour " +"certaines imprimantes et peuvent être désélectionnés si nécessaire." + #: Resources/QML/QT6/FlowTowerDialog.qml:14 msgctxt "@title" msgid "Flow Tower"