From d8d226c0d654b3dbfc05e800785a013db8cc1642 Mon Sep 17 00:00:00 2001 From: Jack Ha Date: Wed, 21 Mar 2018 16:55:58 +0100 Subject: CURA-4557 it's now a small button next to the job spec when one of the warping materials is selected --- plugins/ModelChecker/ModelChecker.py | 138 +++++++++++++++++++++++---------- plugins/ModelChecker/ModelChecker.qml | 47 +++++++++++ plugins/ModelChecker/__init__.py | 15 +--- plugins/ModelChecker/model_checker.svg | 6 +- 4 files changed, 151 insertions(+), 55 deletions(-) create mode 100644 plugins/ModelChecker/ModelChecker.qml (limited to 'plugins/ModelChecker') diff --git a/plugins/ModelChecker/ModelChecker.py b/plugins/ModelChecker/ModelChecker.py index afe8a7e47d..285002deda 100644 --- a/plugins/ModelChecker/ModelChecker.py +++ b/plugins/ModelChecker/ModelChecker.py @@ -1,13 +1,16 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import QTimer -from cura.Scene.CuraSceneNode import CuraSceneNode +import os + +from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, pyqtProperty from UM.Application import Application -from UM.Tool import Tool +from UM.Extension import Extension +from UM.Logger import Logger from UM.Message import Message from UM.i18n import i18nCatalog +from UM.PluginRegistry import PluginRegistry from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator catalog = i18nCatalog("cura") @@ -17,35 +20,34 @@ SHRINKAGE_THRESHOLD = 0.5 WARNING_SIZE_XY = 150 WARNING_SIZE_Z = 100 +# Use this when actual shrinkage data is not in fdm_materials yet +MATERIALS_LOOKUP = { + "generic_abs": 1, + "generic_pc": 1, + "generic_pp": 1, + "generic_cpe_plus": 1 +} + + +class ModelChecker(QObject, Extension): + + needCheckChanged = pyqtSignal() -class ModelChecker(Tool): def __init__(self): super().__init__() - self._last_known_tool_id = None + self._button_view = None + self._need_checks = False - self._controller.activeToolChanged.connect(self._onActiveToolChanged) + Application.getInstance().initializationFinished.connect(self.bindSignals) - def checkObjects(self, nodes_to_check): - warning_nodes = [] - global_container_stack = Application.getInstance().getGlobalContainerStack() - if global_container_stack is None: - return [] - material_shrinkage = {} - need_check = False + def bindSignals(self): + Application.getInstance().getMachineManager().rootMaterialChanged.connect(self._onChanged) - # Get all shrinkage values of materials used - for extruder_position, extruder in global_container_stack.extruders.items(): - shrinkage = extruder.material.getProperty("material_shrinkage_percentage", "value") - if shrinkage is None: - shrinkage = 0 - if shrinkage > SHRINKAGE_THRESHOLD: - need_check = True - material_shrinkage[extruder_position] = shrinkage + def checkObjectsForShrinkage(self, nodes_to_check): + material_shrinkage = self.getMaterialShrinkage() - # Check if we can bail out fast - if not need_check: - return + warning_nodes = [] # Check node material shrinkage and bounding box size for node in nodes_to_check: @@ -64,7 +66,7 @@ class ModelChecker(Tool): for node in DepthFirstIterator(scene.getRoot()): if node.callDecoration("isSliceable"): nodes_to_check.append(node) - return self.checkObjects(nodes_to_check) + return self.checkObjectsForShrinkage(nodes_to_check) ## Display warning message def showWarningMessage(self, warning_nodes): @@ -82,23 +84,77 @@ class ModelChecker(Tool): def showHappyMessage(self): happy_message = Message(catalog.i18nc( "@info:status", - "The Model Checker did not detect any problems with your model / print setup combination."), + "The Model Checker did not detect any problems with your model / chosen materials combination."), lifetime = 5, title = catalog.i18nc("@info:title", "Model Checker")) happy_message.show() - def _onActiveToolChanged(self): - active_tool = self.getController().getActiveTool() - if active_tool is None: - return - active_tool_id = active_tool.getPluginId() - if active_tool_id != self.getPluginId(): - self._last_known_tool_id = active_tool_id - if active_tool_id == self.getPluginId(): - warning_nodes = self.checkAllSliceableNodes() - if warning_nodes: - self.showWarningMessage(warning_nodes) - else: - self.showHappyMessage() - if self._last_known_tool_id is not None: - self.getController().setActiveTool(self._last_known_tool_id) + ## Creates the view used by show popup. The view is saved because of the fairly aggressive garbage collection. + def _createView(self): + Logger.log("d", "Creating model checker view.") + + # Create the plugin dialog component + path = os.path.join(PluginRegistry.getInstance().getPluginPath("ModelChecker"), "ModelChecker.qml") + self._button_view = Application.getInstance().createQmlComponent(path, {"manager": self}) + + # The qml is only the button + Application.getInstance().addAdditionalComponent("jobSpecsButton", self._button_view) + + Logger.log("d", "Model checker view created.") + + def _onChanged(self, *args): + if self._button_view is None: + self._createView() + old_need_checks = self._need_checks + self._need_checks = self.calculateNeedCheck() + if old_need_checks != self._need_checks: + self.needCheckChanged.emit() + + @pyqtSlot() + def runChecks(self): + warning_nodes = self.checkAllSliceableNodes() + if warning_nodes: + self.showWarningMessage(warning_nodes) + else: + self.showHappyMessage() + + # TODO: use this if branch feature_model_check is merged in fdm_materials to master + # def getMaterialShrinkage(self): + # global_container_stack = Application.getInstance().getGlobalContainerStack() + # if global_container_stack is None: + # return {} + # + # material_shrinkage = {} + # # Get all shrinkage values of materials used + # for extruder_position, extruder in global_container_stack.extruders.items(): + # shrinkage = extruder.material.getProperty("material_shrinkage_percentage", "value") + # if shrinkage is None: + # shrinkage = 0 + # material_shrinkage[extruder_position] = shrinkage + # return material_shrinkage + + def getMaterialShrinkage(self): + global_container_stack = Application.getInstance().getGlobalContainerStack() + if global_container_stack is None: + return {} + + material_shrinkage = {} + # Get all shrinkage values of materials used + for extruder_position, extruder in global_container_stack.extruders.items(): + base_file = extruder.material.getMetaDataEntry("base_file") + shrinkage = MATERIALS_LOOKUP.get(base_file, 0) + material_shrinkage[extruder_position] = shrinkage + return material_shrinkage + + @pyqtProperty(bool, notify = needCheckChanged) + def needCheck(self): + return self._need_checks + + def calculateNeedCheck(self): + need_check = False + + for shrinkage in self.getMaterialShrinkage().values(): + if shrinkage > SHRINKAGE_THRESHOLD: + need_check = True + + return need_check diff --git a/plugins/ModelChecker/ModelChecker.qml b/plugins/ModelChecker/ModelChecker.qml new file mode 100644 index 0000000000..77a483c2c6 --- /dev/null +++ b/plugins/ModelChecker/ModelChecker.qml @@ -0,0 +1,47 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Window 2.2 + +import UM 1.2 as UM +import Cura 1.0 as Cura + + +Button +{ + id: modelCheckerButton + + UM.I18nCatalog{id: catalog; name:"cura"} + + visible: manager.needCheck + tooltip: catalog.i18nc("@info:tooltip", "Check current setup for known problems.") + onClicked: manager.runChecks() + + //anchors.leftMargin: UM.Theme.getSize("default_margin").width + + //anchors.right: parent.right + //anchors.verticalCenter: parent.verticalCenter + width: UM.Theme.getSize("save_button_specs_icons").width + height: UM.Theme.getSize("save_button_specs_icons").height + + style: ButtonStyle + { + background: Item + { + UM.RecolorImage + { + width: UM.Theme.getSize("save_button_specs_icons").width; + height: UM.Theme.getSize("save_button_specs_icons").height; + sourceSize.width: width; + sourceSize.height: width; + color: control.hovered ? UM.Theme.getColor("text_scene_hover") : UM.Theme.getColor("text_scene"); + source: "model_checker.svg" + } + } + } +} diff --git a/plugins/ModelChecker/__init__.py b/plugins/ModelChecker/__init__.py index b2b8587a7a..5f4d443729 100644 --- a/plugins/ModelChecker/__init__.py +++ b/plugins/ModelChecker/__init__.py @@ -1,21 +1,14 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # This example is released under the terms of the AGPLv3 or higher. from . import ModelChecker from UM.i18n import i18nCatalog -i18n_catalog = i18nCatalog("uranium") +i18n_catalog = i18nCatalog("cura") def getMetaData(): - return { - "tool": { - "name": i18n_catalog.i18nc("@label", "Model Checker"), - "description": i18n_catalog.i18nc("@info:tooltip", "Checks models and print configuration for possible printing issues and give suggestions."), - "icon": "model_checker.svg", - "weight": 10 - } - } + return {} def register(app): - return { "tool": ModelChecker.ModelChecker() } + return { "extension": ModelChecker.ModelChecker() } diff --git a/plugins/ModelChecker/model_checker.svg b/plugins/ModelChecker/model_checker.svg index ca5228155a..5b9dd4d197 100644 --- a/plugins/ModelChecker/model_checker.svg +++ b/plugins/ModelChecker/model_checker.svg @@ -1,10 +1,10 @@ ModelChecker - - + + - + -- cgit v1.2.3