diff --git a/cura/Arranging/Arrange.py b/cura/Arranging/Arrange.py index 1027b39199..21ed45dbf1 100644 --- a/cura/Arranging/Arrange.py +++ b/cura/Arranging/Arrange.py @@ -3,6 +3,7 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Logger import Logger +from UM.Math.Polygon import Polygon from UM.Math.Vector import Vector from cura.Arranging.ShapeArray import ShapeArray from cura.Scene import ZOffsetDecorator @@ -45,7 +46,7 @@ class Arrange: # \param scene_root Root for finding all scene nodes # \param fixed_nodes Scene nodes to be placed @classmethod - def create(cls, scene_root = None, fixed_nodes = None, scale = 0.5, x = 350, y = 250): + def create(cls, scene_root = None, fixed_nodes = None, scale = 0.5, x = 350, y = 250, min_offset = 8): arranger = Arrange(x, y, x // 2, y // 2, scale = scale) arranger.centerFirst() @@ -58,9 +59,10 @@ class Arrange: # Place all objects fixed nodes for fixed_node in fixed_nodes: - vertices = fixed_node.callDecoration("getConvexHull") + vertices = fixed_node.callDecoration("getConvexHullHead") or fixed_node.callDecoration("getConvexHull") if not vertices: continue + vertices = vertices.getMinkowskiHull(Polygon.approximatedCircle(min_offset)) points = copy.deepcopy(vertices._points) shape_arr = ShapeArray.fromPolygon(points, scale = scale) arranger.place(0, 0, shape_arr) @@ -81,12 +83,12 @@ class Arrange: ## Find placement for a node (using offset shape) and place it (using hull shape) # return the nodes that should be placed # \param node - # \param offset_shape_arr ShapeArray with offset, used to find location - # \param hull_shape_arr ShapeArray without offset, for placing the shape + # \param offset_shape_arr ShapeArray with offset, for placing the shape + # \param hull_shape_arr ShapeArray without offset, used to find location def findNodePlacement(self, node, offset_shape_arr, hull_shape_arr, step = 1): new_node = copy.deepcopy(node) best_spot = self.bestSpot( - offset_shape_arr, start_prio = self._last_priority, step = step) + hull_shape_arr, start_prio = self._last_priority, step = step) x, y = best_spot.x, best_spot.y # Save the last priority. @@ -102,7 +104,7 @@ class Arrange: if x is not None: # We could find a place new_node.setPosition(Vector(x, center_y, y)) found_spot = True - self.place(x, y, hull_shape_arr) # place the object in arranger + self.place(x, y, offset_shape_arr) # place the object in arranger else: Logger.log("d", "Could not find spot!"), found_spot = False diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index 08fd1985a9..5e982582fd 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -37,7 +37,7 @@ class ArrangeObjectsJob(Job): machine_width = global_container_stack.getProperty("machine_width", "value") machine_depth = global_container_stack.getProperty("machine_depth", "value") - arranger = Arrange.create(x = machine_width, y = machine_depth, fixed_nodes = self._fixed_nodes) + arranger = Arrange.create(x = machine_width, y = machine_depth, fixed_nodes = self._fixed_nodes, min_offset = self._min_offset) # Collect nodes to be placed nodes_arr = [] # fill with (size, node, offset_shape_arr, hull_shape_arr) @@ -66,7 +66,7 @@ class ArrangeObjectsJob(Job): start_priority = last_priority else: start_priority = 0 - best_spot = arranger.bestSpot(offset_shape_arr, start_prio=start_priority) + best_spot = arranger.bestSpot(hull_shape_arr, start_prio = start_priority) x, y = best_spot.x, best_spot.y node.removeDecorator(ZOffsetDecorator) if node.getBoundingBox(): @@ -77,7 +77,7 @@ class ArrangeObjectsJob(Job): last_size = size last_priority = best_spot.priority - arranger.place(x, y, hull_shape_arr) # take place before the next one + arranger.place(x, y, offset_shape_arr) # take place before the next one grouped_operation.addOperation(TranslateOperation(node, Vector(x, center_y, y), set_position = True)) else: Logger.log("d", "Arrange all: could not find spot!") diff --git a/cura/CuraPackageManager.py b/cura/CuraPackageManager.py index 52f31020e6..91507bab7d 100644 --- a/cura/CuraPackageManager.py +++ b/cura/CuraPackageManager.py @@ -158,14 +158,17 @@ class CuraPackageManager(QObject): # Add bundled plugins if package_id in self._bundled_package_dict: package_info = self._bundled_package_dict[package_id]["package_info"] + package_info["is_installed"] = True # Add installed plugins if package_id in self._installed_package_dict: package_info = self._installed_package_dict[package_id]["package_info"] + package_info["is_installed"] = True # Add to install plugins if package_id in self._to_install_package_dict: package_info = self._to_install_package_dict[package_id]["package_info"] + package_info["is_installed"] = False if package_info is None: continue diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index af24036eeb..57db7734e7 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -38,7 +38,7 @@ class MultiplyObjectsJob(Job): root = scene.getRoot() scale = 0.5 - arranger = Arrange.create(x = machine_width, y = machine_depth, scene_root = root, scale = scale) + arranger = Arrange.create(x = machine_width, y = machine_depth, scene_root = root, scale = scale, min_offset = self._min_offset) processed_nodes = [] nodes = [] diff --git a/plugins/3MFReader/ThreeMFReader.py b/plugins/3MFReader/ThreeMFReader.py index 2ecea82691..5423ee0caa 100755 --- a/plugins/3MFReader/ThreeMFReader.py +++ b/plugins/3MFReader/ThreeMFReader.py @@ -15,7 +15,6 @@ from UM.Math.Vector import Vector from UM.Mesh.MeshBuilder import MeshBuilder from UM.Mesh.MeshReader import MeshReader from UM.Scene.GroupDecorator import GroupDecorator -from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType from cura.Settings.ExtruderManager import ExtruderManager from cura.Scene.CuraSceneNode import CuraSceneNode @@ -26,15 +25,6 @@ from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch MYPY = False - -MimeTypeDatabase.addMimeType( - MimeType( - name = "application/x-cura-project-file", - comment = "Cura Project File", - suffixes = ["curaproject.3mf"] - ) -) - try: if not MYPY: import xml.etree.cElementTree as ET diff --git a/plugins/3MFReader/__init__.py b/plugins/3MFReader/__init__.py index ddaf76e01e..e545fb9f87 100644 --- a/plugins/3MFReader/__init__.py +++ b/plugins/3MFReader/__init__.py @@ -13,8 +13,24 @@ from . import ThreeMFWorkspaceReader from UM.i18n import i18nCatalog from UM.Platform import Platform +from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType catalog = i18nCatalog("cura") +MimeTypeDatabase.addMimeType( + MimeType( + name = "application/x-cura-project-file", + comment = "Cura Project File", + suffixes = ["curaproject.3mf"] + ) +) +MimeTypeDatabase.addMimeType( + MimeType( + name = "application/x-cura-project-file", + comment = "Cura Project File", + suffixes = ["3mf"] + ) +) + def getMetaData() -> Dict: # Workarround for osx not supporting double file extensions correctly. if Platform.isOSX(): diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml index 0ae738b71d..b0aecfc9a2 100644 --- a/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml +++ b/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml @@ -13,6 +13,16 @@ Column width: UM.Theme.getSize("toolbox_action_button").width spacing: UM.Theme.getSize("narrow_margin").height + Label + { + visible: !model.is_installed + text: catalog.i18nc("@label", "Will install upon restarting") + color: UM.Theme.getColor("lining") + font: UM.Theme.getFont("default") + wrapMode: Text.WordWrap + width: parent.width + } + ToolboxProgressButton { id: updateButton @@ -39,7 +49,7 @@ Column { id: removeButton text: canDowngrade ? catalog.i18nc("@action:button", "Downgrade") : catalog.i18nc("@action:button", "Uninstall") - visible: !model.is_bundled + visible: !model.is_bundled && model.is_installed enabled: !toolbox.isDownloading style: ButtonStyle { diff --git a/plugins/Toolbox/src/PackagesModel.py b/plugins/Toolbox/src/PackagesModel.py index 5ec3eba1d8..2a3b169e87 100644 --- a/plugins/Toolbox/src/PackagesModel.py +++ b/plugins/Toolbox/src/PackagesModel.py @@ -29,8 +29,9 @@ class PackagesModel(ListModel): self.addRoleName(Qt.UserRole + 12, "last_updated") self.addRoleName(Qt.UserRole + 13, "is_bundled") self.addRoleName(Qt.UserRole + 14, "is_enabled") - self.addRoleName(Qt.UserRole + 15, "has_configs") - self.addRoleName(Qt.UserRole + 16, "supported_configs") + self.addRoleName(Qt.UserRole + 15, "is_installed") # Scheduled pkgs are included in the model but should not be marked as actually installed + self.addRoleName(Qt.UserRole + 16, "has_configs") + self.addRoleName(Qt.UserRole + 17, "supported_configs") # List of filters for queries. The result is the union of the each list of results. self._filter = {} # type: Dict[str, str] @@ -73,6 +74,7 @@ class PackagesModel(ListModel): "last_updated": package["last_updated"] if "last_updated" in package else None, "is_bundled": package["is_bundled"] if "is_bundled" in package else False, "is_enabled": package["is_enabled"] if "is_enabled" in package else False, + "is_installed": package["is_installed"] if "is_installed" in package else False, "has_configs": has_configs, "supported_configs": configs_model })