diff --git a/.github/workflows/translation.yaml b/.github/workflows/translation.yaml index 62d83e0..529392c 100644 --- a/.github/workflows/translation.yaml +++ b/.github/workflows/translation.yaml @@ -1,4 +1,4 @@ -name: "Autmatically update i18n files" +name: "Automatically update i18n files" on: push: diff --git a/.github/workflows/update_pot.yaml b/.github/workflows/update_pot.yaml new file mode 100644 index 0000000..087a114 --- /dev/null +++ b/.github/workflows/update_pot.yaml @@ -0,0 +1,32 @@ +name: "Update i18n template" + +on: + [push] + +jobs: + update-pot: + name: "Update i18n template" + runs-on: "ubuntu-latest" + + steps: + - uses: ConorMacBride/install-package@v1 + with: + apt: gettext + - uses: actions/checkout@v3 + with: + submodules: "recursive" + + - run: mkdir -p i18n + - name: Find strings in Python files + run: xgettext --package-name='Mesh Tools' -o resources/i18n/meshtools.pot --language=python --from-code=UTF-8 -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 $(find -L . -name \*.py) + - name: Find strings in QML files + run: xgettext --package-name='Mesh Tools' -o resources/i18n/meshtools.pot --join-existing --language=javascript --from-code=UTF-8 -ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 $(find -L . -name \*.qml) + - run: git add --intent-to-add i18n + - name: Check diff + id: git_diff + run: echo "##[set-output name=numstat;]$(git diff --numstat i18n)" + + - if: ${{steps.git_diff.outputs.numstat != '1 1 resources/i18n/meshtools.pot'}} + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: Update i18n template for meshtools.pot diff --git a/MeshTools.py b/MeshTools.py index 8ec3b45..f71f80a 100644 --- a/MeshTools.py +++ b/MeshTools.py @@ -49,14 +49,7 @@ from typing import Optional, List, Dict -Resources.addSearchPath( - os.path.join( - os.path.abspath(os.path.dirname(__file__)), - "resources" - ) -) # Plugin translation file import -catalog = i18nCatalog("meshtools") class MeshTools(Extension, QObject,): @@ -64,10 +57,17 @@ def __init__(self, parent = None) -> None: QObject.__init__(self, parent) Extension.__init__(self) - self._application = CuraApplication.getInstance() + Resources.addSearchPath( + os.path.join( + os.path.abspath(os.path.dirname(__file__)), + "resources" + ) + ) # Plugin translation file import + self._catalog = i18nCatalog("meshtools") - self._qml_folder = "qml" if not USE_QT5 else "qml_qt5" + self._qml_folder = "qml_qt6" if not USE_QT5 else "qml_qt5" + self._application = CuraApplication.getInstance() self._application.engineCreatedSignal.connect(self._onEngineCreated) self._application.fileLoaded.connect(self._onFileLoaded) self._application.fileCompleted.connect(self._onFileCompleted) @@ -86,25 +86,29 @@ def __init__(self, parent = None) -> None: self._preferences.addPreference("meshtools/check_models_on_load", True) self._preferences.addPreference("meshtools/fix_normals_on_load", False) self._preferences.addPreference("meshtools/randomise_location_on_load", False) + self._preferences.addPreference("meshtools/set_location_on_load", False) + self._preferences.addPreference("meshtools/set_location_x", 0) + self._preferences.addPreference("meshtools/set_location_y", 0) self._preferences.addPreference("meshtools/model_unit_factor", 1) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Reload model"), self.reloadMesh) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Rename model..."), self.renameMesh) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Replace models..."), self.replaceMeshes) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Reload model"), self.reloadMesh) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Rename model..."), self.renameMesh) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Replace models..."), self.replaceMeshes) self.addMenuItem("", lambda: None) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Check models"), self.checkMeshes) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Analyse models"), self.analyseMeshes) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Fix simple holes"), self.fixSimpleHolesForMeshes) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Fix model normals"), self.fixNormalsForMeshes) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Split model into parts"), self.splitMeshes) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Check models"), self.checkMeshes) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Analyse models"), self.analyseMeshes) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Fix simple holes"), self.fixSimpleHolesForMeshes) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Fix model normals"), self.fixNormalsForMeshes) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Split model into parts"), self.splitMeshes) self.addMenuItem(" ", lambda: None) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Randomise location"), self.randomiseMeshLocation) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Apply transformations to mesh"), self.bakeMeshTransformation) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Reset origin to center of mesh"), self.resetMeshOrigin) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Randomise location"), self.randomiseMeshLocation) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Fixed location"), self.setMeshLocation) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Apply transformations to mesh"), self.bakeMeshTransformation) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Reset origin to center of mesh"), self.resetMeshOrigin) self.addMenuItem(" ", lambda: None) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Mesh Tools settings..."), self.showSettingsDialog) + self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Mesh Tools settings..."), self.showSettingsDialog) - self._message = Message(title=catalog.i18nc("@info:title", "Mesh Tools")) + self._message = Message(title=self._catalog.i18nc("@info:title", "Mesh Tools")) self._additional_menu = None # type: Optional[QObject] def showSettingsDialog(self) -> None: @@ -155,7 +159,7 @@ def _onEngineCreated(self) -> None: if USE_QT5: context_menu.insertSeparator(0) - context_menu.insertMenu(0, catalog.i18nc("@info:title", "Mesh Tools")) + context_menu.insertMenu(0, self._catalog.i18nc("@info:title", "Mesh Tools")) # Move additional menu items into context menu self._additional_menu.moveToContextMenu(context_menu) @@ -193,13 +197,27 @@ def checkQueuedNodes(self) -> None: if not mesh_data: continue file_name = mesh_data.getFileName() - - if self._preferences.getValue("meshtools/randomise_location_on_load") and global_container_stack != None: + + if ( self._preferences.getValue("meshtools/randomise_location_on_load") or self._preferences.getValue("meshtools/set_location_on_load") ) and global_container_stack != None: if file_name and os.path.splitext(file_name)[1].lower() == ".3mf": # don't randomise project files continue node_bounds = node.getBoundingBox() - position = self._randomLocation(node_bounds, max_x_coordinate, max_y_coordinate) + self._message.hide() + + if self._preferences.getValue("meshtools/randomise_location_on_load") : + position = self._randomLocation(node_bounds, max_x_coordinate, max_y_coordinate) + message_body= self._catalog.i18nc("@info:status", "Randomise Location fixed by Mesh Tools") + " : {}".format(position) + else : + Vx=float(self._preferences.getValue("meshtools/set_location_x")) + Vy=float(self._preferences.getValue("meshtools/set_location_y")) + Logger.log('d', "Position X : {} Y : {}".format(Vx,Vy)) + position = Vector(Vx,(node_bounds.height / 2),Vy) + message_body= self._catalog.i18nc("@info:status", "Location fixed by Mesh Tools") + " X : {} Y : {}".format(Vx,Vy) + + self._message.setText(message_body) + self._message.show() + node.setPosition(position) if ( @@ -223,23 +241,23 @@ def checkQueuedNodes(self) -> None: if self._preferences.getValue("meshtools/check_models_on_load") and not tri_node.is_watertight: if not file_name: - file_name = catalog.i18nc("@text Print job name", "Untitled") + file_name = self._catalog.i18nc("@text Print job name", "Untitled") base_name = os.path.basename(file_name) if file_name in self._mesh_not_watertight_messages: self._mesh_not_watertight_messages[file_name].hide() - message = Message(title=catalog.i18nc("@info:title", "Mesh Tools")) - body = catalog.i18nc("@info:status", "Model %s is not watertight, and may not print properly.") % base_name + message = Message(title=self._catalog.i18nc("@info:title", "Mesh Tools")) + body = self._catalog.i18nc("@info:status", "Model %s is not watertight, and may not print properly.") % base_name # XRayView may not be available if the plugin has been disabled active_view = self._controller.getActiveView() if active_view and "XRayView" in self._controller.getAllViews() and active_view.getPluginId() != "XRayView": - body += " " + catalog.i18nc("@info:status", "Check X-Ray View and repair the model before printing it.") - message.addAction("X-Ray", catalog.i18nc("@action:button", "Show X-Ray View"), "", "") + body += " " + self._catalog.i18nc("@info:status", "Check X-Ray View and repair the model before printing it.") + message.addAction("X-Ray", self._catalog.i18nc("@action:button", "Show X-Ray View"), "", "") message.actionTriggered.connect(self._showXRayView) else: - body += " " +catalog.i18nc("@info:status", "Repair the model before printing it.") + body += " " +self._catalog.i18nc("@info:status", "Repair the model before printing it.") message.setText(body) message.show() @@ -277,12 +295,12 @@ def _getSelectedNodes(self, force_single = False) -> List[SceneNode]: if len(selection) == 1: return selection[:] - self._message.setText(catalog.i18nc("@info:status", "Please select a single model first")) + self._message.setText(self._catalog.i18nc("@info:status", "Please select a single model first")) else: if len(selection) >= 1: return selection[:] - self._message.setText(catalog.i18nc("@info:status", "Please select one or more models first")) + self._message.setText(self._catalog.i18nc("@info:status", "Please select one or more models first")) self._message.show() return [] @@ -300,7 +318,7 @@ def _getAllSelectedNodes(self) -> List[SceneNode]: if deep_selection: return deep_selection - self._message.setText(catalog.i18nc("@info:status", "Please select one or more models first")) + self._message.setText(self._catalog.i18nc("@info:status", "Please select one or more models first")) self._message.show() return [] @@ -311,16 +329,16 @@ def checkMeshes(self) -> None: if not nodes_list: return - message_body = catalog.i18nc("@info:status", "Check summary:") + message_body = self._catalog.i18nc("@info:status", "Check summary:") for node in nodes_list: tri_node = self._toTriMesh(node.getMeshData()) message_body = message_body + "\n - %s" % node.getName() if tri_node.is_watertight: - message_body = message_body + " " + catalog.i18nc("@info:status", "is watertight") + message_body = message_body + " " + self._catalog.i18nc("@info:status", "is watertight") else: - message_body = message_body + " " + catalog.i18nc("@info:status", "is not watertight and may not print properly") + message_body = message_body + " " + self._catalog.i18nc("@info:status", "is not watertight and may not print properly") if tri_node.body_count > 1: - message_body = message_body + " " + catalog.i18nc("@info:status", "and consists of {body_count} submeshes").format(body_count = tri_node.body_count) + message_body = message_body + " " + self._catalog.i18nc("@info:status", "and consists of {body_count} submeshes").format(body_count = tri_node.body_count) self._message.setText(message_body) self._message.show() @@ -331,13 +349,13 @@ def analyseMeshes(self) -> None: if not nodes_list: return - message_body = catalog.i18nc("@info:status", "Analysis summary:") + message_body = self._catalog.i18nc("@info:status", "Analysis summary:") for node in nodes_list: tri_node = self._toTriMesh(node.getMeshDataTransformed()) message_body = message_body + "\n - %s:" % node.getName() - message_body += "\n\t" + catalog.i18nc("@info:status", "%d vertices, %d faces") % (len(tri_node.vertices), len(tri_node.faces)) + message_body += "\n\t" + self._catalog.i18nc("@info:status", "%d vertices, %d faces") % (len(tri_node.vertices), len(tri_node.faces)) if tri_node.is_watertight: - message_body += "\n\t" + catalog.i18nc("@info:status", "area: %d mm2, volume: %d mm3") % (tri_node.area, tri_node.volume) + message_body += "\n\t" + self._catalog.i18nc("@info:status", "area: %d mm2, volume: %d mm3") % (tri_node.area, tri_node.volume) self._message.setText(message_body) self._message.show() @@ -353,7 +371,7 @@ def fixSimpleHolesForMeshes(self) -> None: success = tri_node.fill_holes() self._replaceSceneNode(node, [tri_node]) if not success: - self._message.setText(catalog.i18nc( + self._message.setText(self._catalog.i18nc( "@info:status", "The mesh needs more extensive repair to become watertight" )) @@ -376,15 +394,15 @@ def splitMeshes(self) -> None: if not nodes_list: return - message_body = catalog.i18nc("@info:status", "Split result:") + message_body = self._catalog.i18nc("@info:status", "Split result:") for node in nodes_list: message_body = message_body + "\n - %s" % node.getName() tri_node = self._toTriMesh(node.getMeshData()) if tri_node.body_count > 1: self._replaceSceneNode(node, tri_node.split(only_watertight=False)) - message_body = message_body + " " + catalog.i18nc("@info:status", "was split in %d submeshes") % tri_node.body_count + message_body = message_body + " " + self._catalog.i18nc("@info:status", "was split in %d submeshes") % tri_node.body_count else: - message_body = message_body + " " + catalog.i18nc("@info:status", "could not be split into submeshes") + message_body = message_body + " " + self._catalog.i18nc("@info:status", "could not be split into submeshes") self._message.setText(message_body) self._message.show() @@ -398,7 +416,7 @@ def replaceMeshes(self) -> None: for node in self._node_queue: mesh_data = node.getMeshData() if not mesh_data: - self._message.setText(catalog.i18nc("@info:status", "Replacing a group is not supported")) + self._message.setText(self._catalog.i18nc("@info:status", "Replacing a group is not supported")) self._message.show() self._node_queue = [] #type: List[SceneNode] return @@ -419,12 +437,12 @@ def replaceMeshes(self) -> None: file_name, _ = QFileDialog.getOpenFileName( parent=None, - caption=catalog.i18nc("@title:window", "Select Replacement Mesh File"), + caption=self._catalog.i18nc("@title:window", "Select Replacement Mesh File"), directory=directory, options=options, filter=filter_types ) else: dialog = QFileDialog() - dialog.setWindowTitle(catalog.i18nc("@title:window", "Select Replacement Mesh File")) + dialog.setWindowTitle(self._catalog.i18nc("@title:window", "Select Replacement Mesh File")) dialog.setDirectory(directory) dialog.setNameFilters(self._application.getMeshFileHandler().supportedReadFileTypes) dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen) @@ -473,14 +491,14 @@ def reloadMesh(self) -> None: mesh_data = self._node_queue[0].getMeshData() if not mesh_data: - self._message.setText(catalog.i18nc("@info:status", "Reloading a group is not supported")) + self._message.setText(self._catalog.i18nc("@info:status", "Reloading a group is not supported")) self._message.show() self._node_queue = [] #type: List[SceneNode] return file_name = mesh_data.getFileName() if not file_name: - self._message.setText(catalog.i18nc("@info:status", "No link to the original file was found")) + self._message.setText(self._catalog.i18nc("@info:status", "No link to the original file was found")) self._message.show() self._node_queue = [] #type: List[SceneNode] return @@ -492,14 +510,14 @@ def reloadMesh(self) -> None: def _readMeshFinished(self, job) -> None: job_result = job.getResult() if len(job_result) == 0: - self._message.setText(catalog.i18nc("@info:status", "Failed to load mesh")) + self._message.setText(self._catalog.i18nc("@info:status", "Failed to load mesh")) self._message.show() self._node_queue = [] #type: List[SceneNode] return mesh_data = job_result[0].getMeshData() if not mesh_data: - self._message.setText(catalog.i18nc("@info:status", "Replacing meshes with a group of meshes is not supported")) + self._message.setText(self._catalog.i18nc("@info:status", "Replacing meshes with a group of meshes is not supported")) self._message.show() self._node_queue = [] #type: List[SceneNode] return @@ -508,7 +526,7 @@ def _readMeshFinished(self, job) -> None: if file_name: mesh_name = os.path.basename(file_name) else: - mesh_name = catalog.i18nc("@text Print job name", "Untitled") + mesh_name = self._catalog.i18nc("@text Print job name", "Untitled") has_merged_nodes = False @@ -547,6 +565,26 @@ def randomiseMeshLocation(self) -> None: op.addOperation(SetTransformOperation(node, translation=position)) op.push() + @pyqtSlot() + def setMeshLocation(self) -> None: + nodes_list = self._getAllSelectedNodes() + if not nodes_list: + return + + global_container_stack = self._application.getGlobalContainerStack() + if not global_container_stack: + return + + op = GroupedOperation() + for node in nodes_list: + node_bounds = node.getBoundingBox() + Vx=float(self._preferences.getValue("meshtools/set_location_x")) + Vy=float(self._preferences.getValue("meshtools/set_location_y")) + Logger.log('d', "Position X : {} Y : {}".format(Vx,Vy)) + position = Vector(Vx,(node_bounds.height / 2),Vy) + op.addOperation(SetTransformOperation(node, translation=position)) + op.push() + def _randomLocation(self, node_bounds, max_x_coordinate, max_y_coordinate): return Vector( (2 * random.random() - 1) * (max_x_coordinate - (node_bounds.width / 2)), @@ -572,7 +610,7 @@ def bakeMeshTransformation(self) -> None: file_name = "" mesh_name = os.path.basename(file_name) if not mesh_name: - mesh_name = catalog.i18nc("@text Print job name", "Untitled") + mesh_name = self._catalog.i18nc("@text Print job name", "Untitled") local_transformation = node.getLocalTransformation() position = local_transformation.getTranslation() diff --git a/README.md b/README.md index 8843858..5fc93c2 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,11 @@ When printing with a consumable build plate surface, it can be beneficial to print have each print on a different location on the build plate to make sure it wears down evenly. +### Fixed location +Allows you to position parts at a specific position defined in the plugin settings. +The position can be set in the settings dialog which can be found via +`Extensions -> Mesh Tools -> Mesh Tools Settings` + ### Apply transformations to mesh This function applies the rotation and scale to the mesh coordinates, and resets the model rotation and scale to upright and 100%. This can make it diff --git a/plugin.json b/plugin.json index 997496d..6f064a6 100644 --- a/plugin.json +++ b/plugin.json @@ -1,7 +1,7 @@ { "name": "Mesh Tools", "author": "fieldOfView", - "version": "3.7.1", + "version": "3.7.2", "description": "Adds several mesh analysis and manipulation tools", "api": 5, "supported_sdk_versions": ["5.0.0", "6.0.0", "7.0.0", "8.0.0"], diff --git a/resources/i18n/fr_FR/LC_MESSAGES/meshtools.mo b/resources/i18n/fr_FR/LC_MESSAGES/meshtools.mo index 3db9bc9..8d996d5 100644 Binary files a/resources/i18n/fr_FR/LC_MESSAGES/meshtools.mo and b/resources/i18n/fr_FR/LC_MESSAGES/meshtools.mo differ diff --git a/resources/i18n/fr_FR/meshtools.po b/resources/i18n/fr_FR/meshtools.po index e79aef2..fded25f 100644 --- a/resources/i18n/fr_FR/meshtools.po +++ b/resources/i18n/fr_FR/meshtools.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Mesh Tools\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-20 15:21+0000\n" -"PO-Revision-Date: 2023-02-27 17:07+0200\n" +"POT-Creation-Date: 2023-07-25 23:23+0000\n" +"PO-Revision-Date: 2023-07-26 01:24+0200\n" "Last-Translator: 5axes <5axes@free.fr>\n" "Language-Team: 5axes\n" "Language: fr\n" @@ -17,228 +17,258 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Virtaal 0.7.1\n" -#: MeshTools.py:88 qml/MeshToolsMenu.qml:19 qml_qt5/MeshToolsMenu.qml:18 +#: MeshTools.py:94 resources/qml_qt5/MeshToolsMenu.qml:18 +#: resources/qml_qt6/MeshToolsMenu.qml:19 msgctxt "@item:inmenu" msgid "Reload model" msgstr "Recharger le modèle" -#: MeshTools.py:89 qml/MeshToolsMenu.qml:25 qml_qt5/MeshToolsMenu.qml:24 +#: MeshTools.py:95 resources/qml_qt5/MeshToolsMenu.qml:24 +#: resources/qml_qt6/MeshToolsMenu.qml:25 msgctxt "@item:inmenu" msgid "Rename model..." msgstr "Renommer modèle..." -#: MeshTools.py:90 +#: MeshTools.py:96 msgctxt "@item:inmenu" msgid "Replace models..." msgstr "Remplacer modèles..." -#: MeshTools.py:92 +#: MeshTools.py:98 msgctxt "@item:inmenu" msgid "Check models" msgstr "Vérifier les modèles" -#: MeshTools.py:93 +#: MeshTools.py:99 msgctxt "@item:inmenu" msgid "Analyse models" msgstr "Analyser les modèles" -#: MeshTools.py:94 qml/MeshToolsMenu.qml:50 qml_qt5/MeshToolsMenu.qml:49 +#: MeshTools.py:100 resources/qml_qt5/MeshToolsMenu.qml:49 +#: resources/qml_qt6/MeshToolsMenu.qml:50 msgctxt "@item:inmenu" msgid "Fix simple holes" msgstr "Boucher les trous simples" -#: MeshTools.py:95 qml/MeshToolsMenu.qml:56 qml_qt5/MeshToolsMenu.qml:55 +#: MeshTools.py:101 resources/qml_qt5/MeshToolsMenu.qml:55 +#: resources/qml_qt6/MeshToolsMenu.qml:56 msgctxt "@item:inmenu" msgid "Fix model normals" msgstr "Recalculer les normales du modèle" -#: MeshTools.py:96 qml/MeshToolsMenu.qml:62 qml_qt5/MeshToolsMenu.qml:61 +#: MeshTools.py:102 resources/qml_qt5/MeshToolsMenu.qml:61 +#: resources/qml_qt6/MeshToolsMenu.qml:62 msgctxt "@item:inmenu" msgid "Split model into parts" msgid_plural "Split models into parts" msgstr[0] "Diviser le modèle en plusieurs parties" msgstr[1] "Diviser les modèles en plusieurs parties" -#: MeshTools.py:98 qml/MeshToolsMenu.qml:69 qml_qt5/MeshToolsMenu.qml:68 +#: MeshTools.py:104 resources/qml_qt5/MeshToolsMenu.qml:68 +#: resources/qml_qt6/MeshToolsMenu.qml:69 msgctxt "@item:inmenu" msgid "Randomise location" msgstr "Localisation aléatoire" -#: MeshTools.py:99 qml/MeshToolsMenu.qml:75 qml_qt5/MeshToolsMenu.qml:74 +#: MeshTools.py:105 resources/qml_qt5/MeshToolsMenu.qml:74 +#: resources/qml_qt6/MeshToolsMenu.qml:75 +msgctxt "@item:inmenu" +msgid "Fixed location" +msgstr "Position déterminée" + +#: MeshTools.py:106 resources/qml_qt5/MeshToolsMenu.qml:80 +#: resources/qml_qt6/MeshToolsMenu.qml:81 msgctxt "@item:inmenu" msgid "Apply transformations to mesh" msgstr "Appliquer les transformations au maillage" -#: MeshTools.py:100 qml/MeshToolsMenu.qml:81 qml_qt5/MeshToolsMenu.qml:80 +#: MeshTools.py:107 resources/qml_qt5/MeshToolsMenu.qml:86 +#: resources/qml_qt6/MeshToolsMenu.qml:87 msgctxt "@item:inmenu" msgid "Reset origin to center of mesh" msgstr "Remettre l'origine au centre du maillage" -#: MeshTools.py:102 +#: MeshTools.py:109 msgctxt "@item:inmenu" msgid "Mesh Tools settings..." msgstr "Paramètres de Mesh Tools..." -#: MeshTools.py:104 MeshTools.py:145 MeshTools.py:219 +#: MeshTools.py:111 MeshTools.py:162 MeshTools.py:250 msgctxt "@info:title" msgid "Mesh Tools" msgstr "Mesh Tools" -#: MeshTools.py:213 MeshTools.py:493 MeshTools.py:557 +#: MeshTools.py:210 +msgctxt "@info:status" +msgid "Randomise Location fixed by Mesh Tools" +msgstr "Placement aléatoire par Mesh Tools" + +#: MeshTools.py:216 +msgctxt "@info:status" +msgid "Location fixed by Mesh Tools" +msgstr "Placement fixé par Mesh Tools" + +#: MeshTools.py:244 MeshTools.py:529 MeshTools.py:613 msgctxt "@text Print job name" msgid "Untitled" msgstr "Sans Nom" -#: MeshTools.py:220 +#: MeshTools.py:251 #, python-format msgctxt "@info:status" msgid "Model %s is not watertight, and may not print properly." msgstr "" "Le modèle %s n'est pas étanche et risque de ne pas s'imprimer correctement." -#: MeshTools.py:225 +#: MeshTools.py:256 msgctxt "@info:status" msgid "Check X-Ray View and repair the model before printing it." msgstr "Vérifiez la vue aux Rayons-X et réparez le modèle avant de l'imprimer." -#: MeshTools.py:226 +#: MeshTools.py:257 msgctxt "@action:button" msgid "Show X-Ray View" msgstr "Afficher la vue aux Rayons-X" -#: MeshTools.py:229 +#: MeshTools.py:260 msgctxt "@info:status" msgid "Repair the model before printing it." msgstr "Réparez le modèle avant de l'imprimer." -#: MeshTools.py:267 +#: MeshTools.py:298 msgctxt "@info:status" msgid "Please select a single model first" msgstr "Sélectionnez tout d'abord une pièce" -#: MeshTools.py:272 MeshTools.py:290 +#: MeshTools.py:303 MeshTools.py:321 msgctxt "@info:status" msgid "Please select one or more models first" msgstr "Sélectionnez tout d'abord des pièces" -#: MeshTools.py:301 +#: MeshTools.py:332 msgctxt "@info:status" msgid "Check summary:" msgstr "Résumé de la vérification :" -#: MeshTools.py:306 +#: MeshTools.py:337 msgctxt "@info:status" msgid "is watertight" msgstr "est étanche" -#: MeshTools.py:308 +#: MeshTools.py:339 msgctxt "@info:status" msgid "is not watertight and may not print properly" msgstr "n'est pas étanche et peut ne pas imprimer correctement" -#: MeshTools.py:310 +#: MeshTools.py:341 #, python-brace-format msgctxt "@info:status" msgid "and consists of {body_count} submeshes" msgstr "et consiste en {body_count} sous-ensembles" -#: MeshTools.py:321 +#: MeshTools.py:352 msgctxt "@info:status" msgid "Analysis summary:" msgstr "Résumé de l'analyse :" -#: MeshTools.py:325 +#: MeshTools.py:356 #, python-format msgctxt "@info:status" msgid "%d vertices, %d faces" msgstr "%d sommets, %d faces" -#: MeshTools.py:327 +#: MeshTools.py:358 #, python-format msgctxt "@info:status" msgid "area: %d mm2, volume: %d mm3" msgstr "surface: %d mm2, volume: %d mm3" -#: MeshTools.py:345 +#: MeshTools.py:376 msgctxt "@info:status" msgid "The mesh needs more extensive repair to become watertight" msgstr "" "La maille a besoin de réparations plus importantes pour devenir étanche." -#: MeshTools.py:366 +#: MeshTools.py:397 msgctxt "@info:status" msgid "Split result:" msgstr "Résultat du fractionnement :" -#: MeshTools.py:372 +#: MeshTools.py:403 #, python-format msgctxt "@info:status" msgid "was split in %d submeshes" msgstr "a été divisé en %d sous-maillages" -#: MeshTools.py:374 +#: MeshTools.py:405 msgctxt "@info:status" msgid "could not be split into submeshes" msgstr "n'a pas pu être divisé en sous-ensembles" -#: MeshTools.py:388 +#: MeshTools.py:419 msgctxt "@info:status" msgid "Replacing a group is not supported" msgstr "Le remplacement d'un groupe n'est pas pris en charge" -#: MeshTools.py:409 MeshTools.py:414 +#: MeshTools.py:440 MeshTools.py:445 msgctxt "@title:window" msgid "Select Replacement Mesh File" msgstr "Sélectionnez le fichier de maillage de remplacement" -#: MeshTools.py:458 +#: MeshTools.py:494 msgctxt "@info:status" msgid "Reloading a group is not supported" msgstr "Le rechargement d'un groupe n'est pas pris en charge" -#: MeshTools.py:465 +#: MeshTools.py:501 msgctxt "@info:status" msgid "No link to the original file was found" msgstr "Aucun lien vers le fichier original n'a été trouvé" -#: MeshTools.py:477 +#: MeshTools.py:513 msgctxt "@info:status" msgid "Failed to load mesh" msgstr "Échec du chargement du maillage" -#: MeshTools.py:484 +#: MeshTools.py:520 msgctxt "@info:status" msgid "Replacing meshes with a group of meshes is not supported" msgstr "" "Le remplacement des maillages par un groupe de maillages n'est pas pris en " "charge." -#: qml/SettingsDialog.qml:15 qml_qt5/SettingsDialog.qml:17 +#: resources/qml_qt5/SettingsDialog.qml:18 +#: resources/qml_qt6/SettingsDialog.qml:16 msgctxt "@title:window" msgid "Mesh Tools Settings" msgstr "Paramètres du plugin" -#: qml/SettingsDialog.qml:49 qml_qt5/SettingsDialog.qml:51 +#: resources/qml_qt5/SettingsDialog.qml:52 +#: resources/qml_qt6/SettingsDialog.qml:50 msgctxt "@info:tooltip" msgid "Check if models are watertight when loading them" msgstr "Vérifier l'étanchéité des modèles lors de leur chargement" -#: qml/SettingsDialog.qml:53 qml_qt5/SettingsDialog.qml:55 +#: resources/qml_qt5/SettingsDialog.qml:56 +#: resources/qml_qt6/SettingsDialog.qml:54 msgctxt "@option:check" msgid "Check models on load" msgstr "Vérifier les modèles au chargement" -#: qml/SettingsDialog.qml:63 qml_qt5/SettingsDialog.qml:65 +#: resources/qml_qt5/SettingsDialog.qml:66 +#: resources/qml_qt6/SettingsDialog.qml:64 msgctxt "@info:tooltip" msgid "Always recalculate model normals when loading them" msgstr "Toujours recalculer les normales des modèles lors de leur chargement" -#: qml/SettingsDialog.qml:67 qml_qt5/SettingsDialog.qml:69 +#: resources/qml_qt5/SettingsDialog.qml:70 +#: resources/qml_qt6/SettingsDialog.qml:68 msgctxt "@option:check" msgid "Fix normals on load" msgstr "Corriger les normales au chargement" -#: qml/SettingsDialog.qml:80 qml_qt5/SettingsDialog.qml:82 +#: resources/qml_qt5/SettingsDialog.qml:83 +#: resources/qml_qt6/SettingsDialog.qml:81 msgctxt "@info:tooltip" msgid "" "Unit to convert meshes from when the file does not specify a unit (such as " @@ -248,100 +278,152 @@ msgstr "" "spécifie pas d'unité (comme les fichiers STL). Toutes les unités seront " "converties en millimètres." -#: qml/SettingsDialog.qml:88 qml_qt5/SettingsDialog.qml:90 +#: resources/qml_qt5/SettingsDialog.qml:91 +#: resources/qml_qt6/SettingsDialog.qml:89 msgctxt "@window:text" msgid "Unit for files that don't specify a unit:" msgstr "Unité pour les fichiers qui ne spécifient pas d'unité :" -#: qml/SettingsDialog.qml:96 qml_qt5/SettingsDialog.qml:104 +#: resources/qml_qt5/SettingsDialog.qml:105 +#: resources/qml_qt6/SettingsDialog.qml:97 msgctxt "@option:unit" msgid "Micron" msgstr "Micron" -#: qml/SettingsDialog.qml:97 qml_qt5/SettingsDialog.qml:105 +#: resources/qml_qt5/SettingsDialog.qml:106 +#: resources/qml_qt6/SettingsDialog.qml:98 msgctxt "@option:unit" msgid "Millimeter (default)" msgstr "Millimètre (défaut)" -#: qml/SettingsDialog.qml:98 qml_qt5/SettingsDialog.qml:106 +#: resources/qml_qt5/SettingsDialog.qml:107 +#: resources/qml_qt6/SettingsDialog.qml:99 msgctxt "@option:unit" msgid "Centimeter" msgstr "Centimètre" -#: qml/SettingsDialog.qml:99 qml_qt5/SettingsDialog.qml:107 +#: resources/qml_qt5/SettingsDialog.qml:108 +#: resources/qml_qt6/SettingsDialog.qml:100 msgctxt "@option:unit" msgid "Meter" msgstr "Mètre" -#: qml/SettingsDialog.qml:100 qml_qt5/SettingsDialog.qml:108 +#: resources/qml_qt5/SettingsDialog.qml:109 +#: resources/qml_qt6/SettingsDialog.qml:101 msgctxt "@option:unit" msgid "Inch" msgstr "Pouce" -#: qml/SettingsDialog.qml:101 qml_qt5/SettingsDialog.qml:109 +#: resources/qml_qt5/SettingsDialog.qml:110 +#: resources/qml_qt6/SettingsDialog.qml:102 msgctxt "@option:unit" msgid "Feet" msgstr "Pied" -#: qml/SettingsDialog.qml:143 qml_qt5/SettingsDialog.qml:140 +#: resources/qml_qt5/SettingsDialog.qml:141 +#: resources/qml_qt6/SettingsDialog.qml:144 msgctxt "@info:tooltip" msgid "Place models at a random location on the build plate when loading them" msgstr "" "Placez les modèles à une position aléatoire sur le plateau d'impression " "lorsque vous les chargez." -#: qml/SettingsDialog.qml:147 qml_qt5/SettingsDialog.qml:144 +#: resources/qml_qt5/SettingsDialog.qml:147 +#: resources/qml_qt6/SettingsDialog.qml:150 msgctxt "@option:check" msgid "Randomize position on load" msgstr "Position aléatoire au chargement" -#: qml/SettingsDialog.qml:158 qml_qt5/SettingsDialog.qml:155 +#: resources/qml_qt5/SettingsDialog.qml:157 +#: resources/qml_qt6/SettingsDialog.qml:160 +msgctxt "@info:tooltip" +msgid "" +"Place models at a specific location on the build plate when loading them" +msgstr "" +"Placer les modèles à un endroit précis de la plaque de construction lors de " +"leur chargement." + +#: resources/qml_qt5/SettingsDialog.qml:163 +#: resources/qml_qt6/SettingsDialog.qml:166 +msgctxt "@option:check" +msgid "Set position on load" +msgstr "Position au chargement" + +#: resources/qml_qt5/SettingsDialog.qml:174 +#: resources/qml_qt6/SettingsDialog.qml:176 +msgctxt "@info:tooltip" +msgid "X position relative / Bed Center" +msgstr "Position X relative / Centre du plateau" + +#: resources/qml_qt5/SettingsDialog.qml:179 +#: resources/qml_qt6/SettingsDialog.qml:181 +msgctxt "@label:text" +msgid "X position" +msgstr "Position X" + +#: resources/qml_qt5/SettingsDialog.qml:207 +#: resources/qml_qt6/SettingsDialog.qml:203 +msgctxt "@info:tooltip" +msgid "Y position relative / Bed Center" +msgstr "Position Y relative / Centre du plateau" + +#: resources/qml_qt5/SettingsDialog.qml:212 +#: resources/qml_qt6/SettingsDialog.qml:208 +msgctxt "@label:text" +msgid "Y position" +msgstr "Position Y" + +#: resources/qml_qt5/SettingsDialog.qml:242 +#: resources/qml_qt6/SettingsDialog.qml:234 msgctxt "@action:button" msgid "Close" msgstr "Fermer" -#: qml/RenameDialog.qml:25 qml_qt5/RenameDialog.qml:24 +#: resources/qml_qt5/RenameDialog.qml:24 resources/qml_qt6/RenameDialog.qml:25 msgctxt "@title:window" msgid "Rename" msgstr "Renommer" -#: qml/RenameDialog.qml:26 qml_qt5/RenameDialog.qml:25 +#: resources/qml_qt5/RenameDialog.qml:25 resources/qml_qt6/RenameDialog.qml:26 msgctxt "@info" msgid "Please provide a new name." msgstr "Veuillez indiquer un nouveau nom." -#: qml/RenameDialog.qml:66 qml_qt5/RenameDialog.qml:74 +#: resources/qml_qt5/RenameDialog.qml:74 resources/qml_qt6/RenameDialog.qml:66 msgctxt "@action:button" msgid "Cancel" msgstr "Annuler" -#: qml/RenameDialog.qml:72 qml_qt5/RenameDialog.qml:79 +#: resources/qml_qt5/RenameDialog.qml:79 resources/qml_qt6/RenameDialog.qml:72 msgctxt "@action:button" msgid "OK" msgstr "OK" -#: qml/MeshToolsMenu.qml:15 -msgctxt "@item:inmenu" -msgid "Mesh Tools" -msgstr "Mesh Tools" - -#: qml/MeshToolsMenu.qml:31 qml_qt5/MeshToolsMenu.qml:30 +#: resources/qml_qt5/MeshToolsMenu.qml:30 +#: resources/qml_qt6/MeshToolsMenu.qml:31 msgctxt "@item:inmenu" msgid "Replace model..." msgid_plural "Replace models..." msgstr[0] "Remplacer modèle..." msgstr[1] "Remplacer modèles..." -#: qml/MeshToolsMenu.qml:38 qml_qt5/MeshToolsMenu.qml:37 +#: resources/qml_qt5/MeshToolsMenu.qml:37 +#: resources/qml_qt6/MeshToolsMenu.qml:38 msgctxt "@item:inmenu" msgid "Check mesh" msgid_plural "Check meshes" msgstr[0] "Vérifier le maillage" msgstr[1] "Vérifier les maillages" -#: qml/MeshToolsMenu.qml:44 qml_qt5/MeshToolsMenu.qml:43 +#: resources/qml_qt5/MeshToolsMenu.qml:43 +#: resources/qml_qt6/MeshToolsMenu.qml:44 msgctxt "@item:inmenu" msgid "Analyse mesh" msgid_plural "Analyse meshes" msgstr[0] "Analyser maillage" msgstr[1] "Analyser maillages" + +#: resources/qml_qt6/MeshToolsMenu.qml:15 +msgctxt "@item:inmenu" +msgid "Mesh Tools" +msgstr "Mesh Tools" diff --git a/resources/i18n/meshtools.pot b/resources/i18n/meshtools.pot index 8dcf8c7..47a116f 100644 --- a/resources/i18n/meshtools.pot +++ b/resources/i18n/meshtools.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mesh Tools\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-20 15:21+0000\n" +"POT-Creation-Date: 2023-07-26 09:50+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,322 +18,402 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -#: MeshTools.py:88 qml/MeshToolsMenu.qml:19 qml_qt5/MeshToolsMenu.qml:18 +#: MeshTools.py:94 resources/qml_qt5/MeshToolsMenu.qml:18 +#: resources/qml_qt6/MeshToolsMenu.qml:19 msgctxt "@item:inmenu" msgid "Reload model" msgstr "" -#: MeshTools.py:89 qml/MeshToolsMenu.qml:25 qml_qt5/MeshToolsMenu.qml:24 +#: MeshTools.py:95 resources/qml_qt5/MeshToolsMenu.qml:24 +#: resources/qml_qt6/MeshToolsMenu.qml:25 msgctxt "@item:inmenu" msgid "Rename model..." msgstr "" -#: MeshTools.py:90 +#: MeshTools.py:96 msgctxt "@item:inmenu" msgid "Replace models..." msgstr "" -#: MeshTools.py:92 +#: MeshTools.py:98 msgctxt "@item:inmenu" msgid "Check models" msgstr "" -#: MeshTools.py:93 +#: MeshTools.py:99 msgctxt "@item:inmenu" msgid "Analyse models" msgstr "" -#: MeshTools.py:94 qml/MeshToolsMenu.qml:50 qml_qt5/MeshToolsMenu.qml:49 +#: MeshTools.py:100 resources/qml_qt5/MeshToolsMenu.qml:49 +#: resources/qml_qt6/MeshToolsMenu.qml:50 msgctxt "@item:inmenu" msgid "Fix simple holes" msgstr "" -#: MeshTools.py:95 qml/MeshToolsMenu.qml:56 qml_qt5/MeshToolsMenu.qml:55 +#: MeshTools.py:101 resources/qml_qt5/MeshToolsMenu.qml:55 +#: resources/qml_qt6/MeshToolsMenu.qml:56 msgctxt "@item:inmenu" msgid "Fix model normals" msgstr "" -#: MeshTools.py:96 qml/MeshToolsMenu.qml:62 qml_qt5/MeshToolsMenu.qml:61 +#: MeshTools.py:102 resources/qml_qt5/MeshToolsMenu.qml:61 +#: resources/qml_qt6/MeshToolsMenu.qml:62 msgctxt "@item:inmenu" msgid "Split model into parts" msgid_plural "Split models into parts" msgstr[0] "" msgstr[1] "" -#: MeshTools.py:98 qml/MeshToolsMenu.qml:69 qml_qt5/MeshToolsMenu.qml:68 +#: MeshTools.py:104 resources/qml_qt5/MeshToolsMenu.qml:68 +#: resources/qml_qt6/MeshToolsMenu.qml:69 msgctxt "@item:inmenu" msgid "Randomise location" msgstr "" -#: MeshTools.py:99 qml/MeshToolsMenu.qml:75 qml_qt5/MeshToolsMenu.qml:74 +#: MeshTools.py:105 resources/qml_qt5/MeshToolsMenu.qml:74 +#: resources/qml_qt6/MeshToolsMenu.qml:75 +msgctxt "@item:inmenu" +msgid "Fixed location" +msgstr "" + +#: MeshTools.py:106 resources/qml_qt5/MeshToolsMenu.qml:80 +#: resources/qml_qt6/MeshToolsMenu.qml:81 msgctxt "@item:inmenu" msgid "Apply transformations to mesh" msgstr "" -#: MeshTools.py:100 qml/MeshToolsMenu.qml:81 qml_qt5/MeshToolsMenu.qml:80 +#: MeshTools.py:107 resources/qml_qt5/MeshToolsMenu.qml:86 +#: resources/qml_qt6/MeshToolsMenu.qml:87 msgctxt "@item:inmenu" msgid "Reset origin to center of mesh" msgstr "" -#: MeshTools.py:102 +#: MeshTools.py:109 msgctxt "@item:inmenu" msgid "Mesh Tools settings..." msgstr "" -#: MeshTools.py:104 MeshTools.py:145 MeshTools.py:219 +#: MeshTools.py:111 MeshTools.py:162 MeshTools.py:250 msgctxt "@info:title" msgid "Mesh Tools" msgstr "" -#: MeshTools.py:213 MeshTools.py:493 MeshTools.py:557 +#: MeshTools.py:210 +msgctxt "@info:status" +msgid "Randomise Location fixed by Mesh Tools" +msgstr "" + +#: MeshTools.py:216 +msgctxt "@info:status" +msgid "Location fixed by Mesh Tools" +msgstr "" + +#: MeshTools.py:244 MeshTools.py:529 MeshTools.py:613 msgctxt "@text Print job name" msgid "Untitled" msgstr "" -#: MeshTools.py:220 +#: MeshTools.py:251 #, python-format msgctxt "@info:status" msgid "Model %s is not watertight, and may not print properly." msgstr "" -#: MeshTools.py:225 +#: MeshTools.py:256 msgctxt "@info:status" msgid "Check X-Ray View and repair the model before printing it." msgstr "" -#: MeshTools.py:226 +#: MeshTools.py:257 msgctxt "@action:button" msgid "Show X-Ray View" msgstr "" -#: MeshTools.py:229 +#: MeshTools.py:260 msgctxt "@info:status" msgid "Repair the model before printing it." msgstr "" -#: MeshTools.py:267 +#: MeshTools.py:298 msgctxt "@info:status" msgid "Please select a single model first" msgstr "" -#: MeshTools.py:272 MeshTools.py:290 +#: MeshTools.py:303 MeshTools.py:321 msgctxt "@info:status" msgid "Please select one or more models first" msgstr "" -#: MeshTools.py:301 +#: MeshTools.py:332 msgctxt "@info:status" msgid "Check summary:" msgstr "" -#: MeshTools.py:306 +#: MeshTools.py:337 msgctxt "@info:status" msgid "is watertight" msgstr "" -#: MeshTools.py:308 +#: MeshTools.py:339 msgctxt "@info:status" msgid "is not watertight and may not print properly" msgstr "" -#: MeshTools.py:310 +#: MeshTools.py:341 #, python-brace-format msgctxt "@info:status" msgid "and consists of {body_count} submeshes" msgstr "" -#: MeshTools.py:321 +#: MeshTools.py:352 msgctxt "@info:status" msgid "Analysis summary:" msgstr "" -#: MeshTools.py:325 +#: MeshTools.py:356 #, python-format msgctxt "@info:status" msgid "%d vertices, %d faces" msgstr "" -#: MeshTools.py:327 +#: MeshTools.py:358 #, python-format msgctxt "@info:status" msgid "area: %d mm2, volume: %d mm3" msgstr "" -#: MeshTools.py:345 +#: MeshTools.py:376 msgctxt "@info:status" msgid "The mesh needs more extensive repair to become watertight" msgstr "" -#: MeshTools.py:366 +#: MeshTools.py:397 msgctxt "@info:status" msgid "Split result:" msgstr "" -#: MeshTools.py:372 +#: MeshTools.py:403 #, python-format msgctxt "@info:status" msgid "was split in %d submeshes" msgstr "" -#: MeshTools.py:374 +#: MeshTools.py:405 msgctxt "@info:status" msgid "could not be split into submeshes" msgstr "" -#: MeshTools.py:388 +#: MeshTools.py:419 msgctxt "@info:status" msgid "Replacing a group is not supported" msgstr "" -#: MeshTools.py:409 MeshTools.py:414 +#: MeshTools.py:440 MeshTools.py:445 msgctxt "@title:window" msgid "Select Replacement Mesh File" msgstr "" -#: MeshTools.py:458 +#: MeshTools.py:494 msgctxt "@info:status" msgid "Reloading a group is not supported" msgstr "" -#: MeshTools.py:465 +#: MeshTools.py:501 msgctxt "@info:status" msgid "No link to the original file was found" msgstr "" -#: MeshTools.py:477 +#: MeshTools.py:513 msgctxt "@info:status" msgid "Failed to load mesh" msgstr "" -#: MeshTools.py:484 +#: MeshTools.py:520 msgctxt "@info:status" msgid "Replacing meshes with a group of meshes is not supported" msgstr "" -#: qml/SettingsDialog.qml:15 qml_qt5/SettingsDialog.qml:17 +#: resources/qml_qt5/SettingsDialog.qml:18 +#: resources/qml_qt6/SettingsDialog.qml:16 msgctxt "@title:window" msgid "Mesh Tools Settings" msgstr "" -#: qml/SettingsDialog.qml:49 qml_qt5/SettingsDialog.qml:51 +#: resources/qml_qt5/SettingsDialog.qml:52 +#: resources/qml_qt6/SettingsDialog.qml:50 msgctxt "@info:tooltip" msgid "Check if models are watertight when loading them" msgstr "" -#: qml/SettingsDialog.qml:53 qml_qt5/SettingsDialog.qml:55 +#: resources/qml_qt5/SettingsDialog.qml:56 +#: resources/qml_qt6/SettingsDialog.qml:54 msgctxt "@option:check" msgid "Check models on load" msgstr "" -#: qml/SettingsDialog.qml:63 qml_qt5/SettingsDialog.qml:65 +#: resources/qml_qt5/SettingsDialog.qml:66 +#: resources/qml_qt6/SettingsDialog.qml:64 msgctxt "@info:tooltip" msgid "Always recalculate model normals when loading them" msgstr "" -#: qml/SettingsDialog.qml:67 qml_qt5/SettingsDialog.qml:69 +#: resources/qml_qt5/SettingsDialog.qml:70 +#: resources/qml_qt6/SettingsDialog.qml:68 msgctxt "@option:check" msgid "Fix normals on load" msgstr "" -#: qml/SettingsDialog.qml:80 qml_qt5/SettingsDialog.qml:82 +#: resources/qml_qt5/SettingsDialog.qml:83 +#: resources/qml_qt6/SettingsDialog.qml:81 msgctxt "@info:tooltip" msgid "" "Unit to convert meshes from when the file does not specify a unit (such as " "STL files). All units will be converted to millimeters." msgstr "" -#: qml/SettingsDialog.qml:88 qml_qt5/SettingsDialog.qml:90 +#: resources/qml_qt5/SettingsDialog.qml:91 +#: resources/qml_qt6/SettingsDialog.qml:89 msgctxt "@window:text" msgid "Unit for files that don't specify a unit:" msgstr "" -#: qml/SettingsDialog.qml:96 qml_qt5/SettingsDialog.qml:104 +#: resources/qml_qt5/SettingsDialog.qml:105 +#: resources/qml_qt6/SettingsDialog.qml:97 msgctxt "@option:unit" msgid "Micron" msgstr "" -#: qml/SettingsDialog.qml:97 qml_qt5/SettingsDialog.qml:105 +#: resources/qml_qt5/SettingsDialog.qml:106 +#: resources/qml_qt6/SettingsDialog.qml:98 msgctxt "@option:unit" msgid "Millimeter (default)" msgstr "" -#: qml/SettingsDialog.qml:98 qml_qt5/SettingsDialog.qml:106 +#: resources/qml_qt5/SettingsDialog.qml:107 +#: resources/qml_qt6/SettingsDialog.qml:99 msgctxt "@option:unit" msgid "Centimeter" msgstr "" -#: qml/SettingsDialog.qml:99 qml_qt5/SettingsDialog.qml:107 +#: resources/qml_qt5/SettingsDialog.qml:108 +#: resources/qml_qt6/SettingsDialog.qml:100 msgctxt "@option:unit" msgid "Meter" msgstr "" -#: qml/SettingsDialog.qml:100 qml_qt5/SettingsDialog.qml:108 +#: resources/qml_qt5/SettingsDialog.qml:109 +#: resources/qml_qt6/SettingsDialog.qml:101 msgctxt "@option:unit" msgid "Inch" msgstr "" -#: qml/SettingsDialog.qml:101 qml_qt5/SettingsDialog.qml:109 +#: resources/qml_qt5/SettingsDialog.qml:110 +#: resources/qml_qt6/SettingsDialog.qml:102 msgctxt "@option:unit" msgid "Feet" msgstr "" -#: qml/SettingsDialog.qml:143 qml_qt5/SettingsDialog.qml:140 +#: resources/qml_qt5/SettingsDialog.qml:141 +#: resources/qml_qt6/SettingsDialog.qml:144 msgctxt "@info:tooltip" msgid "Place models at a random location on the build plate when loading them" msgstr "" -#: qml/SettingsDialog.qml:147 qml_qt5/SettingsDialog.qml:144 +#: resources/qml_qt5/SettingsDialog.qml:147 +#: resources/qml_qt6/SettingsDialog.qml:150 msgctxt "@option:check" msgid "Randomize position on load" msgstr "" -#: qml/SettingsDialog.qml:158 qml_qt5/SettingsDialog.qml:155 +#: resources/qml_qt5/SettingsDialog.qml:157 +#: resources/qml_qt6/SettingsDialog.qml:160 +msgctxt "@info:tooltip" +msgid "" +"Place models at a specific location on the build plate when loading them" +msgstr "" + +#: resources/qml_qt5/SettingsDialog.qml:163 +#: resources/qml_qt6/SettingsDialog.qml:166 +msgctxt "@option:check" +msgid "Set position on load" +msgstr "" + +#: resources/qml_qt5/SettingsDialog.qml:174 +#: resources/qml_qt6/SettingsDialog.qml:176 +msgctxt "@info:tooltip" +msgid "X position relative / Bed Center" +msgstr "" + +#: resources/qml_qt5/SettingsDialog.qml:179 +#: resources/qml_qt6/SettingsDialog.qml:181 +msgctxt "@label:text" +msgid "X position" +msgstr "" + +#: resources/qml_qt5/SettingsDialog.qml:213 +#: resources/qml_qt6/SettingsDialog.qml:209 +msgctxt "@info:tooltip" +msgid "Y position relative / Bed Center" +msgstr "" + +#: resources/qml_qt5/SettingsDialog.qml:218 +#: resources/qml_qt6/SettingsDialog.qml:214 +msgctxt "@label:text" +msgid "Y position" +msgstr "" + +#: resources/qml_qt5/SettingsDialog.qml:254 +#: resources/qml_qt6/SettingsDialog.qml:246 msgctxt "@action:button" msgid "Close" msgstr "" -#: qml/RenameDialog.qml:25 qml_qt5/RenameDialog.qml:24 +#: resources/qml_qt5/RenameDialog.qml:24 resources/qml_qt6/RenameDialog.qml:25 msgctxt "@title:window" msgid "Rename" msgstr "" -#: qml/RenameDialog.qml:26 qml_qt5/RenameDialog.qml:25 +#: resources/qml_qt5/RenameDialog.qml:25 resources/qml_qt6/RenameDialog.qml:26 msgctxt "@info" msgid "Please provide a new name." msgstr "" -#: qml/RenameDialog.qml:66 qml_qt5/RenameDialog.qml:74 +#: resources/qml_qt5/RenameDialog.qml:74 resources/qml_qt6/RenameDialog.qml:66 msgctxt "@action:button" msgid "Cancel" msgstr "" -#: qml/RenameDialog.qml:72 qml_qt5/RenameDialog.qml:79 +#: resources/qml_qt5/RenameDialog.qml:79 resources/qml_qt6/RenameDialog.qml:72 msgctxt "@action:button" msgid "OK" msgstr "" -#: qml/MeshToolsMenu.qml:15 -msgctxt "@item:inmenu" -msgid "Mesh Tools" -msgstr "" - -#: qml/MeshToolsMenu.qml:31 qml_qt5/MeshToolsMenu.qml:30 +#: resources/qml_qt5/MeshToolsMenu.qml:30 +#: resources/qml_qt6/MeshToolsMenu.qml:31 msgctxt "@item:inmenu" msgid "Replace model..." msgid_plural "Replace models..." msgstr[0] "" msgstr[1] "" -#: qml/MeshToolsMenu.qml:38 qml_qt5/MeshToolsMenu.qml:37 +#: resources/qml_qt5/MeshToolsMenu.qml:37 +#: resources/qml_qt6/MeshToolsMenu.qml:38 msgctxt "@item:inmenu" msgid "Check mesh" msgid_plural "Check meshes" msgstr[0] "" msgstr[1] "" -#: qml/MeshToolsMenu.qml:44 qml_qt5/MeshToolsMenu.qml:43 +#: resources/qml_qt5/MeshToolsMenu.qml:43 +#: resources/qml_qt6/MeshToolsMenu.qml:44 msgctxt "@item:inmenu" msgid "Analyse mesh" msgid_plural "Analyse meshes" msgstr[0] "" msgstr[1] "" + +#: resources/qml_qt6/MeshToolsMenu.qml:15 +msgctxt "@item:inmenu" +msgid "Mesh Tools" +msgstr "" diff --git a/resources/qml_qt5/MeshToolsMenu.qml b/resources/qml_qt5/MeshToolsMenu.qml index 9239cd5..b88340f 100644 --- a/resources/qml_qt5/MeshToolsMenu.qml +++ b/resources/qml_qt5/MeshToolsMenu.qml @@ -1,5 +1,5 @@ -// Copyright (c) 2016 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. +// Copyright (c) 2023 Aldo Hoeben / fieldOfView +// MeshTools is released under the terms of the AGPLv3 or higher. import QtQuick 2.2 import QtQuick.Controls 1.1 @@ -70,6 +70,12 @@ Menu onTriggered: manager.randomiseMeshLocation() } MenuItem + { + text: catalog.i18nc("@item:inmenu", "Fixed location") + enabled: UM.Selection.hasSelection + onTriggered: manager.setMeshLocation() + } + MenuItem { text: catalog.i18nc("@item:inmenu", "Apply transformations to mesh") enabled: UM.Selection.hasSelection diff --git a/resources/qml_qt5/SettingsDialog.qml b/resources/qml_qt5/SettingsDialog.qml index e3ebc3f..08c6fc7 100644 --- a/resources/qml_qt5/SettingsDialog.qml +++ b/resources/qml_qt5/SettingsDialog.qml @@ -5,6 +5,7 @@ import QtQuick 2.1 import QtQuick.Controls 1.1 import QtQuick.Dialogs 1.2 import QtQuick.Window 2.1 +import QtQuick.Layouts 1.1 import UM 1.3 as UM import Cura 1.0 as Cura @@ -141,11 +142,109 @@ UM.Dialog CheckBox { + id: checkRandom + enabled: !checkPosition.checked text: catalog.i18nc("@option:check", "Randomize position on load") checked: boolCheck(UM.Preferences.getValue("meshtools/randomise_location_on_load")) onCheckedChanged: UM.Preferences.setValue("meshtools/randomise_location_on_load", checked) } } + + UM.TooltipArea + { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip", "Place models at a specific location on the build plate when loading them") + + CheckBox + { + id: checkPosition + enabled: !checkRandom.checked + text: catalog.i18nc("@option:check", "Set position on load") + checked: boolCheck(UM.Preferences.getValue("meshtools/set_location_on_load")) + onCheckedChanged: UM.Preferences.setValue("meshtools/set_location_on_load", checked) + } + } + + + UM.TooltipArea + { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip", "X position relative / Bed Center") + + Label + { + id: label_X + text: catalog.i18nc("@label:text", "X position") + } + TextField + { + id: field_X + width: UM.Theme.getSize("setting_control").width + height: UM.Theme.getSize("setting_control").height + text: UM.Preferences.getValue("meshtools/set_location_x") + + anchors.left: label_X.right + + validator: DoubleValidator + { + decimals: 1 + locale: "en_US" + } + + onEditingFinished: + { + var modified_text = text.replace(",", ".") // User convenience. We use dots for decimal values + UM.Preferences.setValue("meshtools/set_location_x", modified_text) + } + } + Label + { + text: "mm" + + anchors.left: field_X.right + } + } + UM.TooltipArea + { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip", "Y position relative / Bed Center") + + Label + { + id: label_Y + text: catalog.i18nc("@label:text", "Y position") + } + TextField + { + id: field_Y + width: UM.Theme.getSize("setting_control").width + height: UM.Theme.getSize("setting_control").height + text: UM.Preferences.getValue("meshtools/set_location_y") + + anchors.left: label_Y.right + + validator: DoubleValidator + { + decimals: 1 + locale: "en_US" + } + + onEditingFinished: + { + var modified_text = text.replace(",", ".") // User convenience. We use dots for decimal values + UM.Preferences.setValue("meshtools/set_location_y", modified_text) + } + } + Label + { + text: "mm" + + anchors.left: field_Y.right + } + } } rightButtons: [ diff --git a/resources/qml/MeshToolsMenu.qml b/resources/qml_qt6/MeshToolsMenu.qml similarity index 90% rename from resources/qml/MeshToolsMenu.qml rename to resources/qml_qt6/MeshToolsMenu.qml index 5014832..9ffc8fb 100644 --- a/resources/qml/MeshToolsMenu.qml +++ b/resources/qml_qt6/MeshToolsMenu.qml @@ -1,5 +1,5 @@ -// Copyright (c) 2016 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. +// Copyright (c) 2023 Aldo Hoeben / fieldOfView +// MeshTools is released under the terms of the AGPLv3 or higher. import QtQuick 2.1 @@ -69,6 +69,12 @@ Cura.Menu text: catalog.i18nc("@item:inmenu", "Randomise location") enabled: UM.Selection.hasSelection onTriggered: manager.randomiseMeshLocation() + } + Cura.MenuItem + { + text: catalog.i18nc("@item:inmenu", "Fixed location") + enabled: UM.Selection.hasSelection + onTriggered: manager.setMeshLocation() } Cura.MenuItem { diff --git a/resources/qml/RenameDialog.qml b/resources/qml_qt6/RenameDialog.qml similarity index 100% rename from resources/qml/RenameDialog.qml rename to resources/qml_qt6/RenameDialog.qml diff --git a/resources/qml/SettingsDialog.qml b/resources/qml_qt6/SettingsDialog.qml similarity index 68% rename from resources/qml/SettingsDialog.qml rename to resources/qml_qt6/SettingsDialog.qml index 947e610..5473ec3 100644 --- a/resources/qml/SettingsDialog.qml +++ b/resources/qml_qt6/SettingsDialog.qml @@ -1,11 +1,12 @@ // Copyright (c) 2023 Aldo Hoeben / fieldOfView // MeshTools is released under the terms of the AGPLv3 or higher. -import QtQuick 2.1 -import QtQuick.Controls 2.0 +import QtQuick 6.0 +import QtQuick.Controls 6.0 +import QtQuick.Layouts 6.0 -import UM 1.5 as UM -import Cura 1.1 as Cura +import UM 1.6 as UM +import Cura 1.7 as Cura UM.Dialog @@ -144,11 +145,98 @@ UM.Dialog UM.CheckBox { + id: checkRandom + enabled: !checkPosition.checked text: catalog.i18nc("@option:check", "Randomize position on load") checked: boolCheck(UM.Preferences.getValue("meshtools/randomise_location_on_load")) onCheckedChanged: UM.Preferences.setValue("meshtools/randomise_location_on_load", checked) } } + + UM.TooltipArea + { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip", "Place models at a specific location on the build plate when loading them") + + UM.CheckBox + { + id: checkPosition + enabled: !checkRandom.checked + text: catalog.i18nc("@option:check", "Set position on load") + checked: boolCheck(UM.Preferences.getValue("meshtools/set_location_on_load")) + onCheckedChanged: UM.Preferences.setValue("meshtools/set_location_on_load", checked) + } + } + + UM.TooltipArea + { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip", "X position relative / Bed Center") + + UM.Label + { + id: label_X + text: catalog.i18nc("@label:text", "X position") + } + UM.TextFieldWithUnit + { + width: UM.Theme.getSize("setting_control").width + height: UM.Theme.getSize("setting_control").height + unit: "mm" + text: UM.Preferences.getValue("meshtools/set_location_x") + + anchors.left: label_X.right + + validator: DoubleValidator + { + decimals: 1 + locale: "en_US" + } + + onEditingFinished: + { + var modified_text = text.replace(",", ".") // User convenience. We use dots for decimal values + UM.Preferences.setValue("meshtools/set_location_x", modified_text) + } + } + } + UM.TooltipArea + { + width: childrenRect.width + height: childrenRect.height + text: catalog.i18nc("@info:tooltip", "Y position relative / Bed Center") + + UM.Label + { + id: label_Y + text: catalog.i18nc("@label:text", "Y position") + } + UM.TextFieldWithUnit + { + width: UM.Theme.getSize("setting_control").width + height: UM.Theme.getSize("setting_control").height + unit: "mm" + text: UM.Preferences.getValue("meshtools/set_location_y") + + anchors.left: label_Y.right + + validator: DoubleValidator + { + decimals: 1 + locale: "en_US" + } + + onEditingFinished: + { + var modified_text = text.replace(",", ".") // User convenience. We use dots for decimal values + UM.Preferences.setValue("meshtools/set_location_y", modified_text) + } + } + + } + } rightButtons: [