diff --git a/.gitignore b/.gitignore index 60b59e6829..2ec5af2b9b 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ run.sh .scannerwork/ CuraEngine +/.coverage diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 1bc55d76f9..0310526c2e 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -114,6 +114,7 @@ from cura.UI.ObjectsModel import ObjectsModel from cura.UI.TextManager import TextManager from cura.UI.AddPrinterPagesModel import AddPrinterPagesModel from cura.UI.WelcomePagesModel import WelcomePagesModel +from cura.UI.WhatsNewPagesModel import WhatsNewPagesModel from .SingleInstance import SingleInstance from .AutoSave import AutoSave @@ -219,6 +220,7 @@ class CuraApplication(QtApplication): self._first_start_machine_actions_model = FirstStartMachineActionsModel(self) self._welcome_pages_model = WelcomePagesModel(self) self._add_printer_pages_model = AddPrinterPagesModel(self) + self._whats_new_pages_model = WhatsNewPagesModel(self) self._text_manager = TextManager(self) self._quality_profile_drop_down_menu_model = None @@ -765,6 +767,7 @@ class CuraApplication(QtApplication): self._output_device_manager.start() self._welcome_pages_model.initialize() self._add_printer_pages_model.initialize() + self._whats_new_pages_model.initialize() # Detect in which mode to run and execute that mode if self._is_headless: @@ -880,6 +883,10 @@ class CuraApplication(QtApplication): def getAddPrinterPagesModel(self, *args) -> "AddPrinterPagesModel": return self._add_printer_pages_model + @pyqtSlot(result = QObject) + def getWhatsNewPagesModel(self, *args) -> "WhatsNewPagesModel": + return self._whats_new_pages_model + @pyqtSlot(result = QObject) def getMachineSettingsManager(self, *args) -> "MachineSettingsManager": return self._machine_settings_manager @@ -1021,6 +1028,7 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager) qmlRegisterType(WelcomePagesModel, "Cura", 1, 0, "WelcomePagesModel") + qmlRegisterType(WhatsNewPagesModel, "Cura", 1, 0, "WhatsNewPagesModel") qmlRegisterType(AddPrinterPagesModel, "Cura", 1, 0, "AddPrinterPagesModel") qmlRegisterType(TextManager, "Cura", 1, 0, "TextManager") @@ -1765,3 +1773,16 @@ class CuraApplication(QtApplication): def getSidebarCustomMenuItems(self) -> list: return self._sidebar_custom_menu_items + @pyqtSlot(result = bool) + def shouldShowWelcomeDialog(self) -> bool: + # Only show the complete flow if there is no printer yet. + return self._machine_manager.activeMachine is None + + @pyqtSlot(result = bool) + def shouldShowWhatsNewDialog(self) -> bool: + has_active_machine = self._machine_manager.activeMachine is not None + has_app_just_upgraded = self.hasJustUpdatedFromOldVersion() + + # Only show the what's new dialog if there's no machine and we have just upgraded + show_whatsnew_only = has_active_machine and has_app_just_upgraded + return show_whatsnew_only diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index df881b4714..3ec73972dd 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -258,6 +258,9 @@ class GlobalStack(CuraContainerStack): def getHasVariants(self) -> bool: return parseBool(self.getMetaDataEntry("has_variants", False)) + def getHasVariantsBuildPlates(self) -> bool: + return parseBool(self.getMetaDataEntry("has_variant_buildplates", False)) + def getHasMachineQuality(self) -> bool: return parseBool(self.getMetaDataEntry("has_machine_quality", False)) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 7d0e7506b8..bd766118a8 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -9,6 +9,7 @@ from typing import Any, List, Dict, TYPE_CHECKING, Optional, cast from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer from UM.ConfigurationErrorMessage import ConfigurationErrorMessage +from UM.Decorators import deprecated from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.Interfaces import ContainerInterface @@ -498,18 +499,21 @@ class MachineManager(QObject): return bool(self._stacks_have_errors) @pyqtProperty(str, notify = globalContainerChanged) + @deprecated("use Cura.MachineManager.activeMachine.definition.name instead", "4.1") def activeMachineDefinitionName(self) -> str: if self._global_container_stack: return self._global_container_stack.definition.getName() return "" @pyqtProperty(str, notify = globalContainerChanged) + @deprecated("use Cura.MachineManager.activeMachine.name instead", "4.1") def activeMachineName(self) -> str: if self._global_container_stack: return self._global_container_stack.getMetaDataEntry("group_name", self._global_container_stack.getName()) return "" @pyqtProperty(str, notify = globalContainerChanged) + @deprecated("use Cura.MachineManager.activeMachine.id instead", "4.1") def activeMachineId(self) -> str: if self._global_container_stack: return self._global_container_stack.getId() @@ -543,6 +547,7 @@ class MachineManager(QObject): return False @pyqtProperty("QVariantList", notify=globalContainerChanged) + @deprecated("use Cura.MachineManager.activeMachine.configuredConnectionTypes instead", "4.1") def activeMachineConfiguredConnectionTypes(self): if self._global_container_stack: return self._global_container_stack.configuredConnectionTypes @@ -715,6 +720,7 @@ class MachineManager(QObject): extruder_stack.userChanges.setProperty(key, "value", new_value) @pyqtProperty(str, notify = activeVariantChanged) + @deprecated("use Cura.activeStack.variant.name instead", "4.1") def activeVariantName(self) -> str: if self._active_container_stack: variant = self._active_container_stack.variant @@ -724,6 +730,7 @@ class MachineManager(QObject): return "" @pyqtProperty(str, notify = activeVariantChanged) + @deprecated("use Cura.activeStack.variant.id instead", "4.1") def activeVariantId(self) -> str: if self._active_container_stack: variant = self._active_container_stack.variant @@ -733,6 +740,7 @@ class MachineManager(QObject): return "" @pyqtProperty(str, notify = activeVariantChanged) + @deprecated("use Cura.activeMachine.variant.name instead", "4.1") def activeVariantBuildplateName(self) -> str: if self._global_container_stack: variant = self._global_container_stack.variant @@ -742,6 +750,7 @@ class MachineManager(QObject): return "" @pyqtProperty(str, notify = globalContainerChanged) + @deprecated("use Cura.activeMachine.definition.id instead", "4.1") def activeDefinitionId(self) -> str: if self._global_container_stack: return self._global_container_stack.definition.id @@ -806,19 +815,19 @@ class MachineManager(QObject): @pyqtProperty(bool, notify = globalContainerChanged) def hasMaterials(self) -> bool: if self._global_container_stack: - return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)) + return self._global_container_stack.getHasMaterials() return False @pyqtProperty(bool, notify = globalContainerChanged) def hasVariants(self) -> bool: if self._global_container_stack: - return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variants", False)) + return self._global_container_stack.getHasVariants() return False @pyqtProperty(bool, notify = globalContainerChanged) def hasVariantBuildplates(self) -> bool: if self._global_container_stack: - return Util.parseBool(self._global_container_stack.getMetaDataEntry("has_variant_buildplates", False)) + return self._global_container_stack.getHasVariantsBuildPlates() return False ## The selected buildplate is compatible if it is compatible with all the materials in all the extruders @@ -1428,6 +1437,7 @@ class MachineManager(QObject): self._global_container_stack.extruders[position].setEnabled(True) self.updateMaterialWithVariant(position) + self.updateDefaultExtruder() self.updateNumberExtrudersEnabled() if configuration.buildplateConfiguration is not None: diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index 429e6d16ec..d230953f9c 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -73,8 +73,8 @@ class SettingOverrideDecorator(SceneNodeDecorator): # use value from the stack because there can be a delay in signal triggering and "_is_non_printing_mesh" # has not been updated yet. - deep_copy._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() - deep_copy._is_non_thumbnail_visible_mesh = self.evaluateIsNonThumbnailVisibleMesh() + deep_copy._is_non_printing_mesh = self._evaluateIsNonPrintingMesh() + deep_copy._is_non_thumbnail_visible_mesh = self._evaluateIsNonThumbnailVisibleMesh() return deep_copy @@ -102,23 +102,32 @@ class SettingOverrideDecorator(SceneNodeDecorator): def isNonPrintingMesh(self): return self._is_non_printing_mesh - def evaluateIsNonPrintingMesh(self): + def _evaluateIsNonPrintingMesh(self): return any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) def isNonThumbnailVisibleMesh(self): return self._is_non_thumbnail_visible_mesh - def evaluateIsNonThumbnailVisibleMesh(self): + def _evaluateIsNonThumbnailVisibleMesh(self): return any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_thumbnail_visible_settings) - def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function - if property_name == "value": + def _onSettingChanged(self, setting_key, property_name): # Reminder: 'property' is a built-in function + # We're only interested in a few settings and only if it's value changed. + if property_name == "value" and (setting_key in self._non_printing_mesh_settings or setting_key in self._non_thumbnail_visible_settings): # Trigger slice/need slicing if the value has changed. - self._is_non_printing_mesh = self.evaluateIsNonPrintingMesh() - self._is_non_thumbnail_visible_mesh = self.evaluateIsNonThumbnailVisibleMesh() + new_is_non_printing_mesh = self._evaluateIsNonPrintingMesh() + new_is_non_thumbnail_visible_mesh = self._evaluateIsNonThumbnailVisibleMesh() + changed = False + if self._is_non_printing_mesh != new_is_non_printing_mesh: + self._is_non_printing_mesh = new_is_non_printing_mesh + self._node.setCalculateBoundingBox(not self._is_non_printing_mesh) + changed = True + if self._is_non_thumbnail_visible_mesh != new_is_non_thumbnail_visible_mesh: + changed = True - Application.getInstance().getBackend().needsSlicing() - Application.getInstance().getBackend().tickle() + if changed: + Application.getInstance().getBackend().needsSlicing() + Application.getInstance().getBackend().tickle() ## Makes sure that the stack upon which the container stack is placed is # kept up to date. diff --git a/cura/UI/WhatsNewPagesModel.py b/cura/UI/WhatsNewPagesModel.py new file mode 100644 index 0000000000..5b968ae574 --- /dev/null +++ b/cura/UI/WhatsNewPagesModel.py @@ -0,0 +1,22 @@ +# Copyright (c) 2019 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from .WelcomePagesModel import WelcomePagesModel + + +# +# This Qt ListModel is more or less the same the WelcomePagesModel, except that this model is only for showing the +# "what's new" page. This is also used in the "Help" menu to show the changes log. +# +class WhatsNewPagesModel(WelcomePagesModel): + + def initialize(self) -> None: + self._pages = [] + self._pages.append({"id": "whats_new", + "page_url": self._getBuiltinWelcomePagePath("WhatsNewContent.qml"), + "next_page_button_text": self._catalog.i18nc("@action:button", "Close"), + }) + self.setItems(self._pages) + + +__all__ = ["WhatsNewPagesModel"] diff --git a/plugins/ChangeLogPlugin/ChangeLog.py b/plugins/ChangeLogPlugin/ChangeLog.py deleted file mode 100644 index 241d7a8953..0000000000 --- a/plugins/ChangeLogPlugin/ChangeLog.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2019 Ultimaker B.V. -# Cura is released under the terms of the LGPLv3 or higher. - -import os.path - -from PyQt5.QtCore import QObject - -from UM.i18n import i18nCatalog -from UM.Extension import Extension -from UM.Application import Application -from UM.PluginRegistry import PluginRegistry -from UM.Version import Version - -catalog = i18nCatalog("cura") - - -class ChangeLog(Extension, QObject): - def __init__(self, parent = None): - QObject.__init__(self, parent) - Extension.__init__(self) - self._changelog_window = None - self._changelog_context = None - version_string = Application.getInstance().getVersion() - if version_string is not "master": - self._current_app_version = Version(version_string) - else: - self._current_app_version = None - - Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated) - Application.getInstance().getPreferences().addPreference("general/latest_version_changelog_shown", "2.0.0") #First version of CURA with uranium - self.setMenuName(catalog.i18nc("@item:inmenu", "Changelog")) - self.addMenuItem(catalog.i18nc("@item:inmenu", "Show Changelog"), self.showChangelog) - - def _onEngineCreated(self): - if not self._current_app_version: - return #We're on dev branch. - - if Application.getInstance().getPreferences().getValue("general/latest_version_changelog_shown") == "master": - latest_version_shown = Version("0.0.0") - else: - latest_version_shown = Version(Application.getInstance().getPreferences().getValue("general/latest_version_changelog_shown")) - - Application.getInstance().getPreferences().setValue("general/latest_version_changelog_shown", Application.getInstance().getVersion()) - - # Do not show the changelog when there is no global container stack - # This implies we are running Cura for the first time. - if not Application.getInstance().getGlobalContainerStack(): - return - - if self._current_app_version > latest_version_shown: - self.showChangelog() - - def showChangelog(self): - if not self._changelog_window: - self.createChangelogWindow() - - self._changelog_window.show() - - def hideChangelog(self): - if self._changelog_window: - self._changelog_window.hide() - - def createChangelogWindow(self): - path = os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "ChangeLog.qml") - self._changelog_window = Application.getInstance().createQmlComponent(path, {"manager": self}) diff --git a/plugins/ChangeLogPlugin/ChangeLog.qml b/plugins/ChangeLogPlugin/ChangeLog.qml deleted file mode 100644 index 7089a56caf..0000000000 --- a/plugins/ChangeLogPlugin/ChangeLog.qml +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2015 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.1 -import QtQuick.Controls 1.3 -import QtQuick.Layouts 1.1 -import QtQuick.Window 2.1 - -import UM 1.3 as UM -import Cura 1.0 as Cura - - -UM.Dialog -{ - id: base - minimumWidth: (UM.Theme.getSize("modal_window_minimum").width * 0.75) | 0 - minimumHeight: (UM.Theme.getSize("modal_window_minimum").height * 0.75) | 0 - width: minimumWidth - height: minimumHeight - title: catalog.i18nc("@label", "Changelog") - - TextArea - { - anchors.fill: parent - text: CuraApplication.getTextManager().getChangeLogText() - readOnly: true; - textFormat: TextEdit.RichText - } - - rightButtons: [ - Button - { - UM.I18nCatalog - { - id: catalog - name: "cura" - } - - text: catalog.i18nc("@action:button", "Close") - onClicked: base.hide() - } - ] -} diff --git a/plugins/ChangeLogPlugin/__init__.py b/plugins/ChangeLogPlugin/__init__.py deleted file mode 100644 index a5452b60c8..0000000000 --- a/plugins/ChangeLogPlugin/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015 Ultimaker B.V. -# Cura is released under the terms of the LGPLv3 or higher. - -from . import ChangeLog - - -def getMetaData(): - return {} - -def register(app): - return {"extension": ChangeLog.ChangeLog()} diff --git a/plugins/ChangeLogPlugin/plugin.json b/plugins/ChangeLogPlugin/plugin.json deleted file mode 100644 index 92041d1543..0000000000 --- a/plugins/ChangeLogPlugin/plugin.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Changelog", - "author": "Ultimaker B.V.", - "version": "1.0.1", - "description": "Shows changes since latest checked version.", - "api": "6.0", - "i18n-catalog": "cura" -} diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index ef97364118..d9e1a7806d 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -196,10 +196,7 @@ class StartSliceJob(Job): has_printing_mesh = False for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. if node.callDecoration("isSliceable") and node.getMeshData() and node.getMeshData().getVertices() is not None: - per_object_stack = node.callDecoration("getStack") - is_non_printing_mesh = False - if per_object_stack: - is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) + is_non_printing_mesh = bool(node.callDecoration("isNonPrintingMesh")) # Find a reason not to add the node if node.callDecoration("getBuildPlateNumber") != self._build_plate_number: diff --git a/plugins/PostProcessingPlugin/scripts/FilamentChange.py b/plugins/PostProcessingPlugin/scripts/FilamentChange.py index febb93be4c..2acb01d5cc 100644 --- a/plugins/PostProcessingPlugin/scripts/FilamentChange.py +++ b/plugins/PostProcessingPlugin/scripts/FilamentChange.py @@ -97,7 +97,7 @@ class FilamentChange(Script): if layer_num <= len(data): index, layer_data = self._searchLayerData(data, layer_num - 1) if layer_data is None: - Logger.log("e", "Could not found the layer") + Logger.log("e", "Could not find the layer {layer_num}".format(layer_num = layer_num)) continue lines = layer_data.split("\n") lines.insert(2, color_change) diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index 3763db5534..fecf3d16bb 100755 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -181,6 +181,8 @@ class SliceInfo(QObject, Extension): model = dict() model["hash"] = node.getMeshData().getHash() bounding_box = node.getBoundingBox() + if not bounding_box: + continue model["bounding_box"] = {"minimum": {"x": bounding_box.minimum.x, "y": bounding_box.minimum.y, "z": bounding_box.minimum.z}, diff --git a/plugins/UFPReader/UFPReader.py b/plugins/UFPReader/UFPReader.py index cec70ef655..275726b25b 100644 --- a/plugins/UFPReader/UFPReader.py +++ b/plugins/UFPReader/UFPReader.py @@ -1,15 +1,16 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import cast +from typing import TYPE_CHECKING from Charon.VirtualFile import VirtualFile from UM.Mesh.MeshReader import MeshReader from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase from UM.PluginRegistry import PluginRegistry -from cura.Scene.CuraSceneNode import CuraSceneNode -from plugins.GCodeReader.GCodeReader import GCodeReader + +if TYPE_CHECKING: + from cura.Scene.CuraSceneNode import CuraSceneNode class UFPReader(MeshReader): @@ -26,7 +27,7 @@ class UFPReader(MeshReader): ) self._supported_extensions = [".ufp"] - def _read(self, file_name: str) -> CuraSceneNode: + def _read(self, file_name: str) -> "CuraSceneNode": # Open the file archive = VirtualFile() archive.open(file_name) @@ -36,6 +37,6 @@ class UFPReader(MeshReader): gcode_stream = gcode_data["/3D/model.gcode"].decode("utf-8") # Open the GCodeReader to parse the data - gcode_reader = cast(GCodeReader, PluginRegistry.getInstance().getPluginObject("GCodeReader")) + gcode_reader = PluginRegistry.getInstance().getPluginObject("GCodeReader") # type: ignore gcode_reader.preReadFromStream(gcode_stream) return gcode_reader.readFromStream(gcode_stream) diff --git a/plugins/VersionUpgrade/VersionUpgrade40to41/VersionUpgrade40to41.py b/plugins/VersionUpgrade/VersionUpgrade40to41/VersionUpgrade40to41.py index d80e0007aa..03272e63d5 100644 --- a/plugins/VersionUpgrade/VersionUpgrade40to41/VersionUpgrade40to41.py +++ b/plugins/VersionUpgrade/VersionUpgrade40to41/VersionUpgrade40to41.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import configparser @@ -49,6 +49,15 @@ class VersionUpgrade40to41(VersionUpgrade): parser["general"]["version"] = "4" parser["metadata"]["setting_version"] = "7" + # Limit Maximum Deviation instead of Maximum Resolution. This should have approximately the same effect as before the algorithm change, only more consistent. + if "meshfix_maximum_resolution" in parser["values"]: + resolution = parser["values"]["meshfix_maximum_resolution"] + if resolution.startswith("="): + resolution = resolution[1:] + deviation = "=(" + resolution + ") / 2" + parser["values"]["meshfix_maximum_deviation"] = deviation + del parser["values"]["meshfix_maximum_resolution"] + result = io.StringIO() parser.write(result) return [filename], [result.getvalue()] @@ -62,6 +71,11 @@ class VersionUpgrade40to41(VersionUpgrade): parser["general"]["version"] = "6" if "metadata" not in parser: parser["metadata"] = {} + + # Remove changelog plugin + if "latest_version_changelog_shown" in parser["general"]: + del parser["general"]["latest_version_changelog_shown"] + parser["metadata"]["setting_version"] = "7" result = io.StringIO() diff --git a/resources/bundled_packages/cura.json b/resources/bundled_packages/cura.json index 3dcc02a503..cf8ecfb010 100644 --- a/resources/bundled_packages/cura.json +++ b/resources/bundled_packages/cura.json @@ -33,23 +33,6 @@ } } }, - "ChangeLogPlugin": { - "package_info": { - "package_id": "ChangeLogPlugin", - "package_type": "plugin", - "display_name": "Change Log", - "description": "Shows changes since latest checked version.", - "package_version": "1.0.1", - "sdk_version": "6.0.0", - "website": "https://ultimaker.com", - "author": { - "author_id": "UltimakerPackages", - "display_name": "Ultimaker B.V.", - "email": "plugins@ultimaker.com", - "website": "https://ultimaker.com" - } - } - }, "CuraDrive": { "package_info": { "package_id": "CuraDrive", diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 8ce0246a93..809ed79c9c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -1316,8 +1316,7 @@ "default_value": 0, "type": "float", "enabled": "travel_compensate_overlapping_walls_0_enabled or travel_compensate_overlapping_walls_x_enabled", - "settable_per_mesh": true, - "settable_per_extruder": false + "settable_per_mesh": true }, "wall_min_flow_retract": { @@ -1326,8 +1325,7 @@ "type": "bool", "default_value": false, "enabled": "(travel_compensate_overlapping_walls_0_enabled or travel_compensate_overlapping_walls_x_enabled) and wall_min_flow > 0", - "settable_per_mesh": true, - "settable_per_extruder": false + "settable_per_mesh": true }, "fill_perimeter_gaps": { @@ -5855,10 +5853,10 @@ "description": "The minimum size of a line segment after slicing. If you increase this, the mesh will have a lower resolution. This may allow the printer to keep up with the speed it has to process g-code and will increase slice speed by removing details of the mesh that it can't process anyway.", "type": "float", "unit": "mm", - "default_value": 0.01, + "default_value": 0.25, "minimum_value": "0.001", - "minimum_value_warning": "0.005", - "maximum_value_warning": "0.1", + "minimum_value_warning": "0.02", + "maximum_value_warning": "2", "settable_per_mesh": true }, "meshfix_maximum_travel_resolution": @@ -5867,14 +5865,26 @@ "description": "The minimum size of a travel line segment after slicing. If you increase this, the travel moves will have less smooth corners. This may allow the printer to keep up with the speed it has to process g-code, but it may cause model avoidance to become less accurate.", "type": "float", "unit": "mm", - "default_value": 0.02, + "default_value": 0.5, "value": "meshfix_maximum_resolution * speed_travel / speed_print", "minimum_value": "0.001", - "minimum_value_warning": "0.005", - "maximum_value_warning": "1", + "minimum_value_warning": "0.05", + "maximum_value_warning": "10", "settable_per_mesh": false, "settable_per_extruder": true }, + "meshfix_maximum_deviation": + { + "label": "Maximum Deviation", + "description": "The maximum deviation allowed when reducing the resolution for the Maximum Resolution setting. If you increase this, the print will be less accurate, but the g-code will be smaller.", + "type": "float", + "unit": "mm", + "default_value": 0.005, + "minimum_value": "0.001", + "minimum_value_warning": "0.003", + "maximum_value_warning": "0.1", + "settable_per_mesh": true + }, "support_skip_some_zags": { "label": "Break Up Support In Chunks", diff --git a/resources/definitions/peopoly_moai.def.json b/resources/definitions/peopoly_moai.def.json index a578cc4240..177a6a801e 100644 --- a/resources/definitions/peopoly_moai.def.json +++ b/resources/definitions/peopoly_moai.def.json @@ -173,8 +173,8 @@ "minimum_polygon_circumference": { "value": "0.1" }, - "meshfix_maximum_resolution": { - "value": "0.005" + "meshfix_maximum_deviation": { + "value": "0.003" }, "skin_outline_count": { "value": 0 diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 81c14aa01a..ce9618a560 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -61,6 +61,7 @@ Item property alias documentation: documentationAction; property alias showTroubleshooting: showTroubleShootingAction property alias reportBug: reportBugAction; + property alias whatsNew: whatsNewAction property alias about: aboutAction; property alias toggleFullScreen: toggleFullScreenAction; @@ -229,6 +230,12 @@ Item onTriggered: CuraActions.openBugReportPage(); } + Action + { + id: whatsNewAction; + text: catalog.i18nc("@action:inmenu menubar:help", "What's New"); + } + Action { id: aboutAction; diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index bdd016d24c..f5cbe8ad53 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -71,26 +71,42 @@ UM.MainWindow Component.onCompleted: { CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size")) - // Workaround silly issues with QML Action's shortcut property. - // - // Currently, there is no way to define shortcuts as "Application Shortcut". - // This means that all Actions are "Window Shortcuts". The code for this - // implements a rather naive check that just checks if any of the action's parents - // are a window. Since the "Actions" object is a singleton it has no parent by - // default. If we set its parent to something contained in this window, the - // shortcut will activate properly because one of its parents is a window. - // - // This has been fixed for QtQuick Controls 2 since the Shortcut item has a context property. - Cura.Actions.parent = backgroundItem CuraApplication.purgeWindows() + } - if (CuraApplication.getWelcomePagesModel().shouldShowWelcomeFlow) + Connections + { + target: CuraApplication + onInitializationFinished: { - welcomeDialogItem.visible = true - } - else - { - welcomeDialogItem.visible = false + // Workaround silly issues with QML Action's shortcut property. + // + // Currently, there is no way to define shortcuts as "Application Shortcut". + // This means that all Actions are "Window Shortcuts". The code for this + // implements a rather naive check that just checks if any of the action's parents + // are a window. Since the "Actions" object is a singleton it has no parent by + // default. If we set its parent to something contained in this window, the + // shortcut will activate properly because one of its parents is a window. + // + // This has been fixed for QtQuick Controls 2 since the Shortcut item has a context property. + Cura.Actions.parent = backgroundItem + + if (CuraApplication.shouldShowWelcomeDialog()) + { + welcomeDialogItem.visible = true + } + else + { + welcomeDialogItem.visible = false + } + + // Reuse the welcome dialog item to show "What's New" only. + if (CuraApplication.shouldShowWhatsNewDialog()) + { + welcomeDialogItem.model = CuraApplication.getWhatsNewPagesModel() + welcomeDialogItem.progressBarVisible = false + welcomeDialogItem.visible = true + } } } @@ -780,6 +796,20 @@ UM.MainWindow progressBarVisible: false } + Cura.WizardDialog + { + id: whatsNewDialog + title: catalog.i18nc("@title:window", "What's New") + model: CuraApplication.getWhatsNewPagesModel() + progressBarVisible: false + } + + Connections + { + target: Cura.Actions.whatsNew + onTriggered: whatsNewDialog.show() + } + Connections { target: Cura.Actions.addMachine diff --git a/resources/qml/MainWindow/ApplicationMenu.qml b/resources/qml/MainWindow/ApplicationMenu.qml index 2f18df8914..7f343eb8f4 100644 --- a/resources/qml/MainWindow/ApplicationMenu.qml +++ b/resources/qml/MainWindow/ApplicationMenu.qml @@ -101,6 +101,7 @@ Item MenuItem { action: Cura.Actions.documentation } MenuItem { action: Cura.Actions.reportBug } MenuSeparator { } + MenuItem { action: Cura.Actions.whatsNew } MenuItem { action: Cura.Actions.about } } } diff --git a/resources/qml/WelcomePages/WelcomeDialogItem.qml b/resources/qml/WelcomePages/WelcomeDialogItem.qml index 1ab722598b..7da4c6e897 100644 --- a/resources/qml/WelcomePages/WelcomeDialogItem.qml +++ b/resources/qml/WelcomePages/WelcomeDialogItem.qml @@ -26,6 +26,7 @@ Item property int shadowOffset: 1 * screenScaleFactor + property alias progressBarVisible: wizardPanel.progressBarVisible property var model: CuraApplication.getWelcomePagesModel() onVisibleChanged: diff --git a/resources/qml/WelcomePages/WhatsNewContent.qml b/resources/qml/WelcomePages/WhatsNewContent.qml index 415acae05c..51a347779a 100644 --- a/resources/qml/WelcomePages/WhatsNewContent.qml +++ b/resources/qml/WelcomePages/WhatsNewContent.qml @@ -51,7 +51,7 @@ Item id: getStartedButton anchors.right: parent.right anchors.bottom: parent.bottom - text: catalog.i18nc("@button", "Next") + text: base.currentItem.next_page_button_text onClicked: base.showNextPage() } } diff --git a/resources/setting_visibility/expert.cfg b/resources/setting_visibility/expert.cfg index 7754555ba7..0765c51749 100644 --- a/resources/setting_visibility/expert.cfg +++ b/resources/setting_visibility/expert.cfg @@ -347,6 +347,7 @@ infill_enable_travel_optimization material_flow_dependent_temperature material_flow_temp_graph meshfix_maximum_resolution +meshfix_maximum_deviation support_skip_some_zags support_skip_zag_per_mm support_zag_skip_count diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 4b2f92e6e5..f1e35f189f 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -433,7 +433,7 @@ "monitor_skeleton_loading": [238, 238, 238, 255], "monitor_placeholder_image": [230, 230, 230, 255], "monitor_image_overlay": [0, 0, 0, 255], - "monitor_shadow": [220, 220, 220, 255], + "monitor_shadow": [200, 200, 200, 255], "monitor_carousel_dot": [216, 216, 216, 255], "monitor_carousel_dot_current": [119, 119, 119, 255]