diff --git a/.gitignore b/.gitignore index 0a66b6eb33..60b59e6829 100644 --- a/.gitignore +++ b/.gitignore @@ -42,7 +42,6 @@ plugins/cura-siemensnx-plugin plugins/CuraBlenderPlugin plugins/CuraCloudPlugin plugins/CuraDrivePlugin -plugins/CuraDrive plugins/CuraLiveScriptingPlugin plugins/CuraOpenSCADPlugin plugins/CuraPrintProfileCreator diff --git a/Jenkinsfile b/Jenkinsfile index f9a3a9864a..a345ebbd05 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -38,20 +38,9 @@ parallel_nodes(['linux && cura', 'windows && cura']) { if (isUnix()) { - // For Linux to show everything - def branch = env.BRANCH_NAME - if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}")) - { - branch = "master" - } - def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}") - + // For Linux try { - sh """ - cd .. - export PYTHONPATH=.:"${uranium_dir}" - ${env.CURA_ENVIRONMENT_PATH}/${branch}/bin/pytest -x --verbose --full-trace --capture=no ./tests - """ + sh 'make CTEST_OUTPUT_ON_FAILURE=TRUE test' } catch(e) { currentBuild.result = "UNSTABLE" @@ -70,34 +59,6 @@ parallel_nodes(['linux && cura', 'windows && cura']) } } } - - stage('Code Style') - { - if (isUnix()) - { - // For Linux to show everything. - // CMake also runs this test, but if it fails then the test just shows "failed" without details of what exactly failed. - def branch = env.BRANCH_NAME - if(!fileExists("${env.CURA_ENVIRONMENT_PATH}/${branch}")) - { - branch = "master" - } - def uranium_dir = get_workspace_dir("Ultimaker/Uranium/${branch}") - - try - { - sh """ - cd .. - export PYTHONPATH=.:"${uranium_dir}" - ${env.CURA_ENVIRONMENT_PATH}/${branch}/bin/python3 run_mypy.py - """ - } - catch(e) - { - currentBuild.result = "UNSTABLE" - } - } - } } } diff --git a/README.md b/README.md index 70466e9c22..93abcc0c61 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,9 @@ Dependencies ------------ * [Uranium](https://github.com/Ultimaker/Uranium) Cura is built on top of the Uranium framework. * [CuraEngine](https://github.com/Ultimaker/CuraEngine) This will be needed at runtime to perform the actual slicing. +* [fdm_materials](https://github.com/Ultimaker/fdm_materials) Required to load a printer that has swappable material profiles. * [PySerial](https://github.com/pyserial/pyserial) Only required for USB printing support. -* [python-zeroconf](https://github.com/jstasiak/python-zeroconf) Only required to detect mDNS-enabled printers +* [python-zeroconf](https://github.com/jstasiak/python-zeroconf) Only required to detect mDNS-enabled printers. Build scripts ------------- diff --git a/cmake/CuraTests.cmake b/cmake/CuraTests.cmake index f2ee92d65b..b6d04de036 100644 --- a/cmake/CuraTests.cmake +++ b/cmake/CuraTests.cmake @@ -6,6 +6,8 @@ include(CMakeParseArguments) find_package(PythonInterp 3.5.0 REQUIRED) +add_custom_target(test-verbose COMMAND ${CMAKE_CTEST_COMMAND} --verbose) + function(cura_add_test) set(_single_args NAME DIRECTORY PYTHONPATH) cmake_parse_arguments("" "" "${_single_args}" "" ${ARGN}) diff --git a/cura.desktop.in b/cura.desktop.in index fbe8b30fed..b0195015a5 100644 --- a/cura.desktop.in +++ b/cura.desktop.in @@ -13,6 +13,6 @@ TryExec=@CMAKE_INSTALL_FULL_BINDIR@/cura Icon=cura-icon Terminal=false Type=Application -MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;model/x3d+xml; +MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;model/x3d+xml;text/x-gcode; Categories=Graphics; Keywords=3D;Printing;Slicer; diff --git a/cura.sharedmimeinfo b/cura.sharedmimeinfo index 23d38795eb..ed9099d425 100644 --- a/cura.sharedmimeinfo +++ b/cura.sharedmimeinfo @@ -19,4 +19,12 @@ + + + Gcode file + + + + + \ No newline at end of file diff --git a/cura/API/Account.py b/cura/API/Account.py index 397e220478..a04f97ef1c 100644 --- a/cura/API/Account.py +++ b/cura/API/Account.py @@ -6,6 +6,7 @@ from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty from UM.i18n import i18nCatalog from UM.Message import Message +from cura import UltimakerCloudAuthentication from cura.OAuth2.AuthorizationService import AuthorizationService from cura.OAuth2.Models import OAuth2Settings @@ -37,15 +38,16 @@ class Account(QObject): self._logged_in = False self._callback_port = 32118 - self._oauth_root = "https://account.ultimaker.com" - self._cloud_api_root = "https://api.ultimaker.com" + self._oauth_root = UltimakerCloudAuthentication.CuraCloudAccountAPIRoot self._oauth_settings = OAuth2Settings( OAUTH_SERVER_URL= self._oauth_root, CALLBACK_PORT=self._callback_port, CALLBACK_URL="http://localhost:{}/callback".format(self._callback_port), - CLIENT_ID="um---------------ultimaker_cura_drive_plugin", - CLIENT_SCOPES="account.user.read drive.backup.read drive.backup.write packages.download packages.rating.read packages.rating.write", + CLIENT_ID="um----------------------------ultimaker_cura", + CLIENT_SCOPES="account.user.read drive.backup.read drive.backup.write packages.download " + "packages.rating.read packages.rating.write connect.cluster.read connect.cluster.write " + "cura.printjob.read cura.printjob.write cura.mesh.read cura.mesh.write", AUTH_DATA_PREFERENCE_KEY="general/ultimaker_auth_data", AUTH_SUCCESS_REDIRECT="{}/app/auth-success".format(self._oauth_root), AUTH_FAILED_REDIRECT="{}/app/auth-error".format(self._oauth_root) @@ -60,6 +62,11 @@ class Account(QObject): self._authorization_service.onAuthenticationError.connect(self._onLoginStateChanged) self._authorization_service.loadAuthDataFromPreferences() + ## Returns a boolean indicating whether the given authentication is applied against staging or not. + @property + def is_staging(self) -> bool: + return "staging" in self._oauth_root + @pyqtProperty(bool, notify=loginStateChanged) def isLoggedIn(self) -> bool: return self._logged_in diff --git a/cura/API/Backups.py b/cura/API/Backups.py index 8e5cd7b83a..ef74e74be0 100644 --- a/cura/API/Backups.py +++ b/cura/API/Backups.py @@ -1,6 +1,6 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Tuple, Optional, TYPE_CHECKING +from typing import Tuple, Optional, TYPE_CHECKING, Dict, Any from cura.Backups.BackupsManager import BackupsManager @@ -24,12 +24,12 @@ class Backups: ## Create a new back-up using the BackupsManager. # \return Tuple containing a ZIP file with the back-up data and a dict # with metadata about the back-up. - def createBackup(self) -> Tuple[Optional[bytes], Optional[dict]]: + def createBackup(self) -> Tuple[Optional[bytes], Optional[Dict[str, Any]]]: return self.manager.createBackup() ## Restore a back-up using the BackupsManager. # \param zip_file A ZIP file containing the actual back-up data. # \param meta_data Some metadata needed for restoring a back-up, like the # Cura version number. - def restoreBackup(self, zip_file: bytes, meta_data: dict) -> None: + def restoreBackup(self, zip_file: bytes, meta_data: Dict[str, Any]) -> None: return self.manager.restoreBackup(zip_file, meta_data) diff --git a/cura/ApplicationMetadata.py b/cura/ApplicationMetadata.py new file mode 100644 index 0000000000..4cb19edb72 --- /dev/null +++ b/cura/ApplicationMetadata.py @@ -0,0 +1,42 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +# --------- +# Genearl constants used in Cura +# --------- +DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura" +DEFAULT_CURA_VERSION = "master" +DEFAULT_CURA_BUILD_TYPE = "" +DEFAULT_CURA_DEBUG_MODE = False +DEFAULT_CURA_SDK_VERSION = "6.0.0" + +try: + from cura.CuraVersion import CuraAppDisplayName # type: ignore + if CuraAppDisplayName == "": + CuraAppDisplayName = DEFAULT_CURA_DISPLAY_NAME +except ImportError: + CuraAppDisplayName = DEFAULT_CURA_DISPLAY_NAME + +try: + from cura.CuraVersion import CuraVersion # type: ignore + if CuraVersion == "": + CuraVersion = DEFAULT_CURA_VERSION +except ImportError: + CuraVersion = DEFAULT_CURA_VERSION # [CodeStyle: Reflecting imported value] + +try: + from cura.CuraVersion import CuraBuildType # type: ignore +except ImportError: + CuraBuildType = DEFAULT_CURA_BUILD_TYPE + +try: + from cura.CuraVersion import CuraDebugMode # type: ignore +except ImportError: + CuraDebugMode = DEFAULT_CURA_DEBUG_MODE + +try: + from cura.CuraVersion import CuraSDKVersion # type: ignore + if CuraSDKVersion == "": + CuraSDKVersion = DEFAULT_CURA_SDK_VERSION +except ImportError: + CuraSDKVersion = DEFAULT_CURA_SDK_VERSION diff --git a/cura/Arranging/Arrange.py b/cura/Arranging/Arrange.py index 5657ee991a..32796005c8 100644 --- a/cura/Arranging/Arrange.py +++ b/cura/Arranging/Arrange.py @@ -66,6 +66,11 @@ class Arrange: continue vertices = vertices.getMinkowskiHull(Polygon.approximatedCircle(min_offset)) points = copy.deepcopy(vertices._points) + + # After scaling (like up to 0.1 mm) the node might not have points + if len(points) == 0: + continue + shape_arr = ShapeArray.fromPolygon(points, scale = scale) arranger.place(0, 0, shape_arr) diff --git a/cura/Backups/Backup.py b/cura/Backups/Backup.py index 897d5fa979..714d6527fe 100644 --- a/cura/Backups/Backup.py +++ b/cura/Backups/Backup.py @@ -46,12 +46,13 @@ class Backup: # We copy the preferences file to the user data directory in Linux as it's in a different location there. # When restoring a backup on Linux, we move it back. - if Platform.isLinux(): + if Platform.isLinux(): #TODO: This should check for the config directory not being the same as the data directory, rather than hard-coding that to Linux systems. preferences_file_name = self._application.getApplicationName() preferences_file = Resources.getPath(Resources.Preferences, "{}.cfg".format(preferences_file_name)) backup_preferences_file = os.path.join(version_data_dir, "{}.cfg".format(preferences_file_name)) - Logger.log("d", "Copying preferences file from %s to %s", preferences_file, backup_preferences_file) - shutil.copyfile(preferences_file, backup_preferences_file) + if os.path.exists(preferences_file) and (not os.path.exists(backup_preferences_file) or not os.path.samefile(preferences_file, backup_preferences_file)): + Logger.log("d", "Copying preferences file from %s to %s", preferences_file, backup_preferences_file) + shutil.copyfile(preferences_file, backup_preferences_file) # Create an empty buffer and write the archive to it. buffer = io.BytesIO() diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 547c3dae71..aa1f170707 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -83,7 +83,14 @@ class BuildVolume(SceneNode): " with printed models."), title = catalog.i18nc("@info:title", "Build Volume")) self._global_container_stack = None + + self._stack_change_timer = QTimer() + self._stack_change_timer.setInterval(100) + self._stack_change_timer.setSingleShot(True) + self._stack_change_timer.timeout.connect(self._onStackChangeTimerFinished) + self._application.globalContainerStackChanged.connect(self._onStackChanged) + self._onStackChanged() self._engine_ready = False @@ -105,6 +112,8 @@ class BuildVolume(SceneNode): self._setting_change_timer.setSingleShot(True) self._setting_change_timer.timeout.connect(self._onSettingChangeTimerFinished) + + # Must be after setting _build_volume_message, apparently that is used in getMachineManager. # activeQualityChanged is always emitted after setActiveVariant, setActiveMaterial and setActiveQuality. # Therefore this works. @@ -479,6 +488,8 @@ class BuildVolume(SceneNode): maximum = Vector(max_w - bed_adhesion_size - 1, max_h - self._raft_thickness - self._extra_z_clearance, max_d - disallowed_area_size + bed_adhesion_size - 1) ) + self._application.getController().getScene()._maximum_bounds = scale_to_max_bounds + self.updateNodeBoundaryCheck() def getBoundingBox(self) -> AxisAlignedBox: @@ -489,7 +500,9 @@ class BuildVolume(SceneNode): def _updateRaftThickness(self): old_raft_thickness = self._raft_thickness - self._adhesion_type = self._global_container_stack.getProperty("adhesion_type", "value") + if self._global_container_stack.extruders: + # This might be called before the extruder stacks have initialised, in which case getting the adhesion_type fails + self._adhesion_type = self._global_container_stack.getProperty("adhesion_type", "value") self._raft_thickness = 0.0 if self._adhesion_type == "raft": self._raft_thickness = ( @@ -522,8 +535,11 @@ class BuildVolume(SceneNode): if extra_z != self._extra_z_clearance: self._extra_z_clearance = extra_z - ## Update the build volume visualization def _onStackChanged(self): + self._stack_change_timer.start() + + ## Update the build volume visualization + def _onStackChangeTimerFinished(self): if self._global_container_stack: self._global_container_stack.propertyChanged.disconnect(self._onSettingPropertyChanged) extruders = ExtruderManager.getInstance().getActiveExtruderStacks() diff --git a/cura/CrashHandler.py b/cura/CrashHandler.py index 46544ca0ef..d43743bc37 100644 --- a/cura/CrashHandler.py +++ b/cura/CrashHandler.py @@ -36,18 +36,14 @@ else: except ImportError: CuraDebugMode = False # [CodeStyle: Reflecting imported value] -# List of exceptions that should be considered "fatal" and abort the program. -# These are primarily some exception types that we simply cannot really recover from -# (MemoryError and SystemError) and exceptions that indicate grave errors in the -# code that cause the Python interpreter to fail (SyntaxError, ImportError). -fatal_exception_types = [ - MemoryError, - SyntaxError, - ImportError, - SystemError, +# List of exceptions that should not be considered "fatal" and abort the program. +# These are primarily some exception types that we simply skip +skip_exception_types = [ + SystemExit, + KeyboardInterrupt, + GeneratorExit ] - class CrashHandler: crash_url = "https://stats.ultimaker.com/api/cura" @@ -70,7 +66,7 @@ class CrashHandler: # If Cura has fully started, we only show fatal errors. # If Cura has not fully started yet, we always show the early crash dialog. Otherwise, Cura will just crash # without any information. - if has_started and exception_type not in fatal_exception_types: + if has_started and exception_type in skip_exception_types: return if not has_started: @@ -387,7 +383,7 @@ class CrashHandler: Application.getInstance().callLater(self._show) def _show(self): - # When the exception is not in the fatal_exception_types list, the dialog is not created, so we don't need to show it + # When the exception is in the skip_exception_types list, the dialog is not created, so we don't need to show it if self.dialog: self.dialog.exec_() os._exit(1) diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 93a18318df..91e0966fed 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -3,7 +3,7 @@ from PyQt5.QtCore import QObject, QUrl from PyQt5.QtGui import QDesktopServices -from typing import List, TYPE_CHECKING +from typing import List, TYPE_CHECKING, cast from UM.Event import CallFunctionEvent from UM.FlameProfiler import pyqtSlot @@ -36,12 +36,12 @@ class CuraActions(QObject): # Starting a web browser from a signal handler connected to a menu will crash on windows. # So instead, defer the call to the next run of the event loop, since that does work. # Note that weirdly enough, only signal handlers that open a web browser fail like that. - event = CallFunctionEvent(self._openUrl, [QUrl("http://ultimaker.com/en/support/software")], {}) + event = CallFunctionEvent(self._openUrl, [QUrl("https://ultimaker.com/en/resources/manuals/software")], {}) cura.CuraApplication.CuraApplication.getInstance().functionEvent(event) @pyqtSlot() def openBugReportPage(self) -> None: - event = CallFunctionEvent(self._openUrl, [QUrl("http://github.com/Ultimaker/Cura/issues")], {}) + event = CallFunctionEvent(self._openUrl, [QUrl("https://github.com/Ultimaker/Cura/issues")], {}) cura.CuraApplication.CuraApplication.getInstance().functionEvent(event) ## Reset camera position and direction to default @@ -61,8 +61,10 @@ class CuraActions(QObject): operation = GroupedOperation() for node in Selection.getAllSelectedObjects(): current_node = node - while current_node.getParent() and current_node.getParent().callDecoration("isGroup"): - current_node = current_node.getParent() + parent_node = current_node.getParent() + while parent_node and parent_node.callDecoration("isGroup"): + current_node = parent_node + parent_node = current_node.getParent() # This was formerly done with SetTransformOperation but because of # unpredictable matrix deconstruction it was possible that mirrors @@ -150,13 +152,13 @@ class CuraActions(QObject): root = cura.CuraApplication.CuraApplication.getInstance().getController().getScene().getRoot() - nodes_to_change = [] + nodes_to_change = [] # type: List[SceneNode] for node in Selection.getAllSelectedObjects(): parent_node = node # Find the parent node to change instead while parent_node.getParent() != root: - parent_node = parent_node.getParent() + parent_node = cast(SceneNode, parent_node.getParent()) - for single_node in BreadthFirstIterator(parent_node): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. + for single_node in BreadthFirstIterator(parent_node): # type: ignore #Ignore type error because iter() should get called automatically by Python syntax. nodes_to_change.append(single_node) if not nodes_to_change: diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 47cc94f972..d3de15690d 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -4,7 +4,7 @@ import os import sys import time -from typing import cast, TYPE_CHECKING, Optional, Callable +from typing import cast, TYPE_CHECKING, Optional, Callable, List import numpy @@ -51,6 +51,7 @@ from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob from cura.Arranging.ShapeArray import ShapeArray from cura.MultiplyObjectsJob import MultiplyObjectsJob +from cura.GlobalStacksModel import GlobalStacksModel from cura.Scene.ConvexHullDecorator import ConvexHullDecorator from cura.Operations.SetParentOperation import SetParentOperation from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator @@ -113,8 +114,11 @@ from cura.Settings.CuraFormulaFunctions import CuraFormulaFunctions from cura.ObjectsModel import ObjectsModel +from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.NetworkMJPGImage import NetworkMJPGImage +from cura import ApplicationMetadata + from UM.FlameProfiler import pyqtSlot from UM.Decorators import override @@ -127,6 +131,7 @@ if TYPE_CHECKING: numpy.seterr(all = "ignore") + try: from cura.CuraVersion import CuraAppDisplayName, CuraVersion, CuraBuildType, CuraDebugMode, CuraSDKVersion # type: ignore except ImportError: @@ -134,14 +139,14 @@ except ImportError: CuraVersion = "master" # [CodeStyle: Reflecting imported value] CuraBuildType = "" CuraDebugMode = False - CuraSDKVersion = "5.0.0" + CuraSDKVersion = "6.0.0" class CuraApplication(QtApplication): # SettingVersion represents the set of settings available in the machine/extruder definitions. # You need to make sure that this version number needs to be increased if there is any non-backwards-compatible # changes of the settings. - SettingVersion = 5 + SettingVersion = 6 Created = False @@ -162,11 +167,11 @@ class CuraApplication(QtApplication): def __init__(self, *args, **kwargs): super().__init__(name = "cura", - app_display_name = CuraAppDisplayName, - version = CuraVersion, - api_version = CuraSDKVersion, - buildtype = CuraBuildType, - is_debug_mode = CuraDebugMode, + app_display_name = ApplicationMetadata.CuraAppDisplayName, + version = ApplicationMetadata.CuraVersion, + api_version = ApplicationMetadata.CuraSDKVersion, + buildtype = ApplicationMetadata.CuraBuildType, + is_debug_mode = ApplicationMetadata.CuraDebugMode, tray_icon_name = "cura-icon-32.png", **kwargs) @@ -181,7 +186,6 @@ class CuraApplication(QtApplication): # Variables set from CLI self._files_to_open = [] self._use_single_instance = False - self._trigger_early_crash = False # For debug only self._single_instance = None @@ -206,6 +210,8 @@ class CuraApplication(QtApplication): self._container_manager = None self._object_manager = None + self._extruders_model = None + self._extruders_model_with_optional = None self._build_plate_model = None self._multi_build_plate_model = None self._setting_visibility_presets_model = None @@ -292,7 +298,10 @@ class CuraApplication(QtApplication): sys.exit(0) self._use_single_instance = self._cli_args.single_instance - self._trigger_early_crash = self._cli_args.trigger_early_crash + # FOR TESTING ONLY + if self._cli_args.trigger_early_crash: + assert not "This crash is triggered by the trigger_early_crash command line argument." + for filename in self._cli_args.file: self._files_to_open.append(os.path.abspath(filename)) @@ -428,7 +437,8 @@ class CuraApplication(QtApplication): def startSplashWindowPhase(self) -> None: super().startSplashWindowPhase() - self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) + if not self.getIsHeadLess(): + self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png"))) self.setRequiredPlugins([ # Misc.: @@ -439,6 +449,7 @@ class CuraApplication(QtApplication): "XmlMaterialProfile", #Cura crashes without this one. "Toolbox", #This contains the interface to enable/disable plug-ins, so if you disable it you can't enable it back. "PrepareStage", #Cura is useless without this one since you can't load models. + "PreviewStage", #This shows the list of the plugin views that are installed in Cura. "MonitorStage", #Major part of Cura's functionality. "LocalFileOutputDevice", #Major part of Cura's functionality. "LocalContainerProvider", #Cura is useless without any profiles or setting definitions. @@ -492,7 +503,8 @@ class CuraApplication(QtApplication): preferences.addPreference("cura/choice_on_profile_override", "always_ask") preferences.addPreference("cura/choice_on_open_project", "always_ask") preferences.addPreference("cura/use_multi_build_plate", False) - + preferences.addPreference("view/settings_list_height", 400) + preferences.addPreference("view/settings_visible", False) preferences.addPreference("cura/currency", "€") preferences.addPreference("cura/material_settings", "{}") @@ -631,9 +643,7 @@ class CuraApplication(QtApplication): self._message_box_callback(button, *self._message_box_callback_arguments) self._message_box_callback = None self._message_box_callback_arguments = [] - - showPrintMonitor = pyqtSignal(bool, arguments = ["show"]) - + def setSaveDataEnabled(self, enabled: bool) -> None: self._save_data_enabled = enabled @@ -659,12 +669,12 @@ class CuraApplication(QtApplication): ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistry - def _loadPlugins(self): + def _loadPlugins(self) -> None: self._plugin_registry.addType("profile_reader", self._addProfileReader) self._plugin_registry.addType("profile_writer", self._addProfileWriter) if Platform.isLinux(): - lib_suffixes = {"", "64", "32", "x32"} #A few common ones on different distributions. + lib_suffixes = {"", "64", "32", "x32"} # A few common ones on different distributions. else: lib_suffixes = {""} for suffix in lib_suffixes: @@ -861,6 +871,19 @@ class CuraApplication(QtApplication): self._object_manager = ObjectsModel.createObjectsModel() return self._object_manager + @pyqtSlot(result = QObject) + def getExtrudersModel(self, *args) -> "ExtrudersModel": + if self._extruders_model is None: + self._extruders_model = ExtrudersModel(self) + return self._extruders_model + + @pyqtSlot(result = QObject) + def getExtrudersModelWithOptional(self, *args) -> "ExtrudersModel": + if self._extruders_model_with_optional is None: + self._extruders_model_with_optional = ExtrudersModel(self) + self._extruders_model_with_optional.setAddOptionalExtruder(True) + return self._extruders_model_with_optional + @pyqtSlot(result = QObject) def getMultiBuildPlateModel(self, *args) -> MultiBuildPlateModel: if self._multi_build_plate_model is None: @@ -935,7 +958,7 @@ class CuraApplication(QtApplication): engine.rootContext().setContextProperty("CuraApplication", self) engine.rootContext().setContextProperty("PrintInformation", self._print_information) engine.rootContext().setContextProperty("CuraActions", self._cura_actions) - engine.rootContext().setContextProperty("CuraSDKVersion", CuraSDKVersion) + engine.rootContext().setContextProperty("CuraSDKVersion", ApplicationMetadata.CuraSDKVersion) qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type") @@ -953,6 +976,7 @@ class CuraApplication(QtApplication): qmlRegisterType(MultiBuildPlateModel, "Cura", 1, 0, "MultiBuildPlateModel") qmlRegisterType(InstanceContainer, "Cura", 1, 0, "InstanceContainer") qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") + qmlRegisterType(GlobalStacksModel, "Cura", 1, 0, "GlobalStacksModel") qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel") qmlRegisterType(GenericMaterialsModel, "Cura", 1, 0, "GenericMaterialsModel") @@ -974,6 +998,8 @@ class CuraApplication(QtApplication): qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.getInstance) qmlRegisterType(SidebarCustomMenuItemsModel, "Cura", 1, 0, "SidebarCustomMenuItemsModel") + qmlRegisterType(PrinterOutputDevice, "Cura", 1, 0, "PrinterOutputDevice") + from cura.API import CuraAPI qmlRegisterSingletonType(CuraAPI, "Cura", 1, 1, "API", self.getCuraAPI) @@ -1084,88 +1110,6 @@ class CuraApplication(QtApplication): self._platform_activity = True if count > 0 else False self.activityChanged.emit() - # Remove all selected objects from the scene. - @pyqtSlot() - @deprecated("Moved to CuraActions", "2.6") - def deleteSelection(self): - if not self.getController().getToolsEnabled(): - return - removed_group_nodes = [] - op = GroupedOperation() - nodes = Selection.getAllSelectedObjects() - for node in nodes: - op.addOperation(RemoveSceneNodeOperation(node)) - group_node = node.getParent() - if group_node and group_node.callDecoration("isGroup") and group_node not in removed_group_nodes: - remaining_nodes_in_group = list(set(group_node.getChildren()) - set(nodes)) - if len(remaining_nodes_in_group) == 1: - removed_group_nodes.append(group_node) - op.addOperation(SetParentOperation(remaining_nodes_in_group[0], group_node.getParent())) - op.addOperation(RemoveSceneNodeOperation(group_node)) - op.push() - - ## Remove an object from the scene. - # Note that this only removes an object if it is selected. - @pyqtSlot("quint64") - @deprecated("Use deleteSelection instead", "2.6") - def deleteObject(self, object_id): - if not self.getController().getToolsEnabled(): - return - - node = self.getController().getScene().findObject(object_id) - - if not node and object_id != 0: # Workaround for tool handles overlapping the selected object - node = Selection.getSelectedObject(0) - - if node: - op = GroupedOperation() - op.addOperation(RemoveSceneNodeOperation(node)) - - group_node = node.getParent() - if group_node: - # Note that at this point the node has not yet been deleted - if len(group_node.getChildren()) <= 2 and group_node.callDecoration("isGroup"): - op.addOperation(SetParentOperation(group_node.getChildren()[0], group_node.getParent())) - op.addOperation(RemoveSceneNodeOperation(group_node)) - - op.push() - - ## Create a number of copies of existing object. - # \param object_id - # \param count number of copies - # \param min_offset minimum offset to other objects. - @pyqtSlot("quint64", int) - @deprecated("Use CuraActions::multiplySelection", "2.6") - def multiplyObject(self, object_id, count, min_offset = 8): - node = self.getController().getScene().findObject(object_id) - if not node: - node = Selection.getSelectedObject(0) - - while node.getParent() and node.getParent().callDecoration("isGroup"): - node = node.getParent() - - job = MultiplyObjectsJob([node], count, min_offset) - job.start() - return - - ## Center object on platform. - @pyqtSlot("quint64") - @deprecated("Use CuraActions::centerSelection", "2.6") - def centerObject(self, object_id): - node = self.getController().getScene().findObject(object_id) - if not node and object_id != 0: # Workaround for tool handles overlapping the selected object - node = Selection.getSelectedObject(0) - - if not node: - return - - if node.getParent() and node.getParent().callDecoration("isGroup"): - node = node.getParent() - - if node: - op = SetTransformOperation(node, Vector()) - op.push() - ## Select all nodes containing mesh data in the scene. @pyqtSlot() def selectAll(self): @@ -1245,62 +1189,75 @@ class CuraApplication(QtApplication): ## Arrange all objects. @pyqtSlot() - def arrangeObjectsToAllBuildPlates(self): - nodes = [] - for node in DepthFirstIterator(self.getController().getScene().getRoot()): + def arrangeObjectsToAllBuildPlates(self) -> None: + nodes_to_arrange = [] + for node in DepthFirstIterator(self.getController().getScene().getRoot()): # type: ignore if not isinstance(node, SceneNode): continue + if not node.getMeshData() and not node.callDecoration("isGroup"): continue # Node that doesnt have a mesh and is not a group. - if node.getParent() and node.getParent().callDecoration("isGroup"): - continue # Grouped nodes don't need resetting as their parent (the group) is resetted) + + parent_node = node.getParent() + if parent_node and parent_node.callDecoration("isGroup"): + continue # Grouped nodes don't need resetting as their parent (the group) is reset) + if not node.callDecoration("isSliceable") and not node.callDecoration("isGroup"): continue # i.e. node with layer data + + bounding_box = node.getBoundingBox() # Skip nodes that are too big - if node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth: - nodes.append(node) - job = ArrangeObjectsAllBuildPlatesJob(nodes) + if bounding_box is None or bounding_box.width < self._volume.getBoundingBox().width or bounding_box.depth < self._volume.getBoundingBox().depth: + nodes_to_arrange.append(node) + job = ArrangeObjectsAllBuildPlatesJob(nodes_to_arrange) job.start() self.getCuraSceneController().setActiveBuildPlate(0) # Select first build plate # Single build plate @pyqtSlot() - def arrangeAll(self): - nodes = [] + def arrangeAll(self) -> None: + nodes_to_arrange = [] active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate - for node in DepthFirstIterator(self.getController().getScene().getRoot()): + for node in DepthFirstIterator(self.getController().getScene().getRoot()): # type: ignore if not isinstance(node, SceneNode): continue + if not node.getMeshData() and not node.callDecoration("isGroup"): continue # Node that doesnt have a mesh and is not a group. - if node.getParent() and node.getParent().callDecoration("isGroup"): + + parent_node = node.getParent() + if parent_node and parent_node.callDecoration("isGroup"): continue # Grouped nodes don't need resetting as their parent (the group) is resetted) + if not node.isSelectable(): continue # i.e. node with layer data + if not node.callDecoration("isSliceable") and not node.callDecoration("isGroup"): continue # i.e. node with layer data + if node.callDecoration("getBuildPlateNumber") == active_build_plate: # Skip nodes that are too big - if node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth: - nodes.append(node) - self.arrange(nodes, fixed_nodes = []) + bounding_box = node.getBoundingBox() + if bounding_box is None or bounding_box.width < self._volume.getBoundingBox().width or bounding_box.depth < self._volume.getBoundingBox().depth: + nodes_to_arrange.append(node) + self.arrange(nodes_to_arrange, fixed_nodes = []) ## Arrange a set of nodes given a set of fixed nodes # \param nodes nodes that we have to place # \param fixed_nodes nodes that are placed in the arranger before finding spots for nodes - def arrange(self, nodes, fixed_nodes): + def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode]) -> None: min_offset = self.getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset = max(min_offset, 8)) job.start() ## Reload all mesh data on the screen from file. @pyqtSlot() - def reloadAll(self): + def reloadAll(self) -> None: Logger.log("i", "Reloading all loaded mesh data.") nodes = [] has_merged_nodes = False - for node in DepthFirstIterator(self.getController().getScene().getRoot()): - if not isinstance(node, CuraSceneNode) or not node.getMeshData() : + for node in DepthFirstIterator(self.getController().getScene().getRoot()): # type: ignore + if not isinstance(node, CuraSceneNode) or not node.getMeshData(): if node.getName() == "MergedMesh": has_merged_nodes = True continue @@ -1314,7 +1271,7 @@ class CuraApplication(QtApplication): file_name = node.getMeshData().getFileName() if file_name: job = ReadMeshJob(file_name) - job._node = node + job._node = node # type: ignore job.finished.connect(self._reloadMeshFinished) if has_merged_nodes: job.finished.connect(self.updateOriginOfMergedMeshes) @@ -1323,20 +1280,8 @@ class CuraApplication(QtApplication): else: Logger.log("w", "Unable to reload data because we don't have a filename.") - - ## Get logging data of the backend engine - # \returns \type{string} Logging data - @pyqtSlot(result = str) - def getEngineLog(self): - log = "" - - for entry in self.getBackend().getLog(): - log += entry.decode() - - return log - @pyqtSlot("QStringList") - def setExpandedCategories(self, categories): + def setExpandedCategories(self, categories: List[str]) -> None: categories = list(set(categories)) categories.sort() joined = ";".join(categories) @@ -1347,7 +1292,7 @@ class CuraApplication(QtApplication): expandedCategoriesChanged = pyqtSignal() @pyqtProperty("QStringList", notify = expandedCategoriesChanged) - def expandedCategories(self): + def expandedCategories(self) -> List[str]: return self.getPreferences().getValue("cura/categories_expanded").split(";") @pyqtSlot() @@ -1397,13 +1342,12 @@ class CuraApplication(QtApplication): ## Updates origin position of all merged meshes - # \param jobNode \type{Job} empty object which passed which is required by JobQueue - def updateOriginOfMergedMeshes(self, jobNode): + def updateOriginOfMergedMeshes(self, _): group_nodes = [] for node in DepthFirstIterator(self.getController().getScene().getRoot()): if isinstance(node, CuraSceneNode) and node.getName() == "MergedMesh": - #checking by name might be not enough, the merged mesh should has "GroupDecorator" decorator + # Checking by name might be not enough, the merged mesh should has "GroupDecorator" decorator for decorator in node.getDecorators(): if isinstance(decorator, GroupDecorator): group_nodes.append(node) @@ -1447,7 +1391,7 @@ class CuraApplication(QtApplication): @pyqtSlot() - def groupSelected(self): + def groupSelected(self) -> None: # Create a group-node group_node = CuraSceneNode() group_decorator = GroupDecorator() @@ -1463,7 +1407,8 @@ class CuraApplication(QtApplication): # Remove nodes that are directly parented to another selected node from the selection so they remain parented selected_nodes = Selection.getAllSelectedObjects().copy() for node in selected_nodes: - if node.getParent() in selected_nodes and not node.getParent().callDecoration("isGroup"): + parent = node.getParent() + if parent is not None and parent in selected_nodes and not parent.callDecoration("isGroup"): Selection.remove(node) # Move selected nodes into the group-node @@ -1475,7 +1420,7 @@ class CuraApplication(QtApplication): Selection.add(group_node) @pyqtSlot() - def ungroupSelected(self): + def ungroupSelected(self) -> None: selected_objects = Selection.getAllSelectedObjects().copy() for node in selected_objects: if node.callDecoration("isGroup"): @@ -1498,7 +1443,7 @@ class CuraApplication(QtApplication): # Note: The group removes itself from the scene once all its children have left it, # see GroupDecorator._onChildrenChanged - def _createSplashScreen(self): + def _createSplashScreen(self) -> Optional[CuraSplashScreen.CuraSplashScreen]: if self._is_headless: return None return CuraSplashScreen.CuraSplashScreen() @@ -1664,7 +1609,9 @@ class CuraApplication(QtApplication): is_non_sliceable = "." + file_extension in self._non_sliceable_extensions if is_non_sliceable: - self.callLater(lambda: self.getController().setActiveView("SimulationView")) + # Need to switch first to the preview stage and then to layer view + self.callLater(lambda: (self.getController().setActiveStage("PreviewStage"), + self.getController().setActiveView("SimulationView"))) block_slicing_decorator = BlockSlicingDecorator() node.addDecorator(block_slicing_decorator) diff --git a/cura/CuraVersion.py.in b/cura/CuraVersion.py.in index 7c6304231d..770a0efd7b 100644 --- a/cura/CuraVersion.py.in +++ b/cura/CuraVersion.py.in @@ -8,3 +8,4 @@ CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False CuraSDKVersion = "@CURA_SDK_VERSION@" CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@" CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@" +CuraCloudAccountAPIRoot = "@CURA_CLOUD_ACCOUNT_API_ROOT@" diff --git a/cura/CuraView.py b/cura/CuraView.py new file mode 100644 index 0000000000..978c651b43 --- /dev/null +++ b/cura/CuraView.py @@ -0,0 +1,24 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import pyqtProperty, QUrl + +from UM.View.View import View + + +# Since Cura has a few pre-defined "space claims" for the locations of certain components, we've provided some structure +# to indicate this. +# MainComponent works in the same way the MainComponent of a stage. +# the stageMenuComponent returns an item that should be used somehwere in the stage menu. It's up to the active stage +# to actually do something with this. +class CuraView(View): + def __init__(self, parent = None) -> None: + super().__init__(parent) + + @pyqtProperty(QUrl, constant = True) + def mainComponent(self) -> QUrl: + return self.getDisplayComponent("main") + + @pyqtProperty(QUrl, constant = True) + def stageMenuComponent(self) -> QUrl: + return self.getDisplayComponent("menu") \ No newline at end of file diff --git a/cura/GlobalStacksModel.py b/cura/GlobalStacksModel.py new file mode 100644 index 0000000000..289a03d1c4 --- /dev/null +++ b/cura/GlobalStacksModel.py @@ -0,0 +1,63 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from UM.Qt.ListModel import ListModel + +from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal + +from UM.Settings.ContainerRegistry import ContainerRegistry +from UM.Settings.ContainerStack import ContainerStack + +from cura.PrinterOutputDevice import ConnectionType + +from cura.Settings.GlobalStack import GlobalStack + + +class GlobalStacksModel(ListModel): + NameRole = Qt.UserRole + 1 + IdRole = Qt.UserRole + 2 + HasRemoteConnectionRole = Qt.UserRole + 3 + ConnectionTypeRole = Qt.UserRole + 4 + MetaDataRole = Qt.UserRole + 5 + + def __init__(self, parent = None): + super().__init__(parent) + self.addRoleName(self.NameRole, "name") + self.addRoleName(self.IdRole, "id") + self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection") + self.addRoleName(self.ConnectionTypeRole, "connectionType") + self.addRoleName(self.MetaDataRole, "metadata") + self._container_stacks = [] + + # Listen to changes + ContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged) + ContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged) + ContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged) + self._filter_dict = {} + self._update() + + ## Handler for container added/removed events from registry + def _onContainerChanged(self, container): + # We only need to update when the added / removed container GlobalStack + if isinstance(container, GlobalStack): + self._update() + + def _update(self) -> None: + items = [] + + container_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine") + + for container_stack in container_stacks: + connection_type = int(container_stack.getMetaDataEntry("connection_type", ConnectionType.NotConnected.value)) + has_remote_connection = connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value] + if container_stack.getMetaDataEntry("hidden", False) in ["True", True]: + continue + + # TODO: Remove reference to connect group name. + items.append({"name": container_stack.getMetaDataEntry("connect_group_name", container_stack.getName()), + "id": container_stack.getId(), + "hasRemoteConnection": has_remote_connection, + "connectionType": connection_type, + "metadata": container_stack.getMetaData().copy()}) + items.sort(key=lambda i: not i["hasRemoteConnection"]) + self.setItems(items) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index f33934de0c..1941a558ba 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -5,6 +5,8 @@ from UM.Application import Application from typing import Any import numpy +from UM.Logger import Logger + class LayerPolygon: NoneType = 0 @@ -18,7 +20,8 @@ class LayerPolygon: MoveCombingType = 8 MoveRetractionType = 9 SupportInterfaceType = 10 - __number_of_types = 11 + PrimeTower = 11 + __number_of_types = 12 __jump_map = numpy.logical_or(numpy.logical_or(numpy.arange(__number_of_types) == NoneType, numpy.arange(__number_of_types) == MoveCombingType), numpy.arange(__number_of_types) == MoveRetractionType) @@ -33,7 +36,8 @@ class LayerPolygon: self._extruder = extruder self._types = line_types for i in range(len(self._types)): - if self._types[i] >= self.__number_of_types: #Got faulty line data from the engine. + if self._types[i] >= self.__number_of_types: # Got faulty line data from the engine. + Logger.log("w", "Found an unknown line type: %s", i) self._types[i] = self.NoneType self._data = data self._line_widths = line_widths @@ -236,7 +240,8 @@ class LayerPolygon: theme.getColor("layerview_support_infill").getRgbF(), # SupportInfillType theme.getColor("layerview_move_combing").getRgbF(), # MoveCombingType theme.getColor("layerview_move_retraction").getRgbF(), # MoveRetractionType - theme.getColor("layerview_support_interface").getRgbF() # SupportInterfaceType + theme.getColor("layerview_support_interface").getRgbF(), # SupportInterfaceType + theme.getColor("layerview_prime_tower").getRgbF() ]) return cls.__color_map diff --git a/cura/Machines/MachineErrorChecker.py b/cura/Machines/MachineErrorChecker.py index 06f064315b..fb11123af6 100644 --- a/cura/Machines/MachineErrorChecker.py +++ b/cura/Machines/MachineErrorChecker.py @@ -64,21 +64,21 @@ class MachineErrorChecker(QObject): def _onMachineChanged(self) -> None: if self._global_stack: - self._global_stack.propertyChanged.disconnect(self.startErrorCheck) + self._global_stack.propertyChanged.disconnect(self.startErrorCheckPropertyChanged) self._global_stack.containersChanged.disconnect(self.startErrorCheck) for extruder in self._global_stack.extruders.values(): - extruder.propertyChanged.disconnect(self.startErrorCheck) + extruder.propertyChanged.disconnect(self.startErrorCheckPropertyChanged) extruder.containersChanged.disconnect(self.startErrorCheck) self._global_stack = self._machine_manager.activeMachine if self._global_stack: - self._global_stack.propertyChanged.connect(self.startErrorCheck) + self._global_stack.propertyChanged.connect(self.startErrorCheckPropertyChanged) self._global_stack.containersChanged.connect(self.startErrorCheck) for extruder in self._global_stack.extruders.values(): - extruder.propertyChanged.connect(self.startErrorCheck) + extruder.propertyChanged.connect(self.startErrorCheckPropertyChanged) extruder.containersChanged.connect(self.startErrorCheck) hasErrorUpdated = pyqtSignal() @@ -93,6 +93,13 @@ class MachineErrorChecker(QObject): def needToWaitForResult(self) -> bool: return self._need_to_check or self._check_in_progress + # Start the error check for property changed + # this is seperate from the startErrorCheck because it ignores a number property types + def startErrorCheckPropertyChanged(self, key, property_name): + if property_name != "value": + return + self.startErrorCheck() + # Starts the error check timer to schedule a new error check. def startErrorCheck(self, *args) -> None: if not self._check_in_progress: diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index aee96f3153..160508e7a6 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -302,6 +302,10 @@ class MaterialManager(QObject): def getMaterialGroupListByGUID(self, guid: str) -> Optional[List[MaterialGroup]]: return self._guid_material_groups_map.get(guid) + # Returns a dict of all material groups organized by root_material_id. + def getAllMaterialGroups(self) -> Dict[str, "MaterialGroup"]: + return self._material_group_map + # # Return a dict with all root material IDs (k) and ContainerNodes (v) that's suitable for the given setup. # @@ -679,7 +683,11 @@ class MaterialManager(QObject): @pyqtSlot(str) def removeFavorite(self, root_material_id: str) -> None: - self._favorites.remove(root_material_id) + try: + self._favorites.remove(root_material_id) + except KeyError: + Logger.log("w", "Could not delete material %s from favorites as it was already deleted", root_material_id) + return self.materialsUpdated.emit() # Ensure all settings are saved. @@ -688,4 +696,4 @@ class MaterialManager(QObject): @pyqtSlot() def getFavorites(self): - return self._favorites \ No newline at end of file + return self._favorites diff --git a/cura/Machines/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py index ef2e760330..212e4fcf1e 100644 --- a/cura/Machines/Models/BaseMaterialsModel.py +++ b/cura/Machines/Models/BaseMaterialsModel.py @@ -1,5 +1,6 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Optional, Dict, Set from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty from UM.Qt.ListModel import ListModel @@ -9,6 +10,9 @@ from UM.Qt.ListModel import ListModel # Those 2 models are used by the material drop down menu to show generic materials and branded materials separately. # The extruder position defined here is being used to bound a menu to the correct extruder. This is used in the top # bar menu "Settings" -> "Extruder nr" -> "Material" -> this menu +from cura.Machines.MaterialNode import MaterialNode + + class BaseMaterialsModel(ListModel): extruderPositionChanged = pyqtSignal() @@ -54,8 +58,8 @@ class BaseMaterialsModel(ListModel): self._extruder_position = 0 self._extruder_stack = None - self._available_materials = None - self._favorite_ids = None + self._available_materials = None # type: Optional[Dict[str, MaterialNode]] + self._favorite_ids = set() # type: Set[str] def _updateExtruderStack(self): global_stack = self._machine_manager.activeMachine @@ -102,7 +106,6 @@ class BaseMaterialsModel(ListModel): return False extruder_stack = global_stack.extruders[extruder_position] - self._available_materials = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, extruder_stack) if self._available_materials is None: return False diff --git a/cura/Machines/Models/FavoriteMaterialsModel.py b/cura/Machines/Models/FavoriteMaterialsModel.py index 18fe310c44..98a2a01597 100644 --- a/cura/Machines/Models/FavoriteMaterialsModel.py +++ b/cura/Machines/Models/FavoriteMaterialsModel.py @@ -1,20 +1,16 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from UM.Logger import Logger from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel +## Model that shows the list of favorite materials. class FavoriteMaterialsModel(BaseMaterialsModel): - def __init__(self, parent = None): super().__init__(parent) self._update() def _update(self): - - # Perform standard check and reset if the check fails if not self._canUpdate(): - self.setItems([]) return # Get updated list of favorites diff --git a/cura/Machines/Models/GenericMaterialsModel.py b/cura/Machines/Models/GenericMaterialsModel.py index c276b865bf..8f41dd6a70 100644 --- a/cura/Machines/Models/GenericMaterialsModel.py +++ b/cura/Machines/Models/GenericMaterialsModel.py @@ -11,10 +11,7 @@ class GenericMaterialsModel(BaseMaterialsModel): self._update() def _update(self): - - # Perform standard check and reset if the check fails if not self._canUpdate(): - self.setItems([]) return # Get updated list of favorites diff --git a/cura/Machines/Models/MaterialBrandsModel.py b/cura/Machines/Models/MaterialBrandsModel.py index 458e4d9b47..ac82cf6670 100644 --- a/cura/Machines/Models/MaterialBrandsModel.py +++ b/cura/Machines/Models/MaterialBrandsModel.py @@ -28,12 +28,8 @@ class MaterialBrandsModel(BaseMaterialsModel): self._update() def _update(self): - - # Perform standard check and reset if the check fails if not self._canUpdate(): - self.setItems([]) return - # Get updated list of favorites self._favorite_ids = self._material_manager.getFavorites() diff --git a/cura/Machines/Models/NozzleModel.py b/cura/Machines/Models/NozzleModel.py index 9d97106d6b..785ff5b9b9 100644 --- a/cura/Machines/Models/NozzleModel.py +++ b/cura/Machines/Models/NozzleModel.py @@ -33,8 +33,6 @@ class NozzleModel(ListModel): def _update(self): Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) - self.items.clear() - global_stack = self._machine_manager.activeMachine if global_stack is None: self.setItems([]) diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py index a01cc1194f..7ccc886bfe 100644 --- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QTimer from UM.Application import Application from UM.Logger import Logger @@ -21,6 +21,7 @@ class QualityProfilesDropDownMenuModel(ListModel): AvailableRole = Qt.UserRole + 5 QualityGroupRole = Qt.UserRole + 6 QualityChangesGroupRole = Qt.UserRole + 7 + IsExperimentalRole = Qt.UserRole + 8 def __init__(self, parent = None): super().__init__(parent) @@ -32,20 +33,29 @@ class QualityProfilesDropDownMenuModel(ListModel): self.addRoleName(self.AvailableRole, "available") #Whether the quality profile is available in our current nozzle + material. self.addRoleName(self.QualityGroupRole, "quality_group") self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group") + self.addRoleName(self.IsExperimentalRole, "is_experimental") self._application = Application.getInstance() self._machine_manager = self._application.getMachineManager() self._quality_manager = Application.getInstance().getQualityManager() - self._application.globalContainerStackChanged.connect(self._update) - self._machine_manager.activeQualityGroupChanged.connect(self._update) - self._machine_manager.extruderChanged.connect(self._update) - self._quality_manager.qualitiesUpdated.connect(self._update) + self._application.globalContainerStackChanged.connect(self._onChange) + self._machine_manager.activeQualityGroupChanged.connect(self._onChange) + self._machine_manager.extruderChanged.connect(self._onChange) + self._quality_manager.qualitiesUpdated.connect(self._onChange) self._layer_height_unit = "" # This is cached + self._update_timer = QTimer() # type: QTimer + self._update_timer.setInterval(100) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._update) + self._update() + def _onChange(self) -> None: + self._update_timer.start() + def _update(self): Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) @@ -74,7 +84,8 @@ class QualityProfilesDropDownMenuModel(ListModel): "layer_height": layer_height, "layer_height_unit": self._layer_height_unit, "available": quality_group.is_available, - "quality_group": quality_group} + "quality_group": quality_group, + "is_experimental": quality_group.is_experimental} item_list.append(item) diff --git a/cura/Machines/Models/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py index 79131521f2..baa8e3ed29 100644 --- a/cura/Machines/Models/SettingVisibilityPresetsModel.py +++ b/cura/Machines/Models/SettingVisibilityPresetsModel.py @@ -6,6 +6,7 @@ from typing import Optional, List from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from UM.Logger import Logger +from UM.Preferences import Preferences from UM.Resources import Resources from UM.i18n import i18nCatalog @@ -18,14 +19,20 @@ class SettingVisibilityPresetsModel(QObject): onItemsChanged = pyqtSignal() activePresetChanged = pyqtSignal() - def __init__(self, preferences, parent = None): + def __init__(self, preferences: Preferences, parent = None) -> None: super().__init__(parent) self._items = [] # type: List[SettingVisibilityPreset] + self._custom_preset = SettingVisibilityPreset(preset_id = "custom", name = "Custom selection", weight = -100) + self._populate() basic_item = self.getVisibilityPresetById("basic") - basic_visibile_settings = ";".join(basic_item.settings) + if basic_item is not None: + basic_visibile_settings = ";".join(basic_item.settings) + else: + Logger.log("w", "Unable to find the basic visiblity preset.") + basic_visibile_settings = "" self._preferences = preferences @@ -42,7 +49,8 @@ class SettingVisibilityPresetsModel(QObject): visible_settings = self._preferences.getValue("general/visible_settings") if not visible_settings: - self._preferences.setValue("general/visible_settings", ";".join(self._active_preset_item.settings)) + new_visible_settings = self._active_preset_item.settings if self._active_preset_item is not None else [] + self._preferences.setValue("general/visible_settings", ";".join(new_visible_settings)) else: self._onPreferencesChanged("general/visible_settings") @@ -59,9 +67,7 @@ class SettingVisibilityPresetsModel(QObject): def _populate(self) -> None: from cura.CuraApplication import CuraApplication items = [] # type: List[SettingVisibilityPreset] - - custom_preset = SettingVisibilityPreset(preset_id="custom", name ="Custom selection", weight = -100) - items.append(custom_preset) + items.append(self._custom_preset) for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.SettingVisibilityPreset): setting_visibility_preset = SettingVisibilityPreset() try: @@ -77,7 +83,7 @@ class SettingVisibilityPresetsModel(QObject): self.setItems(items) @pyqtProperty("QVariantList", notify = onItemsChanged) - def items(self): + def items(self) -> List[SettingVisibilityPreset]: return self._items def setItems(self, items: List[SettingVisibilityPreset]) -> None: @@ -87,7 +93,7 @@ class SettingVisibilityPresetsModel(QObject): @pyqtSlot(str) def setActivePreset(self, preset_id: str) -> None: - if preset_id == self._active_preset_item.presetId: + if self._active_preset_item is not None and preset_id == self._active_preset_item.presetId: Logger.log("d", "Same setting visibility preset [%s] selected, do nothing.", preset_id) return @@ -96,7 +102,7 @@ class SettingVisibilityPresetsModel(QObject): Logger.log("w", "Tried to set active preset to unknown id [%s]", preset_id) return - need_to_save_to_custom = self._active_preset_item.presetId == "custom" and preset_id != "custom" + need_to_save_to_custom = self._active_preset_item is None or (self._active_preset_item.presetId == "custom" and preset_id != "custom") if need_to_save_to_custom: # Save the current visibility settings to custom current_visibility_string = self._preferences.getValue("general/visible_settings") @@ -117,7 +123,9 @@ class SettingVisibilityPresetsModel(QObject): @pyqtProperty(str, notify = activePresetChanged) def activePreset(self) -> str: - return self._active_preset_item.presetId + if self._active_preset_item is not None: + return self._active_preset_item.presetId + return "" def _onPreferencesChanged(self, name: str) -> None: if name != "general/visible_settings": @@ -149,7 +157,12 @@ class SettingVisibilityPresetsModel(QObject): else: item_to_set = matching_preset_item + # If we didn't find a matching preset, fallback to custom. + if item_to_set is None: + item_to_set = self._custom_preset + if self._active_preset_item is None or self._active_preset_item.presetId != item_to_set.presetId: self._active_preset_item = item_to_set - self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item.presetId) + if self._active_preset_item is not None: + self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item.presetId) self.activePresetChanged.emit() diff --git a/cura/Machines/QualityGroup.py b/cura/Machines/QualityGroup.py index 535ba453f8..f5bcbb0de8 100644 --- a/cura/Machines/QualityGroup.py +++ b/cura/Machines/QualityGroup.py @@ -4,6 +4,9 @@ from typing import Dict, Optional, List, Set from PyQt5.QtCore import QObject, pyqtSlot + +from UM.Util import parseBool + from cura.Machines.ContainerNode import ContainerNode @@ -29,6 +32,7 @@ class QualityGroup(QObject): self.nodes_for_extruders = {} # type: Dict[int, ContainerNode] self.quality_type = quality_type self.is_available = False + self.is_experimental = False @pyqtSlot(result = str) def getName(self) -> str: @@ -51,3 +55,17 @@ class QualityGroup(QObject): for extruder_node in self.nodes_for_extruders.values(): result.append(extruder_node) return result + + def setGlobalNode(self, node: "ContainerNode") -> None: + self.node_for_global = node + + # Update is_experimental flag + is_experimental = parseBool(node.getMetaDataEntry("is_experimental", False)) + self.is_experimental |= is_experimental + + def setExtruderNode(self, position: int, node: "ContainerNode") -> None: + self.nodes_for_extruders[position] = node + + # Update is_experimental flag + is_experimental = parseBool(node.getMetaDataEntry("is_experimental", False)) + self.is_experimental |= is_experimental diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index a784d17f0b..34cc9ce4b2 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -235,7 +235,7 @@ class QualityManager(QObject): for quality_type, quality_node in node.quality_type_map.items(): quality_group = QualityGroup(quality_node.getMetaDataEntry("name", ""), quality_type) - quality_group.node_for_global = quality_node + quality_group.setGlobalNode(quality_node) quality_group_dict[quality_type] = quality_group break @@ -337,7 +337,7 @@ class QualityManager(QObject): quality_group = quality_group_dict[quality_type] if position not in quality_group.nodes_for_extruders: - quality_group.nodes_for_extruders[position] = quality_node + quality_group.setExtruderNode(position, quality_node) # If the machine has its own specific qualities, for extruders, it should skip the global qualities # and use the material/variant specific qualities. @@ -367,7 +367,7 @@ class QualityManager(QObject): if node and node.quality_type_map: for quality_type, quality_node in node.quality_type_map.items(): quality_group = QualityGroup(quality_node.getMetaDataEntry("name", ""), quality_type) - quality_group.node_for_global = quality_node + quality_group.setGlobalNode(quality_node) quality_group_dict[quality_type] = quality_group break diff --git a/cura/Machines/VariantManager.py b/cura/Machines/VariantManager.py index f6feb70e09..eaaa9fc5f0 100644 --- a/cura/Machines/VariantManager.py +++ b/cura/Machines/VariantManager.py @@ -107,7 +107,7 @@ class VariantManager: break return variant_node - return self._machine_to_variant_dict_map[machine_definition_id].get(variant_type, {}).get(variant_name) + return self._machine_to_variant_dict_map.get(machine_definition_id, {}).get(variant_type, {}).get(variant_name) def getVariantNodes(self, machine: "GlobalStack", variant_type: "VariantType") -> Dict[str, ContainerNode]: machine_definition_id = machine.definition.getId() diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index 3cbf795952..e71bbf6668 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -25,7 +25,7 @@ class MultiplyObjectsJob(Job): def run(self): status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime=0, - dismissable=False, progress=0, title = i18n_catalog.i18nc("@info:title", "Placing Object")) + dismissable=False, progress=0, title = i18n_catalog.i18nc("@info:title", "Placing Objects")) status_message.show() scene = Application.getInstance().getController().getScene() diff --git a/cura/OAuth2/AuthorizationHelpers.py b/cura/OAuth2/AuthorizationHelpers.py index f75ad9c9f9..762d0db069 100644 --- a/cura/OAuth2/AuthorizationHelpers.py +++ b/cura/OAuth2/AuthorizationHelpers.py @@ -81,9 +81,14 @@ class AuthorizationHelpers: # \param access_token: The encoded JWT token. # \return: Dict containing some profile data. def parseJWT(self, access_token: str) -> Optional["UserProfile"]: - token_request = requests.get("{}/check-token".format(self._settings.OAUTH_SERVER_URL), headers = { - "Authorization": "Bearer {}".format(access_token) - }) + try: + token_request = requests.get("{}/check-token".format(self._settings.OAUTH_SERVER_URL), headers = { + "Authorization": "Bearer {}".format(access_token) + }) + except ConnectionError: + # Connection was suddenly dropped. Nothing we can do about that. + Logger.logException("e", "Something failed while attempting to parse the JWT token") + return None if token_request.status_code not in (200, 201): Logger.log("w", "Could not retrieve token data from auth server: %s", token_request.text) return None diff --git a/cura/OAuth2/AuthorizationService.py b/cura/OAuth2/AuthorizationService.py index 4355891139..1e98dc9cee 100644 --- a/cura/OAuth2/AuthorizationService.py +++ b/cura/OAuth2/AuthorizationService.py @@ -52,8 +52,11 @@ class AuthorizationService: if not self._user_profile: # If no user profile was stored locally, we try to get it from JWT. self._user_profile = self._parseJWT() - if not self._user_profile: + + if not self._user_profile and self._auth_data: # If there is still no user profile from the JWT, we have to log in again. + Logger.log("w", "The user profile could not be loaded. The user must log in again!") + self.deleteAuthData() return None return self._user_profile @@ -83,9 +86,11 @@ class AuthorizationService: if not self.getUserProfile(): # We check if we can get the user profile. # If we can't get it, that means the access token (JWT) was invalid or expired. + Logger.log("w", "Unable to get the user profile.") return None if self._auth_data is None: + Logger.log("d", "No auth data to retrieve the access_token from") return None return self._auth_data.access_token diff --git a/cura/OAuth2/Models.py b/cura/OAuth2/Models.py index 83fc22554f..0515e789e6 100644 --- a/cura/OAuth2/Models.py +++ b/cura/OAuth2/Models.py @@ -1,4 +1,6 @@ # Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + from typing import Optional diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index e11f70a54c..e863689e21 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -14,8 +14,7 @@ from UM.Logger import Logger from UM.Qt.Duration import Duration from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog -from UM.MimeTypeDatabase import MimeTypeDatabase - +from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError from typing import TYPE_CHECKING @@ -361,7 +360,7 @@ class PrintInformation(QObject): try: mime_type = MimeTypeDatabase.getMimeTypeForFile(name) data = mime_type.stripExtension(name) - except: + except MimeTypeNotFoundError: Logger.log("w", "Unsupported Mime Type Database file extension %s", name) if data is not None and check_name is not None: @@ -395,28 +394,14 @@ class PrintInformation(QObject): return active_machine_type_name = global_container_stack.definition.getName() - abbr_machine = "" - for word in re.findall(r"[\w']+", active_machine_type_name): - if word.lower() == "ultimaker": - abbr_machine += "UM" - elif word.isdigit(): - abbr_machine += word - else: - stripped_word = self._stripAccents(word.upper()) - # - use only the first character if the word is too long (> 3 characters) - # - use the whole word if it's not too long (<= 3 characters) - if len(stripped_word) > 3: - stripped_word = stripped_word[0] - abbr_machine += stripped_word - - self._abbr_machine = abbr_machine + self._abbr_machine = self._application.getMachineManager().getAbbreviatedMachineName(active_machine_type_name) ## Utility method that strips accents from characters (eg: â -> a) def _stripAccents(self, to_strip: str) -> str: return ''.join(char for char in unicodedata.normalize('NFD', to_strip) if unicodedata.category(char) != 'Mn') @pyqtSlot(result = "QVariantMap") - def getFeaturePrintTimes(self): + def getFeaturePrintTimes(self) -> Dict[str, Duration]: result = {} if self._active_build_plate not in self._print_times_per_feature: self._initPrintTimesPerFeature(self._active_build_plate) diff --git a/cura/PrinterOutput/ConfigurationModel.py b/cura/PrinterOutput/ConfigurationModel.py index 89e609c913..f9d0c7e36b 100644 --- a/cura/PrinterOutput/ConfigurationModel.py +++ b/cura/PrinterOutput/ConfigurationModel.py @@ -54,7 +54,7 @@ class ConfigurationModel(QObject): for configuration in self._extruder_configurations: if configuration is None: return False - return self._printer_type is not None + return self._printer_type != "" def __str__(self): message_chunks = [] diff --git a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py index 35d2ce014a..47a6caf3e5 100644 --- a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py +++ b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py @@ -4,19 +4,21 @@ from UM.FileHandler.FileHandler import FileHandler #For typing. from UM.Logger import Logger from UM.Scene.SceneNode import SceneNode #For typing. +from cura.API import Account from cura.CuraApplication import CuraApplication -from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState +from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState, ConnectionType from PyQt5.QtNetwork import QHttpMultiPart, QHttpPart, QNetworkRequest, QNetworkAccessManager, QNetworkReply, QAuthenticator from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QUrl, QCoreApplication from time import time -from typing import Any, Callable, Dict, List, Optional +from typing import Callable, Dict, List, Optional, Union from enum import IntEnum import os # To get the username import gzip + class AuthState(IntEnum): NotAuthenticated = 1 AuthenticationRequested = 2 @@ -28,8 +30,8 @@ class AuthState(IntEnum): class NetworkedPrinterOutputDevice(PrinterOutputDevice): authenticationStateChanged = pyqtSignal() - def __init__(self, device_id, address: str, properties: Dict[bytes, bytes], parent: QObject = None) -> None: - super().__init__(device_id = device_id, parent = parent) + def __init__(self, device_id, address: str, properties: Dict[bytes, bytes], connection_type: ConnectionType = ConnectionType.NetworkConnection, parent: QObject = None) -> None: + super().__init__(device_id = device_id, connection_type = connection_type, parent = parent) self._manager = None # type: Optional[QNetworkAccessManager] self._last_manager_create_time = None # type: Optional[float] self._recreate_network_manager_time = 30 @@ -41,7 +43,8 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._api_prefix = "" self._address = address self._properties = properties - self._user_agent = "%s/%s " % (CuraApplication.getInstance().getApplicationName(), CuraApplication.getInstance().getVersion()) + self._user_agent = "%s/%s " % (CuraApplication.getInstance().getApplicationName(), + CuraApplication.getInstance().getVersion()) self._onFinishedCallbacks = {} # type: Dict[str, Callable[[QNetworkReply], None]] self._authentication_state = AuthState.NotAuthenticated @@ -55,7 +58,8 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._gcode = [] # type: List[str] self._connection_state_before_timeout = None # type: Optional[ConnectionState] - def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, file_handler: Optional[FileHandler] = None, **kwargs: str) -> None: + def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, + file_handler: Optional[FileHandler] = None, **kwargs: str) -> None: raise NotImplementedError("requestWrite needs to be implemented") def setAuthenticationState(self, authentication_state: AuthState) -> None: @@ -125,7 +129,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): if self._connection_state_before_timeout is None: self._connection_state_before_timeout = self._connection_state - self.setConnectionState(ConnectionState.closed) + self.setConnectionState(ConnectionState.Closed) # We need to check if the manager needs to be re-created. If we don't, we get some issues when OSX goes to # sleep. @@ -133,7 +137,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): if self._last_manager_create_time is None or time() - self._last_manager_create_time > self._recreate_network_manager_time: self._createNetworkManager() assert(self._manager is not None) - elif self._connection_state == ConnectionState.closed: + elif self._connection_state == ConnectionState.Closed: # Go out of timeout. if self._connection_state_before_timeout is not None: # sanity check, but it should never be None here self.setConnectionState(self._connection_state_before_timeout) @@ -143,10 +147,15 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): url = QUrl("http://" + self._address + self._api_prefix + target) request = QNetworkRequest(url) if content_type is not None: - request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") + request.setHeader(QNetworkRequest.ContentTypeHeader, content_type) request.setHeader(QNetworkRequest.UserAgentHeader, self._user_agent) return request + ## This method was only available privately before, but it was actually called from SendMaterialJob.py. + # We now have a public equivalent as well. We did not remove the private one as plugins might be using that. + def createFormPart(self, content_header: str, data: bytes, content_type: Optional[str] = None) -> QHttpPart: + return self._createFormPart(content_header, data, content_type) + def _createFormPart(self, content_header: str, data: bytes, content_type: Optional[str] = None) -> QHttpPart: part = QHttpPart() @@ -160,9 +169,15 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): part.setBody(data) return part - ## Convenience function to get the username from the OS. - # The code was copied from the getpass module, as we try to use as little dependencies as possible. + ## Convenience function to get the username, either from the cloud or from the OS. def _getUserName(self) -> str: + # check first if we are logged in with the Ultimaker Account + account = CuraApplication.getInstance().getCuraAPI().account # type: Account + if account and account.isLoggedIn: + return account.userName + + # Otherwise get the username from the US + # The code below was copied from the getpass module, as we try to use as little dependencies as possible. for name in ("LOGNAME", "USER", "LNAME", "USERNAME"): user = os.environ.get(name) if user: @@ -178,49 +193,89 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._createNetworkManager() assert (self._manager is not None) - def put(self, target: str, data: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None: + ## Sends a put request to the given path. + # \param url: The path after the API prefix. + # \param data: The data to be sent in the body + # \param content_type: The content type of the body data. + # \param on_finished: The function to call when the response is received. + # \param on_progress: The function to call when the progress changes. Parameters are bytes_sent / bytes_total. + def put(self, url: str, data: Union[str, bytes], content_type: Optional[str] = None, + on_finished: Optional[Callable[[QNetworkReply], None]] = None, + on_progress: Optional[Callable[[int, int], None]] = None) -> None: self._validateManager() - request = self._createEmptyRequest(target) - self._last_request_time = time() - if self._manager is not None: - reply = self._manager.put(request, data.encode()) - self._registerOnFinishedCallback(reply, on_finished) - else: - Logger.log("e", "Could not find manager.") - def delete(self, target: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None: + request = self._createEmptyRequest(url, content_type = content_type) + self._last_request_time = time() + + if not self._manager: + Logger.log("e", "No network manager was created to execute the PUT call with.") + return + + body = data if isinstance(data, bytes) else data.encode() # type: bytes + reply = self._manager.put(request, body) + self._registerOnFinishedCallback(reply, on_finished) + + if on_progress is not None: + reply.uploadProgress.connect(on_progress) + + ## Sends a delete request to the given path. + # \param url: The path after the API prefix. + # \param on_finished: The function to be call when the response is received. + def delete(self, url: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None: self._validateManager() - request = self._createEmptyRequest(target) - self._last_request_time = time() - if self._manager is not None: - reply = self._manager.deleteResource(request) - self._registerOnFinishedCallback(reply, on_finished) - else: - Logger.log("e", "Could not find manager.") - def get(self, target: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None: + request = self._createEmptyRequest(url) + self._last_request_time = time() + + if not self._manager: + Logger.log("e", "No network manager was created to execute the DELETE call with.") + return + + reply = self._manager.deleteResource(request) + self._registerOnFinishedCallback(reply, on_finished) + + ## Sends a get request to the given path. + # \param url: The path after the API prefix. + # \param on_finished: The function to be call when the response is received. + def get(self, url: str, on_finished: Optional[Callable[[QNetworkReply], None]]) -> None: self._validateManager() - request = self._createEmptyRequest(target) - self._last_request_time = time() - if self._manager is not None: - reply = self._manager.get(request) - self._registerOnFinishedCallback(reply, on_finished) - else: - Logger.log("e", "Could not find manager.") - def post(self, target: str, data: str, on_finished: Optional[Callable[[QNetworkReply], None]], on_progress: Callable = None) -> None: + request = self._createEmptyRequest(url) + self._last_request_time = time() + + if not self._manager: + Logger.log("e", "No network manager was created to execute the GET call with.") + return + + reply = self._manager.get(request) + self._registerOnFinishedCallback(reply, on_finished) + + ## Sends a post request to the given path. + # \param url: The path after the API prefix. + # \param data: The data to be sent in the body + # \param on_finished: The function to call when the response is received. + # \param on_progress: The function to call when the progress changes. Parameters are bytes_sent / bytes_total. + def post(self, url: str, data: Union[str, bytes], + on_finished: Optional[Callable[[QNetworkReply], None]], + on_progress: Optional[Callable[[int, int], None]] = None) -> None: self._validateManager() - request = self._createEmptyRequest(target) - self._last_request_time = time() - if self._manager is not None: - reply = self._manager.post(request, data.encode()) - if on_progress is not None: - reply.uploadProgress.connect(on_progress) - self._registerOnFinishedCallback(reply, on_finished) - else: - Logger.log("e", "Could not find manager.") - def postFormWithParts(self, target: str, parts: List[QHttpPart], on_finished: Optional[Callable[[QNetworkReply], None]], on_progress: Callable = None) -> QNetworkReply: + request = self._createEmptyRequest(url) + self._last_request_time = time() + + if not self._manager: + Logger.log("e", "Could not find manager.") + return + + body = data if isinstance(data, bytes) else data.encode() # type: bytes + reply = self._manager.post(request, body) + if on_progress is not None: + reply.uploadProgress.connect(on_progress) + self._registerOnFinishedCallback(reply, on_finished) + + def postFormWithParts(self, target: str, parts: List[QHttpPart], + on_finished: Optional[Callable[[QNetworkReply], None]], + on_progress: Optional[Callable[[int, int], None]] = None) -> QNetworkReply: self._validateManager() request = self._createEmptyRequest(target, content_type=None) multi_post_part = QHttpMultiPart(QHttpMultiPart.FormDataType) @@ -282,8 +337,8 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice): self._last_response_time = time() - if self._connection_state == ConnectionState.connecting: - self.setConnectionState(ConnectionState.connected) + if self._connection_state == ConnectionState.Connecting: + self.setConnectionState(ConnectionState.Connected) callback_key = reply.url().toString() + str(reply.operation()) try: diff --git a/cura/PrinterOutput/PrintJobOutputModel.py b/cura/PrinterOutput/PrintJobOutputModel.py index 25b168e6fd..a77ac81909 100644 --- a/cura/PrinterOutput/PrintJobOutputModel.py +++ b/cura/PrinterOutput/PrintJobOutputModel.py @@ -118,17 +118,40 @@ class PrintJobOutputModel(QObject): self.nameChanged.emit() @pyqtProperty(int, notify = timeTotalChanged) - def timeTotal(self): + def timeTotal(self) -> int: return self._time_total @pyqtProperty(int, notify = timeElapsedChanged) - def timeElapsed(self): + def timeElapsed(self) -> int: return self._time_elapsed + @pyqtProperty(int, notify = timeElapsedChanged) + def timeRemaining(self) -> int: + # Never get a negative time remaining + return max(self.timeTotal - self.timeElapsed, 0) + + @pyqtProperty(float, notify = timeElapsedChanged) + def progress(self) -> float: + time_elapsed = max(float(self.timeElapsed), 1.0) # Prevent a division by zero exception + result = time_elapsed / self.timeTotal + return min(result, 1.0) # Never get a progress past 1.0 + @pyqtProperty(str, notify=stateChanged) - def state(self): + def state(self) -> str: return self._state + @pyqtProperty(bool, notify=stateChanged) + def isActive(self) -> bool: + inactiveStates = [ + "pausing", + "paused", + "resuming", + "wait_cleanup" + ] + if self.state in inactiveStates and self.timeRemaining > 0: + return False + return True + def updateTimeTotal(self, new_time_total): if self._time_total != new_time_total: self._time_total = new_time_total diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 969aa3c460..dbdf8c986c 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -1,5 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from enum import IntEnum +from typing import Callable, List, Optional, Union from UM.Decorators import deprecated from UM.i18n import i18nCatalog @@ -12,9 +14,6 @@ from UM.Signal import signalemitter from UM.Qt.QtApplication import QtApplication from UM.FlameProfiler import pyqtSlot -from enum import IntEnum # For the connection state tracking. -from typing import Callable, List, Optional, Union - MYPY = False if MYPY: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel @@ -28,11 +27,18 @@ i18n_catalog = i18nCatalog("cura") ## The current processing state of the backend. class ConnectionState(IntEnum): - closed = 0 - connecting = 1 - connected = 2 - busy = 3 - error = 4 + Closed = 0 + Connecting = 1 + Connected = 2 + Busy = 3 + Error = 4 + + +class ConnectionType(IntEnum): + NotConnected = 0 + UsbConnection = 1 + NetworkConnection = 2 + CloudConnection = 3 ## Printer output device adds extra interface options on top of output device. @@ -46,6 +52,7 @@ class ConnectionState(IntEnum): # For all other uses it should be used in the same way as a "regular" OutputDevice. @signalemitter class PrinterOutputDevice(QObject, OutputDevice): + printersChanged = pyqtSignal() connectionStateChanged = pyqtSignal(str) acceptsCommandsChanged = pyqtSignal() @@ -62,33 +69,34 @@ class PrinterOutputDevice(QObject, OutputDevice): # Signal to indicate that the configuration of one of the printers has changed. uniqueConfigurationsChanged = pyqtSignal() - def __init__(self, device_id: str, parent: QObject = None) -> None: + def __init__(self, device_id: str, connection_type: "ConnectionType" = ConnectionType.NotConnected, parent: QObject = None) -> None: super().__init__(device_id = device_id, parent = parent) # type: ignore # MyPy complains with the multiple inheritance self._printers = [] # type: List[PrinterOutputModel] self._unique_configurations = [] # type: List[ConfigurationModel] - self._monitor_view_qml_path = "" #type: str - self._monitor_component = None #type: Optional[QObject] - self._monitor_item = None #type: Optional[QObject] + self._monitor_view_qml_path = "" # type: str + self._monitor_component = None # type: Optional[QObject] + self._monitor_item = None # type: Optional[QObject] - self._control_view_qml_path = "" #type: str - self._control_component = None #type: Optional[QObject] - self._control_item = None #type: Optional[QObject] + self._control_view_qml_path = "" # type: str + self._control_component = None # type: Optional[QObject] + self._control_item = None # type: Optional[QObject] - self._accepts_commands = False #type: bool + self._accepts_commands = False # type: bool - self._update_timer = QTimer() #type: QTimer + self._update_timer = QTimer() # type: QTimer self._update_timer.setInterval(2000) # TODO; Add preference for update interval self._update_timer.setSingleShot(False) self._update_timer.timeout.connect(self._update) - self._connection_state = ConnectionState.closed #type: ConnectionState + self._connection_state = ConnectionState.Closed # type: ConnectionState + self._connection_type = connection_type # type: ConnectionType - self._firmware_updater = None #type: Optional[FirmwareUpdater] - self._firmware_name = None #type: Optional[str] - self._address = "" #type: str - self._connection_text = "" #type: str + self._firmware_updater = None # type: Optional[FirmwareUpdater] + self._firmware_name = None # type: Optional[str] + self._address = "" # type: str + self._connection_text = "" # type: str self.printersChanged.connect(self._onPrintersChanged) QtApplication.getInstance().getOutputDeviceManager().outputDevicesChanged.connect(self._updateUniqueConfigurations) @@ -110,15 +118,19 @@ class PrinterOutputDevice(QObject, OutputDevice): callback(QMessageBox.Yes) def isConnected(self) -> bool: - return self._connection_state != ConnectionState.closed and self._connection_state != ConnectionState.error + return self._connection_state != ConnectionState.Closed and self._connection_state != ConnectionState.Error - def setConnectionState(self, connection_state: ConnectionState) -> None: + def setConnectionState(self, connection_state: "ConnectionState") -> None: if self._connection_state != connection_state: self._connection_state = connection_state self.connectionStateChanged.emit(self._id) - @pyqtProperty(str, notify = connectionStateChanged) - def connectionState(self) -> ConnectionState: + @pyqtProperty(int, constant = True) + def connectionType(self) -> "ConnectionType": + return self._connection_type + + @pyqtProperty(int, notify = connectionStateChanged) + def connectionState(self) -> "ConnectionState": return self._connection_state def _update(self) -> None: @@ -131,7 +143,8 @@ class PrinterOutputDevice(QObject, OutputDevice): return None - def requestWrite(self, nodes: List["SceneNode"], file_name: Optional[str] = None, limit_mimetypes: bool = False, file_handler: Optional["FileHandler"] = None, **kwargs: str) -> None: + def requestWrite(self, nodes: List["SceneNode"], file_name: Optional[str] = None, limit_mimetypes: bool = False, + file_handler: Optional["FileHandler"] = None, **kwargs: str) -> None: raise NotImplementedError("requestWrite needs to be implemented") @pyqtProperty(QObject, notify = printersChanged) @@ -174,13 +187,13 @@ class PrinterOutputDevice(QObject, OutputDevice): ## Attempt to establish connection def connect(self) -> None: - self.setConnectionState(ConnectionState.connecting) + self.setConnectionState(ConnectionState.Connecting) self._update_timer.start() ## Attempt to close the connection def close(self) -> None: self._update_timer.stop() - self.setConnectionState(ConnectionState.closed) + self.setConnectionState(ConnectionState.Closed) ## Ensure that close gets called when object is destroyed def __del__(self) -> None: @@ -207,10 +220,17 @@ class PrinterOutputDevice(QObject, OutputDevice): return self._unique_configurations def _updateUniqueConfigurations(self) -> None: - self._unique_configurations = list(set([printer.printerConfiguration for printer in self._printers if printer.printerConfiguration is not None])) - self._unique_configurations.sort(key = lambda k: k.printerType) + self._unique_configurations = sorted( + {printer.printerConfiguration for printer in self._printers if printer.printerConfiguration is not None}, + key=lambda config: config.printerType, + ) self.uniqueConfigurationsChanged.emit() + # Returns the unique configurations of the printers within this output device + @pyqtProperty("QStringList", notify = uniqueConfigurationsChanged) + def uniquePrinterTypes(self) -> List[str]: + return list(sorted(set([configuration.printerType for configuration in self._unique_configurations]))) + def _onPrintersChanged(self) -> None: for printer in self._printers: printer.configurationChanged.connect(self._updateUniqueConfigurations) @@ -238,4 +258,4 @@ class PrinterOutputDevice(QObject, OutputDevice): if not self._firmware_updater: return - self._firmware_updater.updateFirmware(firmware_file) \ No newline at end of file + self._firmware_updater.updateFirmware(firmware_file) diff --git a/cura/Scene/ConvexHullDecorator.py b/cura/Scene/ConvexHullDecorator.py index 39124c5ba3..9bdb6a2c0e 100644 --- a/cura/Scene/ConvexHullDecorator.py +++ b/cura/Scene/ConvexHullDecorator.py @@ -187,7 +187,10 @@ class ConvexHullDecorator(SceneNodeDecorator): for child in self._node.getChildren(): child_hull = child.callDecoration("_compute2DConvexHull") if child_hull: - points = numpy.append(points, child_hull.getPoints(), axis = 0) + try: + points = numpy.append(points, child_hull.getPoints(), axis = 0) + except ValueError: + pass if points.size < 3: return None @@ -239,7 +242,7 @@ class ConvexHullDecorator(SceneNodeDecorator): # See http://stackoverflow.com/questions/16970982/find-unique-rows-in-numpy-array vertex_byte_view = numpy.ascontiguousarray(vertex_data).view( numpy.dtype((numpy.void, vertex_data.dtype.itemsize * vertex_data.shape[1]))) - _, idx = numpy.unique(vertex_byte_view, return_index=True) + _, idx = numpy.unique(vertex_byte_view, return_index = True) vertex_data = vertex_data[idx] # Select the unique rows by index. hull = Polygon(vertex_data) @@ -272,7 +275,7 @@ class ConvexHullDecorator(SceneNodeDecorator): head_and_fans = self._getHeadAndFans().intersectionConvexHulls(mirrored) # Min head hull is used for the push free - convex_hull = self._compute2DConvexHeadFull() + convex_hull = self._compute2DConvexHull() if convex_hull: return convex_hull.getMinkowskiHull(head_and_fans) return None diff --git a/cura/Scene/ConvexHullNode.py b/cura/Scene/ConvexHullNode.py index 4c79c7d5dc..90bf536308 100644 --- a/cura/Scene/ConvexHullNode.py +++ b/cura/Scene/ConvexHullNode.py @@ -1,7 +1,10 @@ # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Optional from UM.Application import Application +from UM.Math.Polygon import Polygon +from UM.Qt.QtApplication import QtApplication from UM.Scene.SceneNode import SceneNode from UM.Resources import Resources from UM.Math.Color import Color @@ -16,7 +19,7 @@ class ConvexHullNode(SceneNode): # location an object uses on the buildplate. This area (or area's in case of one at a time printing) is # then displayed as a transparent shadow. If the adhesion type is set to raft, the area is extruded # to represent the raft as well. - def __init__(self, node, hull, thickness, parent = None): + def __init__(self, node: SceneNode, hull: Optional[Polygon], thickness: float, parent: Optional[SceneNode] = None) -> None: super().__init__(parent) self.setCalculateBoundingBox(False) @@ -25,7 +28,11 @@ class ConvexHullNode(SceneNode): # Color of the drawn convex hull if not Application.getInstance().getIsHeadLess(): - self._color = Color(*Application.getInstance().getTheme().getColor("convex_hull").getRgb()) + theme = QtApplication.getInstance().getTheme() + if theme: + self._color = Color(*theme.getColor("convex_hull").getRgb()) + else: + self._color = Color(0, 0, 0) else: self._color = Color(0, 0, 0) @@ -47,7 +54,7 @@ class ConvexHullNode(SceneNode): if hull_mesh_builder.addConvexPolygonExtrusion( self._hull.getPoints()[::-1], # bottom layer is reversed - self._mesh_height-thickness, self._mesh_height, color=self._color): + self._mesh_height - thickness, self._mesh_height, color = self._color): hull_mesh = hull_mesh_builder.build() self.setMeshData(hull_mesh) @@ -75,7 +82,7 @@ class ConvexHullNode(SceneNode): return True - def _onNodeDecoratorsChanged(self, node): + def _onNodeDecoratorsChanged(self, node: SceneNode) -> None: convex_hull_head = self._node.callDecoration("getConvexHullHead") if convex_hull_head: convex_hull_head_builder = MeshBuilder() diff --git a/cura/Settings/CuraFormulaFunctions.py b/cura/Settings/CuraFormulaFunctions.py index 1db01857f8..9ef80bd3d4 100644 --- a/cura/Settings/CuraFormulaFunctions.py +++ b/cura/Settings/CuraFormulaFunctions.py @@ -5,6 +5,7 @@ from typing import Any, List, Optional, TYPE_CHECKING from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext from UM.Settings.SettingFunction import SettingFunction +from UM.Logger import Logger if TYPE_CHECKING: from cura.CuraApplication import CuraApplication @@ -38,7 +39,11 @@ class CuraFormulaFunctions: extruder_position = int(machine_manager.defaultExtruderPosition) global_stack = machine_manager.activeMachine - extruder_stack = global_stack.extruders[str(extruder_position)] + try: + extruder_stack = global_stack.extruders[str(extruder_position)] + except KeyError: + Logger.log("w", "Value for %s of extruder %s was requested, but that extruder is not available" % (property_key, extruder_position)) + return None value = extruder_stack.getRawProperty(property_key, "value", context = context) if isinstance(value, SettingFunction): diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 9089ba96e9..a459d65ba3 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -63,7 +63,7 @@ class ExtruderManager(QObject): if not self._application.getGlobalContainerStack(): return None # No active machine, so no active extruder. try: - return self._extruder_trains[self._application.getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId() + return self._extruder_trains[self._application.getGlobalContainerStack().getId()][str(self.activeExtruderIndex)].getId() except KeyError: # Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong. return None @@ -83,8 +83,9 @@ class ExtruderManager(QObject): # \param index The index of the new active extruder. @pyqtSlot(int) def setActiveExtruderIndex(self, index: int) -> None: - self._active_extruder_index = index - self.activeExtruderChanged.emit() + if self._active_extruder_index != index: + self._active_extruder_index = index + self.activeExtruderChanged.emit() @pyqtProperty(int, notify = activeExtruderChanged) def activeExtruderIndex(self) -> int: @@ -144,7 +145,7 @@ class ExtruderManager(QObject): @pyqtSlot(result = QObject) def getActiveExtruderStack(self) -> Optional["ExtruderStack"]: - return self.getExtruderStack(self._active_extruder_index) + return self.getExtruderStack(self.activeExtruderIndex) ## Get an extruder stack by index def getExtruderStack(self, index) -> Optional["ExtruderStack"]: @@ -300,12 +301,7 @@ class ExtruderManager(QObject): global_stack = self._application.getGlobalContainerStack() if not global_stack: return [] - - result_tuple_list = sorted(list(global_stack.extruders.items()), key = lambda x: int(x[0])) - result_list = [item[1] for item in result_tuple_list] - - machine_extruder_count = global_stack.getProperty("machine_extruder_count", "value") - return result_list[:machine_extruder_count] + return global_stack.extruderList def _globalContainerStackChanged(self) -> None: # If the global container changed, the machine changed and might have extruders that were not registered yet @@ -344,6 +340,7 @@ class ExtruderManager(QObject): if extruders_changed: self.extrudersChanged.emit(global_stack_id) self.setActiveExtruderIndex(0) + self.activeExtruderChanged.emit() # After 3.4, all single-extrusion machines have their own extruder definition files instead of reusing # "fdmextruder". We need to check a machine here so its extruder definition is correct according to this. diff --git a/cura/Settings/ExtruderStack.py b/cura/Settings/ExtruderStack.py index d7faedb71c..edb0e7d41f 100644 --- a/cura/Settings/ExtruderStack.py +++ b/cura/Settings/ExtruderStack.py @@ -52,8 +52,8 @@ class ExtruderStack(CuraContainerStack): return super().getNextStack() def setEnabled(self, enabled: bool) -> None: - if "enabled" not in self._metadata: - self.setMetaDataEntry("enabled", "True") + if self.getMetaDataEntry("enabled", True) == enabled: # No change. + return # Don't emit a signal then. self.setMetaDataEntry("enabled", str(enabled)) self.enabledChanged.emit() diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 52fc502bfc..076cebf60d 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -1,7 +1,7 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, pyqtProperty, QTimer +from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer from typing import Iterable from UM.i18n import i18nCatalog @@ -24,8 +24,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): ## Human-readable name of the extruder. NameRole = Qt.UserRole + 2 - ## Is the extruder enabled? - EnabledRole = Qt.UserRole + 9 ## Colour of the material loaded in the extruder. ColorRole = Qt.UserRole + 3 @@ -47,6 +45,12 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): VariantRole = Qt.UserRole + 7 StackRole = Qt.UserRole + 8 + MaterialBrandRole = Qt.UserRole + 9 + ColorNameRole = Qt.UserRole + 10 + + ## Is the extruder enabled? + EnabledRole = Qt.UserRole + 11 + ## List of colours to display if there is no material or the material has no known # colour. defaultColors = ["#ffc924", "#86ec21", "#22eeee", "#245bff", "#9124ff", "#ff24c8"] @@ -67,14 +71,13 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): self.addRoleName(self.MaterialRole, "material") self.addRoleName(self.VariantRole, "variant") self.addRoleName(self.StackRole, "stack") - + self.addRoleName(self.MaterialBrandRole, "material_brand") + self.addRoleName(self.ColorNameRole, "color_name") self._update_extruder_timer = QTimer() self._update_extruder_timer.setInterval(100) self._update_extruder_timer.setSingleShot(True) self._update_extruder_timer.timeout.connect(self.__updateExtruders) - self._simple_names = False - self._active_machine_extruders = [] # type: Iterable[ExtruderStack] self._add_optional_extruder = False @@ -96,21 +99,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def addOptionalExtruder(self): return self._add_optional_extruder - ## Set the simpleNames property. - def setSimpleNames(self, simple_names): - if simple_names != self._simple_names: - self._simple_names = simple_names - self.simpleNamesChanged.emit() - self._updateExtruders() - - ## Emitted when the simpleNames property changes. - simpleNamesChanged = pyqtSignal() - - ## Whether or not the model should show all definitions regardless of visibility. - @pyqtProperty(bool, fset = setSimpleNames, notify = simpleNamesChanged) - def simpleNames(self): - return self._simple_names - ## Links to the stack-changed signal of the new extruders when an extruder # is swapped out or added in the current machine. # @@ -160,7 +148,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): def __updateExtruders(self): extruders_changed = False - if self.rowCount() != 0: + if self.count != 0: extruders_changed = True items = [] @@ -172,7 +160,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): machine_extruder_count = global_container_stack.getProperty("machine_extruder_count", "value") for extruder in Application.getInstance().getExtruderManager().getActiveExtruderStacks(): - position = extruder.getMetaDataEntry("position", default = "0") # Get the position + position = extruder.getMetaDataEntry("position", default = "0") try: position = int(position) except ValueError: @@ -183,7 +171,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): default_color = self.defaultColors[position] if 0 <= position < len(self.defaultColors) else self.defaultColors[0] color = extruder.material.getMetaDataEntry("color_code", default = default_color) if extruder.material else default_color - + material_brand = extruder.material.getMetaDataEntry("brand", default = "generic") + color_name = extruder.material.getMetaDataEntry("color_name") # construct an item with only the relevant information item = { "id": extruder.getId(), @@ -195,6 +184,8 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "material": extruder.material.getName() if extruder.material else "", "variant": extruder.variant.getName() if extruder.variant else "", # e.g. print core "stack": extruder, + "material_brand": material_brand, + "color_name": color_name } items.append(item) @@ -213,9 +204,14 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): "enabled": True, "color": "#ffffff", "index": -1, - "definition": "" + "definition": "", + "material": "", + "variant": "", + "stack": None, + "material_brand": "", + "color_name": "", } items.append(item) - - self.setItems(items) - self.modelChanged.emit() + if self._items != items: + self.setItems(items) + self.modelChanged.emit() diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index da1ec61254..8dba0f5204 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -3,8 +3,8 @@ from collections import defaultdict import threading -from typing import Any, Dict, Optional, Set, TYPE_CHECKING -from PyQt5.QtCore import pyqtProperty, pyqtSlot +from typing import Any, Dict, Optional, Set, TYPE_CHECKING, List +from PyQt5.QtCore import pyqtProperty, pyqtSlot, pyqtSignal from UM.Decorators import override from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase @@ -42,13 +42,23 @@ class GlobalStack(CuraContainerStack): # Per thread we have our own resolving_settings, or strange things sometimes occur. self._resolving_settings = defaultdict(set) #type: Dict[str, Set[str]] # keys are thread names + extrudersChanged = pyqtSignal() + ## Get the list of extruders of this stack. # # \return The extruders registered with this stack. - @pyqtProperty("QVariantMap") + @pyqtProperty("QVariantMap", notify = extrudersChanged) def extruders(self) -> Dict[str, "ExtruderStack"]: return self._extruders + @pyqtProperty("QVariantList", notify = extrudersChanged) + def extruderList(self) -> List["ExtruderStack"]: + result_tuple_list = sorted(list(self.extruders.items()), key=lambda x: int(x[0])) + result_list = [item[1] for item in result_tuple_list] + + machine_extruder_count = self.getProperty("machine_extruder_count", "value") + return result_list[:machine_extruder_count] + @classmethod def getLoadingPriority(cls) -> int: return 2 @@ -87,6 +97,7 @@ class GlobalStack(CuraContainerStack): return self._extruders[position] = extruder + self.extrudersChanged.emit() Logger.log("i", "Extruder[%s] added to [%s] at position [%s]", extruder.id, self.id, position) ## Overridden from ContainerStack diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index f321ce94a6..5763d2bcab 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -3,6 +3,8 @@ import collections import time +import re +import unicodedata from typing import Any, Callable, List, Dict, TYPE_CHECKING, Optional, cast from UM.ConfigurationErrorMessage import ConfigurationErrorMessage @@ -21,7 +23,7 @@ from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch -from cura.PrinterOutputDevice import PrinterOutputDevice +from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionType from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel @@ -62,9 +64,7 @@ class MachineManager(QObject): self._default_extruder_position = "0" # to be updated when extruders are switched on and off - self.machine_extruder_material_update_dict = collections.defaultdict(list) #type: Dict[str, List[Callable[[], None]]] - - self._instance_container_timer = QTimer() #type: QTimer + self._instance_container_timer = QTimer() # type: QTimer self._instance_container_timer.setInterval(250) self._instance_container_timer.setSingleShot(True) self._instance_container_timer.timeout.connect(self.__emitChangedSignals) @@ -74,7 +74,7 @@ class MachineManager(QObject): self._application.globalContainerStackChanged.connect(self._onGlobalContainerChanged) self._container_registry.containerLoadComplete.connect(self._onContainersChanged) - ## When the global container is changed, active material probably needs to be updated. + # When the global container is changed, active material probably needs to be updated. self.globalContainerChanged.connect(self.activeMaterialChanged) self.globalContainerChanged.connect(self.activeVariantChanged) self.globalContainerChanged.connect(self.activeQualityChanged) @@ -86,12 +86,14 @@ class MachineManager(QObject): self._onGlobalContainerChanged() - ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged) + extruder_manager = self._application.getExtruderManager() + + extruder_manager.activeExtruderChanged.connect(self._onActiveExtruderStackChanged) self._onActiveExtruderStackChanged() - ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeMaterialChanged) - ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeVariantChanged) - ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeQualityChanged) + extruder_manager.activeExtruderChanged.connect(self.activeMaterialChanged) + extruder_manager.activeExtruderChanged.connect(self.activeVariantChanged) + extruder_manager.activeExtruderChanged.connect(self.activeQualityChanged) self.globalContainerChanged.connect(self.activeStackChanged) self.globalValueChanged.connect(self.activeStackValueChanged) @@ -115,15 +117,15 @@ class MachineManager(QObject): self._material_incompatible_message = Message(catalog.i18nc("@info:status", "The selected material is incompatible with the selected machine or configuration."), - title = catalog.i18nc("@info:title", "Incompatible Material")) #type: Message + title = catalog.i18nc("@info:title", "Incompatible Material")) # type: Message - containers = CuraContainerRegistry.getInstance().findInstanceContainers(id = self.activeMaterialId) #type: List[InstanceContainer] + containers = CuraContainerRegistry.getInstance().findInstanceContainers(id = self.activeMaterialId) # type: List[InstanceContainer] if containers: containers[0].nameChanged.connect(self._onMaterialNameChanged) - self._material_manager = self._application.getMaterialManager() #type: MaterialManager - self._variant_manager = self._application.getVariantManager() #type: VariantManager - self._quality_manager = self._application.getQualityManager() #type: QualityManager + self._material_manager = self._application.getMaterialManager() # type: MaterialManager + self._variant_manager = self._application.getVariantManager() # type: VariantManager + self._quality_manager = self._application.getQualityManager() # type: QualityManager # When the materials lookup table gets updated, it can mean that a material has its name changed, which should # be reflected on the GUI. This signal emission makes sure that it happens. @@ -156,7 +158,7 @@ class MachineManager(QObject): blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly outputDevicesChanged = pyqtSignal() - currentConfigurationChanged = pyqtSignal() # Emitted every time the current configurations of the machine changes + currentConfigurationChanged = pyqtSignal() # Emitted every time the current configurations of the machine changes printerConnectedStatusChanged = pyqtSignal() # Emitted every time the active machine change or the outputdevices change rootMaterialChanged = pyqtSignal() @@ -174,6 +176,7 @@ class MachineManager(QObject): self._printer_output_devices.append(printer_output_device) self.outputDevicesChanged.emit() + self.printerConnectedStatusChanged.emit() @pyqtProperty(QObject, notify = currentConfigurationChanged) def currentConfiguration(self) -> ConfigurationModel: @@ -201,7 +204,7 @@ class MachineManager(QObject): extruder_configuration.hotendID = extruder.variant.getName() if extruder.variant != empty_variant_container else None self._current_printer_configuration.extruderConfigurations.append(extruder_configuration) - # an empty build plate configuration from the network printer is presented as an empty string, so use "" for an + # An empty build plate configuration from the network printer is presented as an empty string, so use "" for an # empty build plate. self._current_printer_configuration.buildplateConfiguration = self._global_container_stack.getProperty("machine_buildplate_type", "value") if self._global_container_stack.variant != empty_variant_container else "" self.currentConfigurationChanged.emit() @@ -247,7 +250,7 @@ class MachineManager(QObject): self.updateNumberExtrudersEnabled() self.globalContainerChanged.emit() - # after switching the global stack we reconnect all the signals and set the variant and material references + # After switching the global stack we reconnect all the signals and set the variant and material references if self._global_container_stack: self._application.getPreferences().setValue("cura/active_machine", self._global_container_stack.getId()) @@ -261,7 +264,7 @@ class MachineManager(QObject): if global_variant.getMetaDataEntry("hardware_type") != "buildplate": self._global_container_stack.setVariant(empty_variant_container) - # set the global material to empty as we now use the extruder stack at all times - CURA-4482 + # Set the global material to empty as we now use the extruder stack at all times - CURA-4482 global_material = self._global_container_stack.material if global_material != empty_material_container: self._global_container_stack.setMaterial(empty_material_container) @@ -271,11 +274,6 @@ class MachineManager(QObject): extruder_stack.propertyChanged.connect(self._onPropertyChanged) extruder_stack.containersChanged.connect(self._onContainersChanged) - if self._global_container_stack.getId() in self.machine_extruder_material_update_dict: - for func in self.machine_extruder_material_update_dict[self._global_container_stack.getId()]: - self._application.callLater(func) - del self.machine_extruder_material_update_dict[self._global_container_stack.getId()] - self.activeQualityGroupChanged.emit() def _onActiveExtruderStackChanged(self) -> None: @@ -295,6 +293,7 @@ class MachineManager(QObject): self.activeMaterialChanged.emit() self.rootMaterialChanged.emit() + self.numberExtrudersEnabledChanged.emit() def _onContainersChanged(self, container: ContainerInterface) -> None: self._instance_container_timer.start() @@ -419,7 +418,7 @@ class MachineManager(QObject): # Not a very pretty solution, but the extruder manager doesn't really know how many extruders there are machine_extruder_count = self._global_container_stack.getProperty("machine_extruder_count", "value") extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks() - count = 1 # we start with the global stack + count = 1 # We start with the global stack for stack in extruder_stacks: md = stack.getMetaData() if "position" in md and int(md["position"]) >= machine_extruder_count: @@ -438,12 +437,12 @@ class MachineManager(QObject): if not self._global_container_stack: return False - if self._global_container_stack.getTop().findInstances(): + if self._global_container_stack.getTop().getNumInstances() != 0: return True stacks = ExtruderManager.getInstance().getActiveExtruderStacks() for stack in stacks: - if stack.getTop().findInstances(): + if stack.getTop().getNumInstances() != 0: return True return False @@ -453,10 +452,10 @@ class MachineManager(QObject): if not self._global_container_stack: return 0 num_user_settings = 0 - num_user_settings += len(self._global_container_stack.getTop().findInstances()) - stacks = ExtruderManager.getInstance().getActiveExtruderStacks() + num_user_settings += self._global_container_stack.getTop().getNumInstances() + stacks = self._global_container_stack.extruderList for stack in stacks: - num_user_settings += len(stack.getTop().findInstances()) + num_user_settings += stack.getTop().getNumInstances() return num_user_settings ## Delete a user setting from the global stack and all extruder stacks. @@ -516,10 +515,30 @@ class MachineManager(QObject): return "" @pyqtProperty(bool, notify = printerConnectedStatusChanged) - def printerConnected(self): + def printerConnected(self) -> bool: return bool(self._printer_output_devices) - @pyqtProperty(str, notify = printerConnectedStatusChanged) + @pyqtProperty(bool, notify = printerConnectedStatusChanged) + def activeMachineHasRemoteConnection(self) -> bool: + if self._global_container_stack: + connection_type = int(self._global_container_stack.getMetaDataEntry("connection_type", ConnectionType.NotConnected.value)) + return connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value] + return False + + @pyqtProperty(bool, notify = printerConnectedStatusChanged) + def activeMachineIsGroup(self) -> bool: + return bool(self._printer_output_devices) and len(self._printer_output_devices[0].printers) > 1 + + @pyqtProperty(bool, notify = printerConnectedStatusChanged) + def activeMachineHasActiveNetworkConnection(self) -> bool: + # A network connection is only available if any output device is actually a network connected device. + return any(d.connectionType == ConnectionType.NetworkConnection for d in self._printer_output_devices) + + @pyqtProperty(bool, notify = printerConnectedStatusChanged) + def activeMachineHasActiveCloudConnection(self) -> bool: + # A cloud connection is only available if any output device actually is a cloud connected device. + return any(d.connectionType == ConnectionType.CloudConnection for d in self._printer_output_devices) + def activeMachineNetworkKey(self) -> str: if self._global_container_stack: return self._global_container_stack.getMetaDataEntry("um_network_key", "") @@ -616,6 +635,14 @@ class MachineManager(QObject): is_supported = self._current_quality_group.is_available return is_supported + @pyqtProperty(bool, notify = activeQualityGroupChanged) + def isActiveQualityExperimental(self) -> bool: + is_experimental = False + if self._global_container_stack: + if self._current_quality_group: + is_experimental = self._current_quality_group.is_experimental + return is_experimental + ## Returns whether there is anything unsupported in the current set-up. # # The current set-up signifies the global stack and all extruder stacks, @@ -646,7 +673,7 @@ class MachineManager(QObject): new_value = self._active_container_stack.getProperty(key, "value") extruder_stacks = [stack for stack in ExtruderManager.getInstance().getActiveExtruderStacks()] - # check in which stack the value has to be replaced + # Check in which stack the value has to be replaced for extruder_stack in extruder_stacks: if extruder_stack != self._active_container_stack and extruder_stack.getProperty(key, "value") != new_value: extruder_stack.userChanges.setProperty(key, "value", new_value) # TODO: nested property access, should be improved @@ -662,7 +689,7 @@ class MachineManager(QObject): for key in self._active_container_stack.userChanges.getAllKeys(): new_value = self._active_container_stack.getProperty(key, "value") - # check if the value has to be replaced + # Check if the value has to be replaced extruder_stack.userChanges.setProperty(key, "value", new_value) @pyqtProperty(str, notify = activeVariantChanged) @@ -731,7 +758,7 @@ class MachineManager(QObject): # If the machine that is being removed is the currently active machine, set another machine as the active machine. activate_new_machine = (self._global_container_stack and self._global_container_stack.getId() == machine_id) - # activate a new machine before removing a machine because this is safer + # Activate a new machine before removing a machine because this is safer if activate_new_machine: machine_stacks = CuraContainerRegistry.getInstance().findContainerStacksMetadata(type = "machine") other_machine_stacks = [s for s in machine_stacks if s["id"] != machine_id] @@ -739,7 +766,7 @@ class MachineManager(QObject): self.setActiveMachine(other_machine_stacks[0]["id"]) metadata = CuraContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id)[0] - network_key = metadata["um_network_key"] if "um_network_key" in metadata else None + network_key = metadata.get("um_network_key", None) ExtruderManager.getInstance().removeMachineExtruders(machine_id) containers = CuraContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id) for container in containers: @@ -864,7 +891,7 @@ class MachineManager(QObject): caution_message = Message(catalog.i18nc( "@info:generic", "Settings have been changed to match the current availability of extruders: [%s]" % ", ".join(add_user_changes)), - lifetime=0, + lifetime = 0, title = catalog.i18nc("@info:title", "Settings updated")) caution_message.show() @@ -909,21 +936,18 @@ class MachineManager(QObject): # After CURA-4482 this should not be the case anymore, but we still want to support older project files. global_user_container = self._global_container_stack.userChanges - # Make sure extruder_stacks exists - extruder_stacks = [] #type: List[ExtruderStack] - - if previous_extruder_count == 1: - extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks() - global_user_container = self._global_container_stack.userChanges - for setting_instance in global_user_container.findInstances(): setting_key = setting_instance.definition.key settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder") if settable_per_extruder: limit_to_extruder = int(self._global_container_stack.getProperty(setting_key, "limit_to_extruder")) - extruder_stack = extruder_stacks[max(0, limit_to_extruder)] - extruder_stack.userChanges.setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value")) + extruder_position = max(0, limit_to_extruder) + extruder_stack = self.getExtruder(extruder_position) + if extruder_stack: + extruder_stack.userChanges.setProperty(setting_key, "value", global_user_container.getProperty(setting_key, "value")) + else: + Logger.log("e", "Unable to find extruder on position %s", extruder_position) global_user_container.removeInstance(setting_key) # Signal that the global stack has changed @@ -932,10 +956,9 @@ class MachineManager(QObject): @pyqtSlot(int, result = QObject) def getExtruder(self, position: int) -> Optional[ExtruderStack]: - extruder = None if self._global_container_stack: - extruder = self._global_container_stack.extruders.get(str(position)) - return extruder + return self._global_container_stack.extruders.get(str(position)) + return None def updateDefaultExtruder(self) -> None: if self._global_container_stack is None: @@ -1001,12 +1024,12 @@ class MachineManager(QObject): if not enabled and position == ExtruderManager.getInstance().activeExtruderIndex: ExtruderManager.getInstance().setActiveExtruderIndex(int(self._default_extruder_position)) - # ensure that the quality profile is compatible with current combination, or choose a compatible one if available + # Ensure that the quality profile is compatible with current combination, or choose a compatible one if available self._updateQualityWithMaterial() self.extruderChanged.emit() - # update material compatibility color + # Update material compatibility color self.activeQualityGroupChanged.emit() - # update items in SettingExtruder + # Update items in SettingExtruder ExtruderManager.getInstance().extrudersChanged.emit(self._global_container_stack.getId()) # Make sure the front end reflects changes self.forceUpdateAllSettings() @@ -1080,7 +1103,6 @@ class MachineManager(QObject): return result - # # Sets all quality and quality_changes containers to empty_quality and empty_quality_changes containers # for all stacks in the currently active machine. # @@ -1139,7 +1161,7 @@ class MachineManager(QObject): def _setQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup") -> None: if self._global_container_stack is None: - return #Can't change that. + return # Can't change that. quality_type = quality_changes_group.quality_type # A custom quality can be created based on "not supported". # In that case, do not set quality containers to empty. @@ -1209,7 +1231,7 @@ class MachineManager(QObject): self.rootMaterialChanged.emit() def activeMaterialsCompatible(self) -> bool: - # check material - variant compatibility + # Check material - variant compatibility if self._global_container_stack is not None: if Util.parseBool(self._global_container_stack.getMetaDataEntry("has_materials", False)): for position, extruder in self._global_container_stack.extruders.items(): @@ -1310,17 +1332,18 @@ class MachineManager(QObject): # Get the definition id corresponding to this machine name machine_definition_id = CuraContainerRegistry.getInstance().findDefinitionContainers(name = machine_name)[0].getId() # Try to find a machine with the same network key - new_machine = self.getMachine(machine_definition_id, metadata_filter = {"um_network_key": self.activeMachineNetworkKey}) + new_machine = self.getMachine(machine_definition_id, metadata_filter = {"um_network_key": self.activeMachineNetworkKey()}) # If there is no machine, then create a new one and set it to the non-hidden instance if not new_machine: new_machine = CuraStackBuilder.createMachine(machine_definition_id + "_sync", machine_definition_id) if not new_machine: return - new_machine.setMetaDataEntry("um_network_key", self.activeMachineNetworkKey) + new_machine.setMetaDataEntry("um_network_key", self.activeMachineNetworkKey()) new_machine.setMetaDataEntry("connect_group_name", self.activeMachineNetworkGroupName) new_machine.setMetaDataEntry("hidden", False) + new_machine.setMetaDataEntry("connection_type", self._global_container_stack.getMetaDataEntry("connection_type")) else: - Logger.log("i", "Found a %s with the key %s. Let's use it!", machine_name, self.activeMachineNetworkKey) + Logger.log("i", "Found a %s with the key %s. Let's use it!", machine_name, self.activeMachineNetworkKey()) new_machine.setMetaDataEntry("hidden", False) # Set the current printer instance to hidden (the metadata entry must exist) @@ -1380,10 +1403,10 @@ class MachineManager(QObject): # After updating from 3.2 to 3.3 some group names may be temporary. If there is a mismatch in the name of the group # then all the container stacks are updated, both the current and the hidden ones. def checkCorrectGroupName(self, device_id: str, group_name: str) -> None: - if self._global_container_stack and device_id == self.activeMachineNetworkKey: + if self._global_container_stack and device_id == self.activeMachineNetworkKey(): # Check if the connect_group_name is correct. If not, update all the containers connected to the same printer if self.activeMachineNetworkGroupName != group_name: - metadata_filter = {"um_network_key": self.activeMachineNetworkKey} + metadata_filter = {"um_network_key": self.activeMachineNetworkKey()} containers = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter) for container in containers: container.setMetaDataEntry("connect_group_name", group_name) @@ -1419,7 +1442,7 @@ class MachineManager(QObject): material_diameter, root_material_id) self.setMaterial(position, material_node) - ## global_stack: if you want to provide your own global_stack instead of the current active one + ## Global_stack: if you want to provide your own global_stack instead of the current active one # if you update an active machine, special measures have to be taken. @pyqtSlot(str, "QVariant") def setMaterial(self, position: str, container_node, global_stack: Optional["GlobalStack"] = None) -> None: @@ -1522,6 +1545,10 @@ class MachineManager(QObject): def activeQualityChangesGroup(self) -> Optional["QualityChangesGroup"]: return self._current_quality_changes_group + @pyqtProperty(bool, notify = activeQualityChangesGroupChanged) + def hasCustomQuality(self) -> bool: + return self._current_quality_changes_group is not None + @pyqtProperty(str, notify = activeQualityGroupChanged) def activeQualityOrQualityChangesName(self) -> str: name = empty_quality_container.getName() @@ -1531,9 +1558,32 @@ class MachineManager(QObject): name = self._current_quality_group.name return name + @pyqtProperty(bool, notify = activeQualityGroupChanged) + def hasNotSupportedQuality(self) -> bool: + return self._current_quality_group is None and self._current_quality_changes_group is None + def _updateUponMaterialMetadataChange(self) -> None: if self._global_container_stack is None: return with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self.updateMaterialWithVariant(None) self._updateQualityWithMaterial() + + ## This function will translate any printer type name to an abbreviated printer type name + @pyqtSlot(str, result = str) + def getAbbreviatedMachineName(self, machine_type_name: str) -> str: + abbr_machine = "" + for word in re.findall(r"[\w']+", machine_type_name): + if word.lower() == "ultimaker": + abbr_machine += "UM" + elif word.isdigit(): + abbr_machine += word + else: + stripped_word = "".join(char for char in unicodedata.normalize("NFD", word.upper()) if unicodedata.category(char) != "Mn") + # - use only the first character if the word is too long (> 3 characters) + # - use the whole word if it's not too long (<= 3 characters) + if len(stripped_word) > 3: + stripped_word = stripped_word[0] + abbr_machine += stripped_word + + return abbr_machine diff --git a/cura/Settings/SimpleModeSettingsManager.py b/cura/Settings/SimpleModeSettingsManager.py index fce43243bd..b1896a9205 100644 --- a/cura/Settings/SimpleModeSettingsManager.py +++ b/cura/Settings/SimpleModeSettingsManager.py @@ -1,7 +1,8 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Set -from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty +from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot from UM.Application import Application @@ -16,15 +17,11 @@ class SimpleModeSettingsManager(QObject): self._is_profile_user_created = False # True when profile was custom created by user self._machine_manager.activeStackValueChanged.connect(self._updateIsProfileCustomized) - self._machine_manager.activeQualityGroupChanged.connect(self._updateIsProfileUserCreated) - self._machine_manager.activeQualityChangesGroupChanged.connect(self._updateIsProfileUserCreated) # update on create as the activeQualityChanged signal is emitted before this manager is created when Cura starts self._updateIsProfileCustomized() - self._updateIsProfileUserCreated() isProfileCustomizedChanged = pyqtSignal() - isProfileUserCreatedChanged = pyqtSignal() @pyqtProperty(bool, notify = isProfileCustomizedChanged) def isProfileCustomized(self): @@ -57,33 +54,6 @@ class SimpleModeSettingsManager(QObject): self._is_profile_customized = has_customized_user_settings self.isProfileCustomizedChanged.emit() - @pyqtProperty(bool, notify = isProfileUserCreatedChanged) - def isProfileUserCreated(self): - return self._is_profile_user_created - - def _updateIsProfileUserCreated(self): - quality_changes_keys = set() - - if not self._machine_manager.activeMachine: - return False - - global_stack = self._machine_manager.activeMachine - - # check quality changes settings in the global stack - quality_changes_keys.update(global_stack.qualityChanges.getAllKeys()) - - # check quality changes settings in the extruder stacks - if global_stack.extruders: - for extruder_stack in global_stack.extruders.values(): - quality_changes_keys.update(extruder_stack.qualityChanges.getAllKeys()) - - # check if the qualityChanges container is not empty (meaning it is a user created profile) - has_quality_changes = len(quality_changes_keys) > 0 - - if has_quality_changes != self._is_profile_user_created: - self._is_profile_user_created = has_quality_changes - self.isProfileUserCreatedChanged.emit() - # These are the settings included in the Simple ("Recommended") Mode, so only when the other settings have been # changed, we consider it as a user customized profile in the Simple ("Recommended") Mode. __ignored_custom_setting_keys = ["support_enable", diff --git a/cura/Stages/CuraStage.py b/cura/Stages/CuraStage.py index b2f6d61799..844b0d0768 100644 --- a/cura/Stages/CuraStage.py +++ b/cura/Stages/CuraStage.py @@ -1,23 +1,29 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. + from PyQt5.QtCore import pyqtProperty, QUrl from UM.Stage import Stage +# Since Cura has a few pre-defined "space claims" for the locations of certain components, we've provided some structure +# to indicate this. +# * The StageMenuComponent is the horizontal area below the stage bar. This should be used to show stage specific +# buttons and elements. This component will be drawn over the bar & main component. +# * The MainComponent is the component that will be drawn starting from the bottom of the stageBar and fills the rest +# of the screen. class CuraStage(Stage): - - def __init__(self, parent = None): + def __init__(self, parent = None) -> None: super().__init__(parent) @pyqtProperty(str, constant = True) - def stageId(self): + def stageId(self) -> str: return self.getPluginId() @pyqtProperty(QUrl, constant = True) - def mainComponent(self): + def mainComponent(self) -> QUrl: return self.getDisplayComponent("main") @pyqtProperty(QUrl, constant = True) - def sidebarComponent(self): - return self.getDisplayComponent("sidebar") + def stageMenuComponent(self) -> QUrl: + return self.getDisplayComponent("menu") \ No newline at end of file diff --git a/cura/UltimakerCloudAuthentication.py b/cura/UltimakerCloudAuthentication.py new file mode 100644 index 0000000000..69bb577354 --- /dev/null +++ b/cura/UltimakerCloudAuthentication.py @@ -0,0 +1,28 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +# --------- +# Constants used for the Cloud API +# --------- +DEFAULT_CLOUD_API_ROOT = "https://api.ultimaker.com" # type: str +DEFAULT_CLOUD_API_VERSION = "1" # type: str +DEFAULT_CLOUD_ACCOUNT_API_ROOT = "https://account.ultimaker.com" # type: str + +try: + from cura.CuraVersion import CuraCloudAPIRoot # type: ignore + if CuraCloudAPIRoot == "": + CuraCloudAPIRoot = DEFAULT_CLOUD_API_ROOT +except ImportError: + CuraCloudAPIRoot = DEFAULT_CLOUD_API_ROOT + +try: + from cura.CuraVersion import CuraCloudAPIVersion # type: ignore +except ImportError: + CuraCloudAPIVersion = DEFAULT_CLOUD_API_VERSION + +try: + from cura.CuraVersion import CuraCloudAccountAPIRoot # type: ignore + if CuraCloudAccountAPIRoot == "": + CuraCloudAccountAPIRoot = DEFAULT_CLOUD_ACCOUNT_API_ROOT +except ImportError: + CuraCloudAccountAPIRoot = DEFAULT_CLOUD_ACCOUNT_API_ROOT diff --git a/cura_app.py b/cura_app.py index 164e32e738..8df12d771a 100755 --- a/cura_app.py +++ b/cura_app.py @@ -17,12 +17,6 @@ parser.add_argument("--debug", default = False, help = "Turn on the debug mode by setting this option." ) -parser.add_argument("--trigger-early-crash", - dest = "trigger_early_crash", - action = "store_true", - default = False, - help = "FOR TESTING ONLY. Trigger an early crash to show the crash dialog." - ) known_args = vars(parser.parse_known_args()[0]) if not known_args["debug"]: diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 9ee2ef0dd4..55296979b5 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -794,7 +794,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): # Clear all existing containers quality_changes_info.global_info.container.clear() for container_info in quality_changes_info.extruder_info_dict.values(): - container_info.container.clear() + if container_info.container: + container_info.container.clear() # Loop over everything and override the existing containers global_info = quality_changes_info.global_info diff --git a/plugins/3MFReader/plugin.json b/plugins/3MFReader/plugin.json index 5e41975752..5af21a7033 100644 --- a/plugins/3MFReader/plugin.json +++ b/plugins/3MFReader/plugin.json @@ -1,8 +1,8 @@ { "name": "3MF Reader", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides support for reading 3MF files.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/3MFWriter/plugin.json b/plugins/3MFWriter/plugin.json index 9ec4fb0c20..3820ebd2e7 100644 --- a/plugins/3MFWriter/plugin.json +++ b/plugins/3MFWriter/plugin.json @@ -1,8 +1,8 @@ { "name": "3MF Writer", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides support for writing 3MF files.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt index 7e5cf2dd3b..651abb0cac 100755 --- a/plugins/ChangeLogPlugin/ChangeLog.txt +++ b/plugins/ChangeLogPlugin/ChangeLog.txt @@ -943,7 +943,7 @@ This release adds support for printers with elliptic buildplates. This feature h *AppImage for Linux The Linux distribution is now in AppImage format, which makes Cura easier to install. -*bugfixes +*Bugfixes The user is now notified when a new version of Cura is available. When searching in the setting visibility preferences, the category for each setting is always displayed. 3MF files are now saved and loaded correctly. diff --git a/plugins/ChangeLogPlugin/plugin.json b/plugins/ChangeLogPlugin/plugin.json index e09a08564a..92041d1543 100644 --- a/plugins/ChangeLogPlugin/plugin.json +++ b/plugins/ChangeLogPlugin/plugin.json @@ -1,8 +1,8 @@ { "name": "Changelog", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Shows changes since latest checked version.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/CuraDrive/__init__.py b/plugins/CuraDrive/__init__.py new file mode 100644 index 0000000000..eeb6b78689 --- /dev/null +++ b/plugins/CuraDrive/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from .src.DrivePluginExtension import DrivePluginExtension + + +def getMetaData(): + return {} + + +def register(app): + return {"extension": DrivePluginExtension()} diff --git a/plugins/CuraDrive/plugin.json b/plugins/CuraDrive/plugin.json new file mode 100644 index 0000000000..d1cab39ca5 --- /dev/null +++ b/plugins/CuraDrive/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Cura Backups", + "author": "Ultimaker B.V.", + "description": "Backup and restore your configuration.", + "version": "1.2.0", + "api": 6, + "i18n-catalog": "cura" +} diff --git a/plugins/CuraDrive/src/DriveApiService.py b/plugins/CuraDrive/src/DriveApiService.py new file mode 100644 index 0000000000..7c1f8faa83 --- /dev/null +++ b/plugins/CuraDrive/src/DriveApiService.py @@ -0,0 +1,168 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import base64 +import hashlib +from datetime import datetime +from tempfile import NamedTemporaryFile +from typing import Any, Optional, List, Dict + +import requests + +from UM.Logger import Logger +from UM.Message import Message +from UM.Signal import Signal, signalemitter +from cura.CuraApplication import CuraApplication + +from .UploadBackupJob import UploadBackupJob +from .Settings import Settings + +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") + + +## The DriveApiService is responsible for interacting with the CuraDrive API and Cura's backup handling. +@signalemitter +class DriveApiService: + BACKUP_URL = "{}/backups".format(Settings.DRIVE_API_URL) + + # Emit signal when restoring backup started or finished. + restoringStateChanged = Signal() + + # Emit signal when creating backup started or finished. + creatingStateChanged = Signal() + + def __init__(self) -> None: + self._cura_api = CuraApplication.getInstance().getCuraAPI() + + def getBackups(self) -> List[Dict[str, Any]]: + access_token = self._cura_api.account.accessToken + if not access_token: + Logger.log("w", "Could not get access token.") + return [] + + backup_list_request = requests.get(self.BACKUP_URL, headers = { + "Authorization": "Bearer {}".format(access_token) + }) + + # HTTP status 300s mean redirection. 400s and 500s are errors. + # Technically 300s are not errors, but the use case here relies on "requests" to handle redirects automatically. + if backup_list_request.status_code >= 300: + Logger.log("w", "Could not get backups list from remote: %s", backup_list_request.text) + Message(catalog.i18nc("@info:backup_status", "There was an error listing your backups."), title = catalog.i18nc("@info:title", "Backup")).show() + return [] + return backup_list_request.json()["data"] + + def createBackup(self) -> None: + self.creatingStateChanged.emit(is_creating = True) + + # Create the backup. + backup_zip_file, backup_meta_data = self._cura_api.backups.createBackup() + if not backup_zip_file or not backup_meta_data: + self.creatingStateChanged.emit(is_creating = False, error_message ="Could not create backup.") + return + + # Create an upload entry for the backup. + timestamp = datetime.now().isoformat() + backup_meta_data["description"] = "{}.backup.{}.cura.zip".format(timestamp, backup_meta_data["cura_release"]) + backup_upload_url = self._requestBackupUpload(backup_meta_data, len(backup_zip_file)) + if not backup_upload_url: + self.creatingStateChanged.emit(is_creating = False, error_message ="Could not upload backup.") + return + + # Upload the backup to storage. + upload_backup_job = UploadBackupJob(backup_upload_url, backup_zip_file) + upload_backup_job.finished.connect(self._onUploadFinished) + upload_backup_job.start() + + def _onUploadFinished(self, job: "UploadBackupJob") -> None: + if job.backup_upload_error_message != "": + # If the job contains an error message we pass it along so the UI can display it. + self.creatingStateChanged.emit(is_creating = False, error_message = job.backup_upload_error_message) + else: + self.creatingStateChanged.emit(is_creating = False) + + def restoreBackup(self, backup: Dict[str, Any]) -> None: + self.restoringStateChanged.emit(is_restoring = True) + download_url = backup.get("download_url") + if not download_url: + # If there is no download URL, we can't restore the backup. + return self._emitRestoreError() + + download_package = requests.get(download_url, stream = True) + if download_package.status_code >= 300: + # Something went wrong when attempting to download the backup. + Logger.log("w", "Could not download backup from url %s: %s", download_url, download_package.text) + return self._emitRestoreError() + + # We store the file in a temporary path fist to ensure integrity. + temporary_backup_file = NamedTemporaryFile(delete = False) + with open(temporary_backup_file.name, "wb") as write_backup: + for chunk in download_package: + write_backup.write(chunk) + + if not self._verifyMd5Hash(temporary_backup_file.name, backup.get("md5_hash", "")): + # Don't restore the backup if the MD5 hashes do not match. + # This can happen if the download was interrupted. + Logger.log("w", "Remote and local MD5 hashes do not match, not restoring backup.") + return self._emitRestoreError() + + # Tell Cura to place the backup back in the user data folder. + with open(temporary_backup_file.name, "rb") as read_backup: + self._cura_api.backups.restoreBackup(read_backup.read(), backup.get("metadata", {})) + self.restoringStateChanged.emit(is_restoring = False) + + def _emitRestoreError(self) -> None: + self.restoringStateChanged.emit(is_restoring = False, + error_message = catalog.i18nc("@info:backup_status", + "There was an error trying to restore your backup.")) + + # Verify the MD5 hash of a file. + # \param file_path Full path to the file. + # \param known_hash The known MD5 hash of the file. + # \return: Success or not. + @staticmethod + def _verifyMd5Hash(file_path: str, known_hash: str) -> bool: + with open(file_path, "rb") as read_backup: + local_md5_hash = base64.b64encode(hashlib.md5(read_backup.read()).digest(), altchars = b"_-").decode("utf-8") + return known_hash == local_md5_hash + + def deleteBackup(self, backup_id: str) -> bool: + access_token = self._cura_api.account.accessToken + if not access_token: + Logger.log("w", "Could not get access token.") + return False + + delete_backup = requests.delete("{}/{}".format(self.BACKUP_URL, backup_id), headers = { + "Authorization": "Bearer {}".format(access_token) + }) + if delete_backup.status_code >= 300: + Logger.log("w", "Could not delete backup: %s", delete_backup.text) + return False + return True + + # Request a backup upload slot from the API. + # \param backup_metadata: A dict containing some meta data about the backup. + # \param backup_size The size of the backup file in bytes. + # \return: The upload URL for the actual backup file if successful, otherwise None. + def _requestBackupUpload(self, backup_metadata: Dict[str, Any], backup_size: int) -> Optional[str]: + access_token = self._cura_api.account.accessToken + if not access_token: + Logger.log("w", "Could not get access token.") + return None + + backup_upload_request = requests.put(self.BACKUP_URL, json = { + "data": { + "backup_size": backup_size, + "metadata": backup_metadata + } + }, headers = { + "Authorization": "Bearer {}".format(access_token) + }) + + # Any status code of 300 or above indicates an error. + if backup_upload_request.status_code >= 300: + Logger.log("w", "Could not request backup upload: %s", backup_upload_request.text) + return None + + return backup_upload_request.json()["data"]["upload_url"] diff --git a/plugins/CuraDrive/src/DrivePluginExtension.py b/plugins/CuraDrive/src/DrivePluginExtension.py new file mode 100644 index 0000000000..060f1496f1 --- /dev/null +++ b/plugins/CuraDrive/src/DrivePluginExtension.py @@ -0,0 +1,162 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import os +from datetime import datetime +from typing import Optional, List, Dict, Any + +from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal + +from UM.Extension import Extension +from UM.Logger import Logger +from UM.Message import Message +from cura.CuraApplication import CuraApplication + +from .Settings import Settings +from .DriveApiService import DriveApiService + +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") + + +# The DivePluginExtension provides functionality to backup and restore your Cura configuration to Ultimaker's cloud. +class DrivePluginExtension(QObject, Extension): + + # Signal emitted when the list of backups changed. + backupsChanged = pyqtSignal() + + # Signal emitted when restoring has started. Needed to prevent parallel restoring. + restoringStateChanged = pyqtSignal() + + # Signal emitted when creating has started. Needed to prevent parallel creation of backups. + creatingStateChanged = pyqtSignal() + + # Signal emitted when preferences changed (like auto-backup). + preferencesChanged = pyqtSignal() + + DATE_FORMAT = "%d/%m/%Y %H:%M:%S" + + def __init__(self) -> None: + QObject.__init__(self, None) + Extension.__init__(self) + + # Local data caching for the UI. + self._drive_window = None # type: Optional[QObject] + self._backups = [] # type: List[Dict[str, Any]] + self._is_restoring_backup = False + self._is_creating_backup = False + + # Initialize services. + preferences = CuraApplication.getInstance().getPreferences() + self._drive_api_service = DriveApiService() + + # Attach signals. + CuraApplication.getInstance().getCuraAPI().account.loginStateChanged.connect(self._onLoginStateChanged) + self._drive_api_service.restoringStateChanged.connect(self._onRestoringStateChanged) + self._drive_api_service.creatingStateChanged.connect(self._onCreatingStateChanged) + + # Register preferences. + preferences.addPreference(Settings.AUTO_BACKUP_ENABLED_PREFERENCE_KEY, False) + preferences.addPreference(Settings.AUTO_BACKUP_LAST_DATE_PREFERENCE_KEY, + datetime.now().strftime(self.DATE_FORMAT)) + + # Register the menu item + self.addMenuItem(catalog.i18nc("@item:inmenu", "Manage backups"), self.showDriveWindow) + + # Make auto-backup on boot if required. + CuraApplication.getInstance().engineCreatedSignal.connect(self._autoBackup) + + def showDriveWindow(self) -> None: + if not self._drive_window: + plugin_dir_path = CuraApplication.getInstance().getPluginRegistry().getPluginPath("CuraDrive") + path = os.path.join(plugin_dir_path, "src", "qml", "main.qml") + self._drive_window = CuraApplication.getInstance().createQmlComponent(path, {"CuraDrive": self}) + self.refreshBackups() + if self._drive_window: + self._drive_window.show() + + def _autoBackup(self) -> None: + preferences = CuraApplication.getInstance().getPreferences() + if preferences.getValue(Settings.AUTO_BACKUP_ENABLED_PREFERENCE_KEY) and self._isLastBackupTooLongAgo(): + self.createBackup() + + def _isLastBackupTooLongAgo(self) -> bool: + current_date = datetime.now() + last_backup_date = self._getLastBackupDate() + date_diff = current_date - last_backup_date + return date_diff.days > 1 + + def _getLastBackupDate(self) -> "datetime": + preferences = CuraApplication.getInstance().getPreferences() + last_backup_date = preferences.getValue(Settings.AUTO_BACKUP_LAST_DATE_PREFERENCE_KEY) + return datetime.strptime(last_backup_date, self.DATE_FORMAT) + + def _storeBackupDate(self) -> None: + backup_date = datetime.now().strftime(self.DATE_FORMAT) + preferences = CuraApplication.getInstance().getPreferences() + preferences.setValue(Settings.AUTO_BACKUP_LAST_DATE_PREFERENCE_KEY, backup_date) + + def _onLoginStateChanged(self, logged_in: bool = False) -> None: + if logged_in: + self.refreshBackups() + + def _onRestoringStateChanged(self, is_restoring: bool = False, error_message: str = None) -> None: + self._is_restoring_backup = is_restoring + self.restoringStateChanged.emit() + if error_message: + Message(error_message, title = catalog.i18nc("@info:title", "Backup")).show() + + def _onCreatingStateChanged(self, is_creating: bool = False, error_message: str = None) -> None: + self._is_creating_backup = is_creating + self.creatingStateChanged.emit() + if error_message: + Message(error_message, title = catalog.i18nc("@info:title", "Backup")).show() + else: + self._storeBackupDate() + if not is_creating and not error_message: + # We've finished creating a new backup, to the list has to be updated. + self.refreshBackups() + + @pyqtSlot(bool, name = "toggleAutoBackup") + def toggleAutoBackup(self, enabled: bool) -> None: + preferences = CuraApplication.getInstance().getPreferences() + preferences.setValue(Settings.AUTO_BACKUP_ENABLED_PREFERENCE_KEY, enabled) + + @pyqtProperty(bool, notify = preferencesChanged) + def autoBackupEnabled(self) -> bool: + preferences = CuraApplication.getInstance().getPreferences() + return bool(preferences.getValue(Settings.AUTO_BACKUP_ENABLED_PREFERENCE_KEY)) + + @pyqtProperty("QVariantList", notify = backupsChanged) + def backups(self) -> List[Dict[str, Any]]: + return self._backups + + @pyqtSlot(name = "refreshBackups") + def refreshBackups(self) -> None: + self._backups = self._drive_api_service.getBackups() + self.backupsChanged.emit() + + @pyqtProperty(bool, notify = restoringStateChanged) + def isRestoringBackup(self) -> bool: + return self._is_restoring_backup + + @pyqtProperty(bool, notify = creatingStateChanged) + def isCreatingBackup(self) -> bool: + return self._is_creating_backup + + @pyqtSlot(str, name = "restoreBackup") + def restoreBackup(self, backup_id: str) -> None: + for backup in self._backups: + if backup.get("backup_id") == backup_id: + self._drive_api_service.restoreBackup(backup) + return + Logger.log("w", "Unable to find backup with the ID %s", backup_id) + + @pyqtSlot(name = "createBackup") + def createBackup(self) -> None: + self._drive_api_service.createBackup() + + @pyqtSlot(str, name = "deleteBackup") + def deleteBackup(self, backup_id: str) -> None: + self._drive_api_service.deleteBackup(backup_id) + self.refreshBackups() diff --git a/plugins/CuraDrive/src/Settings.py b/plugins/CuraDrive/src/Settings.py new file mode 100644 index 0000000000..abe64e0acd --- /dev/null +++ b/plugins/CuraDrive/src/Settings.py @@ -0,0 +1,13 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from cura import UltimakerCloudAuthentication + + +class Settings: + # Keeps the plugin settings. + DRIVE_API_VERSION = 1 + DRIVE_API_URL = "{}/cura-drive/v{}".format(UltimakerCloudAuthentication.CuraCloudAPIRoot, str(DRIVE_API_VERSION)) + + AUTO_BACKUP_ENABLED_PREFERENCE_KEY = "cura_drive/auto_backup_enabled" + AUTO_BACKUP_LAST_DATE_PREFERENCE_KEY = "cura_drive/auto_backup_date" diff --git a/plugins/CuraDrive/src/UploadBackupJob.py b/plugins/CuraDrive/src/UploadBackupJob.py new file mode 100644 index 0000000000..2e76ed9b4b --- /dev/null +++ b/plugins/CuraDrive/src/UploadBackupJob.py @@ -0,0 +1,41 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import requests + +from UM.Job import Job +from UM.Logger import Logger +from UM.Message import Message + +from UM.i18n import i18nCatalog +catalog = i18nCatalog("cura") + + +class UploadBackupJob(Job): + MESSAGE_TITLE = catalog.i18nc("@info:title", "Backups") + + # This job is responsible for uploading the backup file to cloud storage. + # As it can take longer than some other tasks, we schedule this using a Cura Job. + def __init__(self, signed_upload_url: str, backup_zip: bytes) -> None: + super().__init__() + self._signed_upload_url = signed_upload_url + self._backup_zip = backup_zip + self._upload_success = False + self.backup_upload_error_message = "" + + def run(self) -> None: + upload_message = Message(catalog.i18nc("@info:backup_status", "Uploading your backup..."), title = self.MESSAGE_TITLE, progress = -1) + upload_message.show() + + backup_upload = requests.put(self._signed_upload_url, data = self._backup_zip) + upload_message.hide() + + if backup_upload.status_code >= 300: + self.backup_upload_error_message = backup_upload.text + Logger.log("w", "Could not upload backup file: %s", backup_upload.text) + Message(catalog.i18nc("@info:backup_status", "There was an error while uploading your backup."), title = self.MESSAGE_TITLE).show() + else: + self._upload_success = True + Message(catalog.i18nc("@info:backup_status", "Your backup has finished uploading."), title = self.MESSAGE_TITLE).show() + + self.finished.emit(self) diff --git a/plugins/CuraDrive/src/__init__.py b/plugins/CuraDrive/src/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/CuraDrive/src/qml/components/BackupList.qml b/plugins/CuraDrive/src/qml/components/BackupList.qml new file mode 100644 index 0000000000..a4a460a885 --- /dev/null +++ b/plugins/CuraDrive/src/qml/components/BackupList.qml @@ -0,0 +1,39 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +import UM 1.1 as UM + +ScrollView +{ + property alias model: backupList.model + width: parent.width + clip: true + ListView + { + id: backupList + width: parent.width + delegate: Item + { + // Add a margin, otherwise the scrollbar is on top of the right most component + width: parent.width - UM.Theme.getSize("default_margin").width + height: childrenRect.height + + BackupListItem + { + id: backupListItem + width: parent.width + } + + Rectangle + { + id: divider + color: UM.Theme.getColor("lining") + height: UM.Theme.getSize("default_lining").height + } + } + } +} diff --git a/plugins/CuraDrive/src/qml/components/BackupListFooter.qml b/plugins/CuraDrive/src/qml/components/BackupListFooter.qml new file mode 100644 index 0000000000..8decdc5c27 --- /dev/null +++ b/plugins/CuraDrive/src/qml/components/BackupListFooter.qml @@ -0,0 +1,46 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 + +import UM 1.3 as UM +import Cura 1.0 as Cura + +import "../components" + +RowLayout +{ + id: backupListFooter + width: parent.width + property bool showInfoButton: false + + Cura.PrimaryButton + { + id: infoButton + text: catalog.i18nc("@button", "Want more?") + iconSource: UM.Theme.getIcon("info") + onClicked: Qt.openUrlExternally("https://goo.gl/forms/QACEP8pP3RV60QYG2") + visible: backupListFooter.showInfoButton + } + + Cura.PrimaryButton + { + id: createBackupButton + text: catalog.i18nc("@button", "Backup Now") + iconSource: UM.Theme.getIcon("plus") + enabled: !CuraDrive.isCreatingBackup && !CuraDrive.isRestoringBackup + onClicked: CuraDrive.createBackup() + busy: CuraDrive.isCreatingBackup + } + + Cura.CheckBoxWithTooltip + { + id: autoBackupEnabled + checked: CuraDrive.autoBackupEnabled + onClicked: CuraDrive.toggleAutoBackup(autoBackupEnabled.checked) + text: catalog.i18nc("@checkbox:description", "Auto Backup") + tooltip: catalog.i18nc("@checkbox:description", "Automatically create a backup each day that Cura is started.") + } +} diff --git a/plugins/CuraDrive/src/qml/components/BackupListItem.qml b/plugins/CuraDrive/src/qml/components/BackupListItem.qml new file mode 100644 index 0000000000..5cdb500b4e --- /dev/null +++ b/plugins/CuraDrive/src/qml/components/BackupListItem.qml @@ -0,0 +1,113 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.1 + +import UM 1.1 as UM +import Cura 1.0 as Cura + +Item +{ + id: backupListItem + width: parent.width + height: showDetails ? dataRow.height + backupDetails.height : dataRow.height + property bool showDetails: false + + // Backup details toggle animation. + Behavior on height + { + PropertyAnimation + { + duration: 70 + } + } + + RowLayout + { + id: dataRow + spacing: UM.Theme.getSize("wide_margin").width + width: parent.width + height: 50 * screenScaleFactor + + UM.SimpleButton + { + width: UM.Theme.getSize("section_icon").width + height: UM.Theme.getSize("section_icon").height + color: UM.Theme.getColor("small_button_text") + hoverColor: UM.Theme.getColor("small_button_text_hover") + iconSource: UM.Theme.getIcon("info") + onClicked: backupListItem.showDetails = !backupListItem.showDetails + } + + Label + { + text: new Date(modelData.generated_time).toLocaleString(UM.Preferences.getValue("general/language")) + color: UM.Theme.getColor("text") + elide: Text.ElideRight + Layout.minimumWidth: 100 * screenScaleFactor + Layout.maximumWidth: 500 * screenScaleFactor + Layout.fillWidth: true + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + } + + Label + { + text: modelData.metadata.description + color: UM.Theme.getColor("text") + elide: Text.ElideRight + Layout.minimumWidth: 100 * screenScaleFactor + Layout.maximumWidth: 500 * screenScaleFactor + Layout.fillWidth: true + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + } + + Cura.SecondaryButton + { + text: catalog.i18nc("@button", "Restore") + enabled: !CuraDrive.isCreatingBackup && !CuraDrive.isRestoringBackup + onClicked: confirmRestoreDialog.visible = true + } + + UM.SimpleButton + { + width: UM.Theme.getSize("message_close").width + height: UM.Theme.getSize("message_close").height + color: UM.Theme.getColor("small_button_text") + hoverColor: UM.Theme.getColor("small_button_text_hover") + iconSource: UM.Theme.getIcon("cross1") + onClicked: confirmDeleteDialog.visible = true + } + } + + BackupListItemDetails + { + id: backupDetails + backupDetailsData: modelData + width: parent.width + visible: parent.showDetails + anchors.top: dataRow.bottom + } + + MessageDialog + { + id: confirmDeleteDialog + title: catalog.i18nc("@dialog:title", "Delete Backup") + text: catalog.i18nc("@dialog:info", "Are you sure you want to delete this backup? This cannot be undone.") + standardButtons: StandardButton.Yes | StandardButton.No + onYes: CuraDrive.deleteBackup(modelData.backup_id) + } + + MessageDialog + { + id: confirmRestoreDialog + title: catalog.i18nc("@dialog:title", "Restore Backup") + text: catalog.i18nc("@dialog:info", "You will need to restart Cura before your backup is restored. Do you want to close Cura now?") + standardButtons: StandardButton.Yes | StandardButton.No + onYes: CuraDrive.restoreBackup(modelData.backup_id) + } +} diff --git a/plugins/CuraDrive/src/qml/components/BackupListItemDetails.qml b/plugins/CuraDrive/src/qml/components/BackupListItemDetails.qml new file mode 100644 index 0000000000..4da15c6f16 --- /dev/null +++ b/plugins/CuraDrive/src/qml/components/BackupListItemDetails.qml @@ -0,0 +1,63 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 + +import UM 1.1 as UM + +ColumnLayout +{ + id: backupDetails + width: parent.width + spacing: UM.Theme.getSize("default_margin").width + property var backupDetailsData + + // Cura version + BackupListItemDetailsRow + { + iconSource: UM.Theme.getIcon("application") + label: catalog.i18nc("@backuplist:label", "Cura Version") + value: backupDetailsData.metadata.cura_release + } + + // Machine count. + BackupListItemDetailsRow + { + iconSource: UM.Theme.getIcon("printer_single") + label: catalog.i18nc("@backuplist:label", "Machines") + value: backupDetailsData.metadata.machine_count + } + + // Material count + BackupListItemDetailsRow + { + iconSource: UM.Theme.getIcon("category_material") + label: catalog.i18nc("@backuplist:label", "Materials") + value: backupDetailsData.metadata.material_count + } + + // Profile count. + BackupListItemDetailsRow + { + iconSource: UM.Theme.getIcon("settings") + label: catalog.i18nc("@backuplist:label", "Profiles") + value: backupDetailsData.metadata.profile_count + } + + // Plugin count. + BackupListItemDetailsRow + { + iconSource: UM.Theme.getIcon("plugin") + label: catalog.i18nc("@backuplist:label", "Plugins") + value: backupDetailsData.metadata.plugin_count + } + + // Spacer. + Item + { + width: parent.width + height: UM.Theme.getSize("default_margin").height + } +} diff --git a/plugins/CuraDrive/src/qml/components/BackupListItemDetailsRow.qml b/plugins/CuraDrive/src/qml/components/BackupListItemDetailsRow.qml new file mode 100644 index 0000000000..9e4612fcf8 --- /dev/null +++ b/plugins/CuraDrive/src/qml/components/BackupListItemDetailsRow.qml @@ -0,0 +1,52 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 + +import UM 1.3 as UM + +RowLayout +{ + id: detailsRow + width: parent.width + height: 40 * screenScaleFactor + + property alias iconSource: icon.source + property alias label: detailName.text + property alias value: detailValue.text + + UM.RecolorImage + { + id: icon + width: 18 * screenScaleFactor + height: width + source: "" + color: UM.Theme.getColor("text") + } + + Label + { + id: detailName + color: UM.Theme.getColor("text") + elide: Text.ElideRight + Layout.minimumWidth: 50 * screenScaleFactor + Layout.maximumWidth: 100 * screenScaleFactor + Layout.fillWidth: true + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + } + + Label + { + id: detailValue + color: UM.Theme.getColor("text") + elide: Text.ElideRight + Layout.minimumWidth: 50 * screenScaleFactor + Layout.maximumWidth: 100 * screenScaleFactor + Layout.fillWidth: true + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + } +} diff --git a/plugins/CuraDrive/src/qml/images/icon.png b/plugins/CuraDrive/src/qml/images/icon.png new file mode 100644 index 0000000000..3f75491786 Binary files /dev/null and b/plugins/CuraDrive/src/qml/images/icon.png differ diff --git a/plugins/CuraDrive/src/qml/images/loading.gif b/plugins/CuraDrive/src/qml/images/loading.gif new file mode 100644 index 0000000000..791dcaa0c9 Binary files /dev/null and b/plugins/CuraDrive/src/qml/images/loading.gif differ diff --git a/plugins/CuraDrive/src/qml/main.qml b/plugins/CuraDrive/src/qml/main.qml new file mode 100644 index 0000000000..48bf3b6ea4 --- /dev/null +++ b/plugins/CuraDrive/src/qml/main.qml @@ -0,0 +1,44 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.2 + +import UM 1.3 as UM +import Cura 1.1 as Cura + +import "components" +import "pages" + +Window +{ + id: curaDriveDialog + minimumWidth: Math.round(UM.Theme.getSize("modal_window_minimum").width) + minimumHeight: Math.round(UM.Theme.getSize("modal_window_minimum").height) + maximumWidth: Math.round(minimumWidth * 1.2) + maximumHeight: Math.round(minimumHeight * 1.2) + width: minimumWidth + height: minimumHeight + color: UM.Theme.getColor("main_background") + title: catalog.i18nc("@title:window", "Cura Backups") + + // Globally available. + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + WelcomePage + { + id: welcomePage + visible: !Cura.API.account.isLoggedIn + } + + BackupsPage + { + id: backupsPage + visible: Cura.API.account.isLoggedIn + } +} diff --git a/plugins/CuraDrive/src/qml/pages/BackupsPage.qml b/plugins/CuraDrive/src/qml/pages/BackupsPage.qml new file mode 100644 index 0000000000..c337294744 --- /dev/null +++ b/plugins/CuraDrive/src/qml/pages/BackupsPage.qml @@ -0,0 +1,75 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 + +import UM 1.3 as UM +import Cura 1.1 as Cura + +import "../components" + +Item +{ + id: backupsPage + anchors.fill: parent + anchors.margins: UM.Theme.getSize("wide_margin").width + + ColumnLayout + { + spacing: UM.Theme.getSize("wide_margin").height + width: parent.width + anchors.fill: parent + + Label + { + id: backupTitle + text: catalog.i18nc("@title", "My Backups") + font: UM.Theme.getFont("large") + color: UM.Theme.getColor("text") + Layout.fillWidth: true + renderType: Text.NativeRendering + } + + Label + { + text: catalog.i18nc("@empty_state", + "You don't have any backups currently. Use the 'Backup Now' button to create one.") + width: parent.width + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + wrapMode: Label.WordWrap + visible: backupList.model.length == 0 + Layout.fillWidth: true + Layout.fillHeight: true + renderType: Text.NativeRendering + } + + BackupList + { + id: backupList + model: CuraDrive.backups + Layout.fillWidth: true + Layout.fillHeight: true + } + + Label + { + text: catalog.i18nc("@backup_limit_info", + "During the preview phase, you'll be limited to 5 visible backups. Remove a backup to see older ones.") + width: parent.width + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + wrapMode: Label.WordWrap + visible: backupList.model.length > 4 + renderType: Text.NativeRendering + } + + BackupListFooter + { + id: backupListFooter + showInfoButton: backupList.model.length > 4 + } + } +} diff --git a/plugins/CuraDrive/src/qml/pages/WelcomePage.qml b/plugins/CuraDrive/src/qml/pages/WelcomePage.qml new file mode 100644 index 0000000000..0b207bc170 --- /dev/null +++ b/plugins/CuraDrive/src/qml/pages/WelcomePage.qml @@ -0,0 +1,56 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Window 2.2 + +import UM 1.3 as UM +import Cura 1.1 as Cura + +import "../components" + + +Column +{ + id: welcomePage + spacing: UM.Theme.getSize("wide_margin").height + width: parent.width + height: childrenRect.height + anchors.centerIn: parent + + Image + { + id: profileImage + fillMode: Image.PreserveAspectFit + source: "../images/icon.png" + anchors.horizontalCenter: parent.horizontalCenter + width: Math.round(parent.width / 4) + } + + Label + { + id: welcomeTextLabel + text: catalog.i18nc("@description", "Backup and synchronize your Cura settings.") + width: Math.round(parent.width / 2) + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + anchors.horizontalCenter: parent.horizontalCenter + wrapMode: Label.WordWrap + renderType: Text.NativeRendering + } + + Cura.PrimaryButton + { + id: loginButton + width: UM.Theme.getSize("account_button").width + height: UM.Theme.getSize("account_button").height + anchors.horizontalCenter: parent.horizontalCenter + text: catalog.i18nc("@button", "Sign in") + onClicked: Cura.API.account.login() + fixedWidthMode: true + } +} + diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto index 292330576b..2eabe62366 100644 --- a/plugins/CuraEngineBackend/Cura.proto +++ b/plugins/CuraEngineBackend/Cura.proto @@ -29,7 +29,7 @@ message Object bytes normals = 3; //An array of 3 floats. bytes indices = 4; //An array of ints. repeated Setting settings = 5; // Setting override per object, overruling the global settings. - string name = 6; + string name = 6; //Mesh name } message Progress @@ -58,6 +58,7 @@ message Polygon { MoveCombingType = 8; MoveRetractionType = 9; SupportInterfaceType = 10; + PrimeTowerType = 11; } Type type = 1; // Type of move bytes points = 2; // The points of the polygon, or two points if only a line segment (Currently only line segments are used) @@ -108,8 +109,9 @@ message PrintTimeMaterialEstimates { // The print time for each feature and mate float time_travel = 9; float time_retract = 10; float time_support_interface = 11; + float time_prime_tower = 12; - repeated MaterialEstimates materialEstimates = 12; // materialEstimates data + repeated MaterialEstimates materialEstimates = 13; // materialEstimates data } message MaterialEstimates { diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 58bc74f3f1..ef0898bb04 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -86,8 +86,8 @@ class CuraEngineBackend(QObject, Backend): self._layer_view_active = False #type: bool self._onActiveViewChanged() - self._stored_layer_data = [] #type: List[Arcus.PythonMessage] - self._stored_optimized_layer_data = {} #type: Dict[int, List[Arcus.PythonMessage]] # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob + self._stored_layer_data = [] # type: List[Arcus.PythonMessage] + self._stored_optimized_layer_data = {} # type: Dict[int, List[Arcus.PythonMessage]] # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob self._scene = self._application.getController().getScene() #type: Scene self._scene.sceneChanged.connect(self._onSceneChanged) @@ -203,7 +203,7 @@ class CuraEngineBackend(QObject, Backend): @pyqtSlot() def stopSlicing(self) -> None: - self.backendStateChange.emit(BackendState.NotStarted) + self.setState(BackendState.NotStarted) if self._slicing: # We were already slicing. Stop the old job. self._terminate() self._createSocket() @@ -229,6 +229,7 @@ class CuraEngineBackend(QObject, Backend): if not self._build_plates_to_be_sliced: self.processingProgress.emit(1.0) Logger.log("w", "Slice unnecessary, nothing has changed that needs reslicing.") + self.setState(BackendState.Done) return if self._process_layers_job: @@ -245,7 +246,7 @@ class CuraEngineBackend(QObject, Backend): num_objects = self._numObjectsPerBuildPlate() self._stored_layer_data = [] - self._stored_optimized_layer_data[build_plate_to_be_sliced] = [] + if build_plate_to_be_sliced not in num_objects or num_objects[build_plate_to_be_sliced] == 0: self._scene.gcode_dict[build_plate_to_be_sliced] = [] #type: ignore #Because we created this attribute above. @@ -253,7 +254,7 @@ class CuraEngineBackend(QObject, Backend): if self._build_plates_to_be_sliced: self.slice() return - + self._stored_optimized_layer_data[build_plate_to_be_sliced] = [] if self._application.getPrintInformation() and build_plate_to_be_sliced == active_build_plate: self._application.getPrintInformation().setToZeroPrintInformation(build_plate_to_be_sliced) @@ -322,7 +323,7 @@ class CuraEngineBackend(QObject, Backend): self._start_slice_job = None if job.isCancelled() or job.getError() or job.getResult() == StartJobResult.Error: - self.backendStateChange.emit(BackendState.Error) + self.setState(BackendState.Error) self.backendError.emit(job) return @@ -331,10 +332,10 @@ class CuraEngineBackend(QObject, Backend): self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current material as it is incompatible with the selected machine or configuration."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() - self.backendStateChange.emit(BackendState.Error) + self.setState(BackendState.Error) self.backendError.emit(job) else: - self.backendStateChange.emit(BackendState.NotStarted) + self.setState(BackendState.NotStarted) return if job.getResult() == StartJobResult.SettingError: @@ -362,10 +363,10 @@ class CuraEngineBackend(QObject, Backend): self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}").format(", ".join(error_labels)), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() - self.backendStateChange.emit(BackendState.Error) + self.setState(BackendState.Error) self.backendError.emit(job) else: - self.backendStateChange.emit(BackendState.NotStarted) + self.setState(BackendState.NotStarted) return elif job.getResult() == StartJobResult.ObjectSettingError: @@ -386,7 +387,7 @@ class CuraEngineBackend(QObject, Backend): self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice due to some per-model settings. The following settings have errors on one or more models: {error_labels}").format(error_labels = ", ".join(errors.values())), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() - self.backendStateChange.emit(BackendState.Error) + self.setState(BackendState.Error) self.backendError.emit(job) return @@ -395,28 +396,28 @@ class CuraEngineBackend(QObject, Backend): self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because the prime tower or prime position(s) are invalid."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() - self.backendStateChange.emit(BackendState.Error) + self.setState(BackendState.Error) self.backendError.emit(job) else: - self.backendStateChange.emit(BackendState.NotStarted) + self.setState(BackendState.NotStarted) if job.getResult() == StartJobResult.ObjectsWithDisabledExtruder: self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because there are objects associated with disabled Extruder %s." % job.getMessage()), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() - self.backendStateChange.emit(BackendState.Error) + self.setState(BackendState.Error) self.backendError.emit(job) return if job.getResult() == StartJobResult.NothingToSlice: if self._application.platformActivity: - self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit."), + self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume or are assigned to a disabled extruder. Please scale or rotate models to fit, or enable an extruder."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() - self.backendStateChange.emit(BackendState.Error) + self.setState(BackendState.Error) self.backendError.emit(job) else: - self.backendStateChange.emit(BackendState.NotStarted) + self.setState(BackendState.NotStarted) self._invokeSlice() return @@ -424,7 +425,7 @@ class CuraEngineBackend(QObject, Backend): self._socket.sendMessage(job.getSliceMessage()) # Notify the user that it's now up to the backend to do it's job - self.backendStateChange.emit(BackendState.Processing) + self.setState(BackendState.Processing) if self._slice_start_time: Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time ) @@ -442,7 +443,7 @@ class CuraEngineBackend(QObject, Backend): for node in DepthFirstIterator(self._scene.getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. if node.callDecoration("isBlockSlicing"): enable_timer = False - self.backendStateChange.emit(BackendState.Disabled) + self.setState(BackendState.Disabled) self._is_disabled = True gcode_list = node.callDecoration("getGCodeList") if gcode_list is not None: @@ -451,7 +452,7 @@ class CuraEngineBackend(QObject, Backend): if self._use_timer == enable_timer: return self._use_timer if enable_timer: - self.backendStateChange.emit(BackendState.NotStarted) + self.setState(BackendState.NotStarted) self.enableTimer() return True else: @@ -518,7 +519,7 @@ class CuraEngineBackend(QObject, Backend): self._build_plates_to_be_sliced.append(build_plate_number) self.printDurationMessage.emit(source_build_plate_number, {}, []) self.processingProgress.emit(0.0) - self.backendStateChange.emit(BackendState.NotStarted) + self.setState(BackendState.NotStarted) # if not self._use_timer: # With manually having to slice, we want to clear the old invalid layer data. self._clearLayerData(build_plate_changed) @@ -567,7 +568,7 @@ class CuraEngineBackend(QObject, Backend): self.stopSlicing() self.markSliceAll() self.processingProgress.emit(0.0) - self.backendStateChange.emit(BackendState.NotStarted) + self.setState(BackendState.NotStarted) if not self._use_timer: # With manually having to slice, we want to clear the old invalid layer data. self._clearLayerData() @@ -613,7 +614,7 @@ class CuraEngineBackend(QObject, Backend): # \param message The protobuf message containing the slicing progress. def _onProgressMessage(self, message: Arcus.PythonMessage) -> None: self.processingProgress.emit(message.amount) - self.backendStateChange.emit(BackendState.Processing) + self.setState(BackendState.Processing) def _invokeSlice(self) -> None: if self._use_timer: @@ -632,7 +633,7 @@ class CuraEngineBackend(QObject, Backend): # # \param message The protobuf message signalling that slicing is finished. def _onSlicingFinishedMessage(self, message: Arcus.PythonMessage) -> None: - self.backendStateChange.emit(BackendState.Done) + self.setState(BackendState.Done) self.processingProgress.emit(1.0) gcode_list = self._scene.gcode_dict[self._start_slice_job_build_plate] #type: ignore #Because we generate this attribute dynamically. @@ -832,7 +833,10 @@ class CuraEngineBackend(QObject, Backend): self._onChanged() def _onProcessLayersFinished(self, job: ProcessSlicedLayersJob) -> None: - del self._stored_optimized_layer_data[job.getBuildPlate()] + if job.getBuildPlate() in self._stored_optimized_layer_data: + del self._stored_optimized_layer_data[job.getBuildPlate()] + else: + Logger.log("w", "The optimized layer data was already deleted for buildplate %s", job.getBuildPlate()) self._process_layers_job = None Logger.log("d", "See if there is more to slice(2)...") self._invokeSlice() diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py index 594bf3a43e..3cc23130ea 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py @@ -137,6 +137,7 @@ class ProcessSlicedLayersJob(Job): extruder = polygon.extruder line_types = numpy.fromstring(polygon.line_type, dtype="u1") # Convert bytearray to numpy array + line_types = line_types.reshape((-1,1)) points = numpy.fromstring(polygon.points, dtype="f4") # Convert bytearray to numpy array @@ -195,7 +196,7 @@ class ProcessSlicedLayersJob(Job): if extruders: material_color_map = numpy.zeros((len(extruders), 4), dtype=numpy.float32) for extruder in extruders: - position = int(extruder.getMetaDataEntry("position", default="0")) # Get the position + position = int(extruder.getMetaDataEntry("position", default = "0")) try: default_color = ExtrudersModel.defaultColors[position] except IndexError: diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 79b1e5249c..d3882a1209 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -66,11 +66,19 @@ class GcodeStartEndFormatter(Formatter): return "{" + key + "}" key = key_fragments[0] - try: - return kwargs[str(extruder_nr)][key] - except KeyError: + + default_value_str = "{" + key + "}" + value = default_value_str + # "-1" is global stack, and if the setting value exists in the global stack, use it as the fallback value. + if key in kwargs["-1"]: + value = kwargs["-1"] + if str(extruder_nr) in kwargs and key in kwargs[str(extruder_nr)]: + value = kwargs[str(extruder_nr)][key] + + if value == default_value_str: Logger.log("w", "Unable to replace '%s' placeholder in start/end g-code", key) - return "{" + key + "}" + + return value ## Job class that builds up the message of scene data to send to CuraEngine. @@ -315,7 +323,7 @@ class StartSliceJob(Job): value = stack.getProperty(key, "value") result[key] = value Job.yieldThread() - + result["print_bed_temperature"] = result["material_bed_temperature"] # Renamed settings. result["print_temperature"] = result["material_print_temperature"] result["time"] = time.strftime("%H:%M:%S") #Some extra settings. diff --git a/plugins/CuraEngineBackend/plugin.json b/plugins/CuraEngineBackend/plugin.json index 111698d8d1..28f0e294e7 100644 --- a/plugins/CuraEngineBackend/plugin.json +++ b/plugins/CuraEngineBackend/plugin.json @@ -2,7 +2,7 @@ "name": "CuraEngine Backend", "author": "Ultimaker B.V.", "description": "Provides the link to the CuraEngine slicing backend.", - "api": 5, - "version": "1.0.0", + "api": "6.0", + "version": "1.0.1", "i18n-catalog": "cura" } diff --git a/plugins/CuraProfileReader/plugin.json b/plugins/CuraProfileReader/plugin.json index 66a2a6a56b..169fb43360 100644 --- a/plugins/CuraProfileReader/plugin.json +++ b/plugins/CuraProfileReader/plugin.json @@ -1,8 +1,8 @@ { "name": "Cura Profile Reader", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides support for importing Cura profiles.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/CuraProfileWriter/plugin.json b/plugins/CuraProfileWriter/plugin.json index 16c8c34152..9627c754d7 100644 --- a/plugins/CuraProfileWriter/plugin.json +++ b/plugins/CuraProfileWriter/plugin.json @@ -1,8 +1,8 @@ { "name": "Cura Profile Writer", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides support for exporting Cura profiles.", - "api": 5, + "api": "6.0", "i18n-catalog":"cura" } diff --git a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py index b37de81f34..906c20dd25 100644 --- a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py +++ b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py @@ -86,6 +86,11 @@ class FirmwareUpdateCheckerJob(Job): current_version = self.getCurrentVersion() + # This case indicates that was an error checking the version. + # It happens for instance when not connected to internet. + if current_version == self.ZERO_VERSION: + return + # If it is the first time the version is checked, the checked_version is "" setting_key_str = getSettingsKeyForMachine(machine_id) checked_version = Version(Application.getInstance().getPreferences().getValue(setting_key_str)) diff --git a/plugins/FirmwareUpdateChecker/plugin.json b/plugins/FirmwareUpdateChecker/plugin.json index cbbd41e420..6c55d77fd8 100644 --- a/plugins/FirmwareUpdateChecker/plugin.json +++ b/plugins/FirmwareUpdateChecker/plugin.json @@ -1,8 +1,8 @@ { "name": "Firmware Update Checker", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Checks for firmware updates.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py index 0a3e3a0ff0..59552775b6 100644 --- a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py @@ -57,7 +57,7 @@ class FirmwareUpdaterMachineAction(MachineAction): outputDeviceCanUpdateFirmwareChanged = pyqtSignal() @pyqtProperty(QObject, notify = outputDeviceCanUpdateFirmwareChanged) def firmwareUpdater(self) -> Optional["FirmwareUpdater"]: - if self._active_output_device and self._active_output_device.activePrinter.getController().can_update_firmware: + if self._active_output_device and self._active_output_device.activePrinter and self._active_output_device.activePrinter.getController().can_update_firmware: self._active_firmware_updater = self._active_output_device.getFirmwareUpdater() return self._active_firmware_updater diff --git a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml index 9a56dbb20a..b5b6c15f50 100644 --- a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml @@ -22,7 +22,7 @@ Cura.MachineAction { id: firmwareUpdaterMachineAction anchors.fill: parent; - UM.I18nCatalog { id: catalog; name:"cura"} + UM.I18nCatalog { id: catalog; name: "cura"} spacing: UM.Theme.getSize("default_margin").height Label diff --git a/plugins/FirmwareUpdater/plugin.json b/plugins/FirmwareUpdater/plugin.json index 3e09eab2b5..c1034e5e42 100644 --- a/plugins/FirmwareUpdater/plugin.json +++ b/plugins/FirmwareUpdater/plugin.json @@ -1,8 +1,8 @@ { "name": "Firmware Updater", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides a machine actions for updating firmware.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/GCodeGzReader/plugin.json b/plugins/GCodeGzReader/plugin.json index 3bd6a4097d..d4f281682f 100644 --- a/plugins/GCodeGzReader/plugin.json +++ b/plugins/GCodeGzReader/plugin.json @@ -1,8 +1,8 @@ { "name": "Compressed G-code Reader", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Reads g-code from a compressed archive.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/GCodeGzWriter/plugin.json b/plugins/GCodeGzWriter/plugin.json index 4c6497317b..b0e6f8d605 100644 --- a/plugins/GCodeGzWriter/plugin.json +++ b/plugins/GCodeGzWriter/plugin.json @@ -1,8 +1,8 @@ { "name": "Compressed G-code Writer", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Writes g-code to a compressed archive.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/GCodeProfileReader/plugin.json b/plugins/GCodeProfileReader/plugin.json index 9677628c85..af1c2d1827 100644 --- a/plugins/GCodeProfileReader/plugin.json +++ b/plugins/GCodeProfileReader/plugin.json @@ -1,8 +1,8 @@ { "name": "G-code Profile Reader", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides support for importing profiles from g-code files.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/GCodeReader/FlavorParser.py b/plugins/GCodeReader/FlavorParser.py index 6fe2cb5260..baf21d47ce 100644 --- a/plugins/GCodeReader/FlavorParser.py +++ b/plugins/GCodeReader/FlavorParser.py @@ -364,6 +364,8 @@ class FlavorParser: self._layer_type = LayerPolygon.SupportType elif type == "FILL": self._layer_type = LayerPolygon.InfillType + elif type == "SUPPORT-INTERFACE": + self._layer_type = LayerPolygon.SupportInterfaceType else: Logger.log("w", "Encountered a unknown type (%s) while parsing g-code.", type) diff --git a/plugins/GCodeReader/plugin.json b/plugins/GCodeReader/plugin.json index 75b4d0cd4f..bbc94fa917 100644 --- a/plugins/GCodeReader/plugin.json +++ b/plugins/GCodeReader/plugin.json @@ -1,8 +1,8 @@ { "name": "G-code Reader", - "author": "Victor Larchenko", - "version": "1.0.0", + "author": "Victor Larchenko, Ultimaker", + "version": "1.0.1", "description": "Allows loading and displaying G-code files.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/GCodeWriter/plugin.json b/plugins/GCodeWriter/plugin.json index 3bbbab8b95..f3a95ddb78 100644 --- a/plugins/GCodeWriter/plugin.json +++ b/plugins/GCodeWriter/plugin.json @@ -1,8 +1,8 @@ { "name": "G-code Writer", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Writes g-code to a file.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/ImageReader/ConfigUI.qml b/plugins/ImageReader/ConfigUI.qml index 12c6aa8dde..b9ff2e4453 100644 --- a/plugins/ImageReader/ConfigUI.qml +++ b/plugins/ImageReader/ConfigUI.qml @@ -20,7 +20,7 @@ UM.Dialog GridLayout { - UM.I18nCatalog{id: catalog; name:"cura"} + UM.I18nCatalog{id: catalog; name: "cura"} anchors.fill: parent; Layout.fillWidth: true columnSpacing: 16 * screenScaleFactor diff --git a/plugins/ImageReader/plugin.json b/plugins/ImageReader/plugin.json index 08195863e8..d966537d99 100644 --- a/plugins/ImageReader/plugin.json +++ b/plugins/ImageReader/plugin.json @@ -1,8 +1,8 @@ { "name": "Image Reader", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Enables ability to generate printable geometry from 2D image files.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/LegacyProfileReader/plugin.json b/plugins/LegacyProfileReader/plugin.json index 179f5444e0..2f5264ad37 100644 --- a/plugins/LegacyProfileReader/plugin.json +++ b/plugins/LegacyProfileReader/plugin.json @@ -1,8 +1,8 @@ { "name": "Legacy Cura Profile Reader", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides support for importing profiles from legacy Cura versions.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index 004b4e3cfc..ef8fda224a 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 @@ -13,7 +13,8 @@ import Cura 1.0 as Cura Cura.MachineAction { id: base - property var extrudersModel: Cura.ExtrudersModel{} + property var extrudersModel: Cura.ExtrudersModel{} // Do not retrieve the Model from a backend. Otherwise the tabs + // in tabView will not removed/updated. Probably QML bug property int extruderTabsCount: 0 property var activeMachineId: Cura.MachineManager.activeMachine != null ? Cura.MachineManager.activeMachine.id : "" @@ -23,7 +24,7 @@ Cura.MachineAction target: base.extrudersModel onModelChanged: { - var extruderCount = base.extrudersModel.rowCount(); + var extruderCount = base.extrudersModel.count; base.extruderTabsCount = extruderCount; } } diff --git a/plugins/MachineSettingsAction/plugin.json b/plugins/MachineSettingsAction/plugin.json index 571658e40a..d734c1adf5 100644 --- a/plugins/MachineSettingsAction/plugin.json +++ b/plugins/MachineSettingsAction/plugin.json @@ -1,8 +1,8 @@ { "name": "Machine Settings action", "author": "fieldOfView", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides a way to change machine settings (such as build volume, nozzle size, etc.).", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/ModelChecker/ModelChecker.qml b/plugins/ModelChecker/ModelChecker.qml index 98db233bf8..ddeed063b1 100644 --- a/plugins/ModelChecker/ModelChecker.qml +++ b/plugins/ModelChecker/ModelChecker.qml @@ -4,19 +4,19 @@ 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"} + UM.I18nCatalog + { + id: catalog + name: "cura" + } visible: manager.hasWarnings tooltip: catalog.i18nc("@info:tooltip", "Some things could be problematic in this print. Click to see tips for adjustment.") @@ -25,6 +25,8 @@ Button width: UM.Theme.getSize("save_button_specs_icons").width height: UM.Theme.getSize("save_button_specs_icons").height + anchors.verticalCenter: parent ? parent.verticalCenter : undefined + style: ButtonStyle { background: Item @@ -33,7 +35,6 @@ Button { 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/plugin.json b/plugins/ModelChecker/plugin.json index 3753c0cc88..59be5bbf0a 100644 --- a/plugins/ModelChecker/plugin.json +++ b/plugins/ModelChecker/plugin.json @@ -1,8 +1,8 @@ { "name": "Model Checker", "author": "Ultimaker B.V.", - "version": "0.1", - "api": 5, + "version": "1.0.1", + "api": "6.0", "description": "Checks models and print configuration for possible printing issues and give suggestions.", "i18n-catalog": "cura" } diff --git a/plugins/MonitorStage/MonitorMain.qml b/plugins/MonitorStage/MonitorMain.qml new file mode 100644 index 0000000000..5fda32db9e --- /dev/null +++ b/plugins/MonitorStage/MonitorMain.qml @@ -0,0 +1,45 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.10 +import QtQuick.Controls 1.4 + +import UM 1.3 as UM +import Cura 1.0 as Cura + + +// We show a nice overlay on the 3D viewer when the current output device has no monitor view +Rectangle +{ + id: viewportOverlay + + color: UM.Theme.getColor("viewport_overlay") + anchors.fill: parent + + // This mouse area is to prevent mouse clicks to be passed onto the scene. + MouseArea + { + anchors.fill: parent + acceptedButtons: Qt.AllButtons + onWheel: wheel.accepted = true + } + + // Disable dropping files into Cura when the monitor page is active + DropArea + { + anchors.fill: parent + } + Loader + { + id: monitorViewComponent + + anchors.fill: parent + + height: parent.height + + property real maximumWidth: parent.width + property real maximumHeight: parent.height + + sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem : null + } +} \ No newline at end of file diff --git a/plugins/MonitorStage/MonitorMainView.qml b/plugins/MonitorStage/MonitorMainView.qml deleted file mode 100644 index c48f6d0aab..0000000000 --- a/plugins/MonitorStage/MonitorMainView.qml +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2017 Ultimaker B.V. - -import QtQuick 2.2 -import QtQuick.Controls 1.1 - -import UM 1.3 as UM -import Cura 1.0 as Cura - -Item -{ - // parent could be undefined as this component is not visible at all times - width: parent ? parent.width : 0 - height: parent ? parent.height : 0 - - // We show a nice overlay on the 3D viewer when the current output device has no monitor view - Rectangle - { - id: viewportOverlay - - color: UM.Theme.getColor("viewport_overlay") - width: parent.width - height: parent.height - - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.AllButtons - onWheel: wheel.accepted = true - } - } - - Loader - { - id: monitorViewComponent - - width: parent.width - height: parent.height - - property real maximumWidth: parent.width - property real maximumHeight: parent.height - - sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem: null - visible: sourceComponent != null - } -} diff --git a/plugins/MonitorStage/MonitorMenu.qml b/plugins/MonitorStage/MonitorMenu.qml new file mode 100644 index 0000000000..bc95c276e8 --- /dev/null +++ b/plugins/MonitorStage/MonitorMenu.qml @@ -0,0 +1,23 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.3 as UM +import Cura 1.1 as Cura + +Item +{ + signal showTooltip(Item item, point location, string text) + signal hideTooltip() + + Cura.MachineSelector + { + id: machineSelection + headerCornerSide: Cura.RoundedRectangle.Direction.All + width: UM.Theme.getSize("machine_selector_widget").width + height: parent.height + anchors.centerIn: parent + } +} \ No newline at end of file diff --git a/plugins/MonitorStage/MonitorStage.py b/plugins/MonitorStage/MonitorStage.py index ace201e994..69b7f20f4e 100644 --- a/plugins/MonitorStage/MonitorStage.py +++ b/plugins/MonitorStage/MonitorStage.py @@ -65,15 +65,10 @@ class MonitorStage(CuraStage): # We can only connect now, as we need to be sure that everything is loaded (plugins get created quite early) Application.getInstance().getMachineManager().outputDevicesChanged.connect(self._onOutputDevicesChanged) self._onOutputDevicesChanged() - self._updateMainOverlay() - self._updateSidebar() - def _updateMainOverlay(self): - main_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("MonitorStage"), - "MonitorMainView.qml") - self.addDisplayComponent("main", main_component_path) - - def _updateSidebar(self): - sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles), - "MonitorSidebar.qml") - self.addDisplayComponent("sidebar", sidebar_component_path) + plugin_path = Application.getInstance().getPluginRegistry().getPluginPath(self.getPluginId()) + if plugin_path is not None: + menu_component_path = os.path.join(plugin_path, "MonitorMenu.qml") + main_component_path = os.path.join(plugin_path, "MonitorMain.qml") + self.addDisplayComponent("menu", menu_component_path) + self.addDisplayComponent("main", main_component_path) diff --git a/plugins/MonitorStage/__init__.py b/plugins/MonitorStage/__init__.py index bdaf53a36c..0468e6319b 100644 --- a/plugins/MonitorStage/__init__.py +++ b/plugins/MonitorStage/__init__.py @@ -7,14 +7,16 @@ from . import MonitorStage from UM.i18n import i18nCatalog i18n_catalog = i18nCatalog("cura") + def getMetaData(): return { "stage": { "name": i18n_catalog.i18nc("@item:inmenu", "Monitor"), - "weight": 1 + "weight": 2 } } + def register(app): return { "stage": MonitorStage.MonitorStage() diff --git a/plugins/MonitorStage/plugin.json b/plugins/MonitorStage/plugin.json index 88b53840e0..95e4b86f36 100644 --- a/plugins/MonitorStage/plugin.json +++ b/plugins/MonitorStage/plugin.json @@ -1,8 +1,8 @@ { "name": "Monitor Stage", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides a monitor stage in Cura.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } \ No newline at end of file diff --git a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml index 5d4e17a102..0e2bd88619 100644 --- a/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml +++ b/plugins/PerObjectSettingsTool/PerObjectSettingsPanel.qml @@ -265,7 +265,6 @@ Item { anchors.verticalCenter: parent.verticalCenter width: parent.width height: width - sourceSize.width: width sourceSize.height: width color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button") source: UM.Theme.getIcon("minus") diff --git a/plugins/PerObjectSettingsTool/plugin.json b/plugins/PerObjectSettingsTool/plugin.json index 15fde63387..f272abf06a 100644 --- a/plugins/PerObjectSettingsTool/plugin.json +++ b/plugins/PerObjectSettingsTool/plugin.json @@ -1,8 +1,8 @@ { "name": "Per Model Settings Tool", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides the Per Model Settings.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.py b/plugins/PostProcessingPlugin/PostProcessingPlugin.py index 11ee610bec..78f9cc0516 100644 --- a/plugins/PostProcessingPlugin/PostProcessingPlugin.py +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.py @@ -55,14 +55,14 @@ class PostProcessingPlugin(QObject, Extension): def selectedScriptDefinitionId(self) -> Optional[str]: try: return self._script_list[self._selected_script_index].getDefinitionId() - except: + except IndexError: return "" @pyqtProperty(str, notify=selectedIndexChanged) def selectedScriptStackId(self) -> Optional[str]: try: return self._script_list[self._selected_script_index].getStackId() - except: + except IndexError: return "" ## Execute all post-processing scripts on the gcode. diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.qml b/plugins/PostProcessingPlugin/PostProcessingPlugin.qml index d492e06462..cd8303d1d3 100644 --- a/plugins/PostProcessingPlugin/PostProcessingPlugin.qml +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.qml @@ -25,13 +25,13 @@ UM.Dialog { if(!visible) //Whenever the window is closed (either via the "Close" button or the X on the window frame), we want to update it in the stack. { - manager.writeScriptsToStack(); + manager.writeScriptsToStack() } } Item { - UM.I18nCatalog{id: catalog; name:"cura"} + UM.I18nCatalog{id: catalog; name: "cura"} id: base property int columnWidth: Math.round((base.width / 2) - UM.Theme.getSize("default_margin").width) property int textMargin: Math.round(UM.Theme.getSize("default_margin").width / 2) @@ -61,18 +61,23 @@ UM.Dialog anchors.leftMargin: base.textMargin anchors.right: parent.right anchors.rightMargin: base.textMargin - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") elide: Text.ElideRight } ListView { id: activeScriptsList - anchors.top: activeScriptsHeader.bottom - anchors.topMargin: base.textMargin - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.right: parent.right - anchors.rightMargin: base.textMargin + + anchors + { + top: activeScriptsHeader.bottom + left: parent.left + right: parent.right + rightMargin: base.textMargin + topMargin: base.textMargin + leftMargin: UM.Theme.getSize("default_margin").width + } + height: childrenRect.height model: manager.scriptList delegate: Item @@ -84,8 +89,12 @@ UM.Dialog id: activeScriptButton text: manager.getScriptLabelByKey(modelData.toString()) exclusiveGroup: selectedScriptGroup + width: parent.width + height: UM.Theme.getSize("setting").height checkable: true - checked: { + + checked: + { if (manager.selectedScriptIndex == index) { base.activeScriptName = manager.getScriptLabelByKey(modelData.toString()) @@ -102,8 +111,7 @@ UM.Dialog manager.setSelectedScriptIndex(index) base.activeScriptName = manager.getScriptLabelByKey(modelData.toString()) } - width: parent.width - height: UM.Theme.getSize("setting").height + style: ButtonStyle { background: Rectangle @@ -121,6 +129,7 @@ UM.Dialog } } } + Button { id: removeButton @@ -141,7 +150,6 @@ UM.Dialog anchors.horizontalCenter: parent.horizontalCenter width: Math.round(control.width / 2.7) height: Math.round(control.height / 2.7) - sourceSize.width: width sourceSize.height: width color: palette.text source: UM.Theme.getIcon("cross1") @@ -176,7 +184,6 @@ UM.Dialog anchors.horizontalCenter: parent.horizontalCenter width: Math.round(control.width / 2.5) height: Math.round(control.height / 2.5) - sourceSize.width: width sourceSize.height: width color: control.enabled ? palette.text : disabledPalette.text source: UM.Theme.getIcon("arrow_bottom") @@ -211,7 +218,6 @@ UM.Dialog anchors.horizontalCenter: parent.horizontalCenter width: Math.round(control.width / 2.5) height: Math.round(control.height / 2.5) - sourceSize.width: width sourceSize.height: width color: control.enabled ? palette.text : disabledPalette.text source: UM.Theme.getIcon("arrow_top") @@ -252,15 +258,15 @@ UM.Dialog onTriggered: manager.addScriptToList(modelData.toString()) } - onObjectAdded: scriptsMenu.insertItem(index, object); - onObjectRemoved: scriptsMenu.removeItem(object); + onObjectAdded: scriptsMenu.insertItem(index, object) + onObjectRemoved: scriptsMenu.removeItem(object) } } } Rectangle { - color: UM.Theme.getColor("sidebar") + color: UM.Theme.getColor("main_background") anchors.left: activeScripts.right anchors.leftMargin: UM.Theme.getSize("default_margin").width anchors.right: parent.right @@ -271,26 +277,35 @@ UM.Dialog { id: scriptSpecsHeader text: manager.selectedScriptIndex == -1 ? catalog.i18nc("@label", "Settings") : base.activeScriptName - anchors.top: parent.top - anchors.topMargin: base.textMargin - anchors.left: parent.left - anchors.leftMargin: base.textMargin - anchors.right: parent.right - anchors.rightMargin: base.textMargin + anchors + { + top: parent.top + topMargin: base.textMargin + left: parent.left + leftMargin: base.textMargin + right: parent.right + rightMargin: base.textMargin + } + elide: Text.ElideRight height: 20 * screenScaleFactor - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") } ScrollView { id: scrollView - anchors.top: scriptSpecsHeader.bottom - anchors.topMargin: settingsPanel.textMargin - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom + anchors + { + top: scriptSpecsHeader.bottom + topMargin: settingsPanel.textMargin + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + bottom: parent.bottom + } + visible: manager.selectedScriptDefinitionId != "" style: UM.Theme.styles.scrollview; @@ -300,11 +315,12 @@ UM.Dialog spacing: UM.Theme.getSize("default_lining").height model: UM.SettingDefinitionsModel { - id: definitionsModel; + id: definitionsModel containerId: manager.selectedScriptDefinitionId showAll: true } - delegate:Loader + + delegate: Loader { id: settingLoader @@ -315,23 +331,24 @@ UM.Dialog { if(model.type != undefined) { - return UM.Theme.getSize("section").height; + return UM.Theme.getSize("section").height } else { - return 0; + return 0 } } else { - return 0; + return 0 } - } Behavior on height { NumberAnimation { duration: 100 } } opacity: provider.properties.enabled == "True" ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } enabled: opacity > 0 + property var definition: model property var settingDefinitionsModel: definitionsModel property var propertyProvider: provider @@ -342,11 +359,12 @@ UM.Dialog //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. asynchronous: model.type != "enum" && model.type != "extruder" - onLoaded: { + onLoaded: + { settingLoader.item.showRevertButton = false settingLoader.item.showInheritButton = false settingLoader.item.showLinkedSettingIcon = false - settingLoader.item.doDepthIndentation = true + settingLoader.item.doDepthIndentation = false settingLoader.item.doQualityUserSettingEmphasis = false } @@ -398,24 +416,20 @@ UM.Dialog onShowTooltip: { - tooltip.text = text; - var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0); - tooltip.show(position); + tooltip.text = text + var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0) + tooltip.show(position) tooltip.target.x = position.x + 1 } - onHideTooltip: - { - tooltip.hide(); - } + onHideTooltip: tooltip.hide() } - } } } } - Cura.SidebarTooltip + Cura.PrintSetupTooltip { id: tooltip } @@ -462,6 +476,7 @@ UM.Dialog Cura.SettingUnknown { } } } + rightButtons: Button { text: catalog.i18nc("@action:button", "Close") @@ -469,44 +484,15 @@ UM.Dialog onClicked: dialog.accept() } - Button { + Cura.SecondaryButton + { objectName: "postProcessingSaveAreaButton" visible: activeScriptsList.count > 0 - height: UM.Theme.getSize("save_button_save_to_button").height + height: UM.Theme.getSize("action_button").height width: height tooltip: catalog.i18nc("@info:tooltip", "Change active post-processing scripts") onClicked: dialog.show() - - style: ButtonStyle { - background: Rectangle { - id: deviceSelectionIcon - border.width: UM.Theme.getSize("default_lining").width - border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") : - control.pressed ? UM.Theme.getColor("action_button_active_border") : - control.hovered ? UM.Theme.getColor("action_button_hovered_border") : UM.Theme.getColor("action_button_border") - color: !control.enabled ? UM.Theme.getColor("action_button_disabled") : - control.pressed ? UM.Theme.getColor("action_button_active") : - control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") - Behavior on color { ColorAnimation { duration: 50; } } - anchors.left: parent.left - anchors.leftMargin: Math.round(UM.Theme.getSize("save_button_text_margin").width / 2); - width: parent.height - height: parent.height - - UM.RecolorImage { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - width: Math.round(parent.width / 2) - height: Math.round(parent.height / 2) - sourceSize.width: width - sourceSize.height: height - color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") : - control.pressed ? UM.Theme.getColor("action_button_active_text") : - control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text"); - source: "postprocessing.svg" - } - } - label: Label{ } - } + iconSource: "postprocessing.svg" + fixedWidthMode: true } } \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/plugin.json b/plugins/PostProcessingPlugin/plugin.json index fea061e93b..1e73133c53 100644 --- a/plugins/PostProcessingPlugin/plugin.json +++ b/plugins/PostProcessingPlugin/plugin.json @@ -1,8 +1,8 @@ { "name": "Post Processing", "author": "Ultimaker", - "version": "2.2", - "api": 5, + "version": "2.2.1", + "api": "6.0", "description": "Extension that allows for user created scripts for post processing", "catalog": "cura" } \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/scripts/ChangeAtZ.py b/plugins/PostProcessingPlugin/scripts/ChangeAtZ.py index 919b06d28e..be9f93c0f6 100644 --- a/plugins/PostProcessingPlugin/scripts/ChangeAtZ.py +++ b/plugins/PostProcessingPlugin/scripts/ChangeAtZ.py @@ -112,7 +112,7 @@ class ChangeAtZ(Script): "e1_Change_speed": { "label": "Change Speed", - "description": "Select if total speed (print and travel) has to be cahnged", + "description": "Select if total speed (print and travel) has to be changed", "type": "bool", "default_value": false }, diff --git a/plugins/PostProcessingPlugin/scripts/ExampleScript.md b/plugins/PostProcessingPlugin/scripts/ExampleScript.md new file mode 100644 index 0000000000..08652132aa --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/ExampleScript.md @@ -0,0 +1,3 @@ +A good example script is SearchAndReplace.py. +If you have any questions please ask them at: +https://github.com/Ultimaker/Cura/issues \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/scripts/ExampleScript.py b/plugins/PostProcessingPlugin/scripts/ExampleScript.py deleted file mode 100644 index 416a5f5404..0000000000 --- a/plugins/PostProcessingPlugin/scripts/ExampleScript.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2015 Jaime van Kessel, Ultimaker B.V. -# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. -from ..Script import Script - -class ExampleScript(Script): - def __init__(self): - super().__init__() - - def getSettingDataString(self): - return """{ - "name":"Example script", - "key": "ExampleScript", - "metadata": {}, - "version": 2, - "settings": - { - "test": - { - "label": "Test", - "description": "None", - "unit": "mm", - "type": "float", - "default_value": 0.5, - "minimum_value": "0", - "minimum_value_warning": "0.1", - "maximum_value_warning": "1" - }, - "derp": - { - "label": "zomg", - "description": "afgasgfgasfgasf", - "unit": "mm", - "type": "float", - "default_value": 0.5, - "minimum_value": "0", - "minimum_value_warning": "0.1", - "maximum_value_warning": "1" - } - } - }""" - - def execute(self, data): - return data \ No newline at end of file diff --git a/plugins/PrepareStage/PrepareMenu.qml b/plugins/PrepareStage/PrepareMenu.qml new file mode 100644 index 0000000000..b62d65254d --- /dev/null +++ b/plugins/PrepareStage/PrepareMenu.qml @@ -0,0 +1,134 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 + +import UM 1.3 as UM +import Cura 1.1 as Cura + +import QtGraphicalEffects 1.0 // For the dropshadow + +Item +{ + id: prepareMenu + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + // Item to ensure that all of the buttons are nicely centered. + Item + { + anchors.horizontalCenter: parent.horizontalCenter + width: openFileButton.width + itemRow.width + UM.Theme.getSize("default_margin").width + height: parent.height + + RowLayout + { + id: itemRow + + anchors.left: openFileButton.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + + width: Math.round(0.9 * prepareMenu.width) + height: parent.height + spacing: 0 + + Cura.MachineSelector + { + id: machineSelection + headerCornerSide: Cura.RoundedRectangle.Direction.Left + Layout.minimumWidth: UM.Theme.getSize("machine_selector_widget").width + Layout.maximumWidth: UM.Theme.getSize("machine_selector_widget").width + Layout.fillWidth: true + Layout.fillHeight: true + } + + // Separator line + Rectangle + { + height: parent.height + width: UM.Theme.getSize("default_lining").width + color: UM.Theme.getColor("lining") + } + + Cura.ConfigurationMenu + { + Layout.fillHeight: true + Layout.fillWidth: true + Layout.preferredWidth: itemRow.width - machineSelection.width - printSetupSelectorItem.width - 2 * UM.Theme.getSize("default_lining").width + } + + // Separator line + Rectangle + { + height: parent.height + width: UM.Theme.getSize("default_lining").width + color: UM.Theme.getColor("lining") + } + + Item + { + id: printSetupSelectorItem + // This is a work around to prevent the printSetupSelector from having to be re-loaded every time + // a stage switch is done. + children: [printSetupSelector] + height: childrenRect.height + width: childrenRect.width + } + } + + Button + { + id: openFileButton + height: UM.Theme.getSize("stage_menu").height + width: UM.Theme.getSize("stage_menu").height + onClicked: Cura.Actions.open.trigger() + hoverEnabled: true + + contentItem: Item + { + anchors.fill: parent + UM.RecolorImage + { + id: buttonIcon + anchors.centerIn: parent + source: UM.Theme.getIcon("load") + width: UM.Theme.getSize("button_icon").width + height: UM.Theme.getSize("button_icon").height + color: UM.Theme.getColor("icon") + + sourceSize.height: height + } + } + + background: Rectangle + { + id: background + height: UM.Theme.getSize("stage_menu").height + width: UM.Theme.getSize("stage_menu").height + + radius: UM.Theme.getSize("default_radius").width + color: openFileButton.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") + } + + DropShadow + { + id: shadow + // Don't blur the shadow + radius: 0 + anchors.fill: background + source: background + verticalOffset: 2 + visible: true + color: UM.Theme.getColor("action_button_shadow") + // Should always be drawn behind the background. + z: background.z - 1 + } + } + } +} diff --git a/plugins/PrepareStage/PrepareStage.py b/plugins/PrepareStage/PrepareStage.py index c3c9f0a1f8..b0f862dc48 100644 --- a/plugins/PrepareStage/PrepareStage.py +++ b/plugins/PrepareStage/PrepareStage.py @@ -1,19 +1,19 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import os.path from UM.Application import Application +from UM.PluginRegistry import PluginRegistry from UM.Resources import Resources from cura.Stages.CuraStage import CuraStage + ## Stage for preparing model (slicing). class PrepareStage(CuraStage): - def __init__(self, parent = None): super().__init__(parent) Application.getInstance().engineCreatedSignal.connect(self._engineCreated) def _engineCreated(self): - sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles), - "PrepareSidebar.qml") - self.addDisplayComponent("sidebar", sidebar_component_path) + menu_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("PrepareStage"), "PrepareMenu.qml") + self.addDisplayComponent("menu", menu_component_path) diff --git a/plugins/PrepareStage/plugin.json b/plugins/PrepareStage/plugin.json index f0464313c7..dc5c68ce16 100644 --- a/plugins/PrepareStage/plugin.json +++ b/plugins/PrepareStage/plugin.json @@ -1,8 +1,8 @@ { "name": "Prepare Stage", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides a prepare stage in Cura.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } \ No newline at end of file diff --git a/plugins/PreviewStage/PreviewMain.qml b/plugins/PreviewStage/PreviewMain.qml new file mode 100644 index 0000000000..04241783e9 --- /dev/null +++ b/plugins/PreviewStage/PreviewMain.qml @@ -0,0 +1,18 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.4 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls.Styles 1.1 + +import UM 1.0 as UM +import Cura 1.0 as Cura + + +Loader +{ + id: previewMain + + source: UM.Controller.activeView != null && UM.Controller.activeView.mainComponent != null ? UM.Controller.activeView.mainComponent : "" +} \ No newline at end of file diff --git a/plugins/PreviewStage/PreviewMenu.qml b/plugins/PreviewStage/PreviewMenu.qml new file mode 100644 index 0000000000..62f814aac9 --- /dev/null +++ b/plugins/PreviewStage/PreviewMenu.qml @@ -0,0 +1,79 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 + +import UM 1.3 as UM +import Cura 1.1 as Cura + +Item +{ + id: previewMenu + + property real itemHeight: height - 2 * UM.Theme.getSize("default_lining").width + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + Row + { + id: stageMenuRow + anchors.centerIn: parent + height: parent.height + width: childrenRect.width + + // We want this row to have a preferred with equals to the 85% of the parent + property int preferredWidth: Math.round(0.85 * previewMenu.width) + + Cura.ViewsSelector + { + id: viewsSelector + height: parent.height + width: UM.Theme.getSize("views_selector").width + headerCornerSide: Cura.RoundedRectangle.Direction.Left + } + + // Separator line + Rectangle + { + height: parent.height + // If there is no viewPanel, we only need a single spacer, so hide this one. + visible: viewPanel.source != "" + width: visible ? UM.Theme.getSize("default_lining").width : 0 + + color: UM.Theme.getColor("lining") + } + + // This component will grow freely up to complete the preferredWidth of the row. + Loader + { + id: viewPanel + height: parent.height + width: source != "" ? (stageMenuRow.preferredWidth - viewsSelector.width - printSetupSelectorItem.width - 2 * UM.Theme.getSize("default_lining").width) : 0 + source: UM.Controller.activeView != null && UM.Controller.activeView.stageMenuComponent != null ? UM.Controller.activeView.stageMenuComponent : "" + } + + // Separator line + Rectangle + { + height: parent.height + width: UM.Theme.getSize("default_lining").width + color: UM.Theme.getColor("lining") + } + + Item + { + id: printSetupSelectorItem + // This is a work around to prevent the printSetupSelector from having to be re-loaded every time + // a stage switch is done. + children: [printSetupSelector] + height: childrenRect.height + width: childrenRect.width + } + } +} diff --git a/plugins/PreviewStage/PreviewStage.py b/plugins/PreviewStage/PreviewStage.py new file mode 100644 index 0000000000..1c487c8340 --- /dev/null +++ b/plugins/PreviewStage/PreviewStage.py @@ -0,0 +1,51 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import os.path + +from UM.Qt.QtApplication import QtApplication +from cura.Stages.CuraStage import CuraStage + +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from UM.View.View import View + + +## Displays a preview of what you're about to print. +# +# The Python component of this stage just loads PreviewMain.qml for display +# when the stage is selected, and makes sure that it reverts to the previous +# view when the previous stage is activated. +class PreviewStage(CuraStage): + def __init__(self, application: QtApplication, parent = None) -> None: + super().__init__(parent) + self._application = application + self._application.engineCreatedSignal.connect(self._engineCreated) + self._previously_active_view = None # type: Optional[View] + + ## When selecting the stage, remember which was the previous view so that + # we can revert to that view when we go out of the stage later. + def onStageSelected(self) -> None: + self._previously_active_view = self._application.getController().getActiveView() + + ## Called when going to a different stage (away from the Preview Stage). + # + # When going to a different stage, the view should be reverted to what it + # was before. Normally, that just reverts it to solid view. + def onStageDeselected(self) -> None: + if self._previously_active_view is not None: + self._application.getController().setActiveView(self._previously_active_view.getPluginId()) + self._previously_active_view = None + + ## Delayed load of the QML files. + # + # We need to make sure that the QML engine is running before we can load + # these. + def _engineCreated(self) -> None: + plugin_path = self._application.getPluginRegistry().getPluginPath(self.getPluginId()) + if plugin_path is not None: + menu_component_path = os.path.join(plugin_path, "PreviewMenu.qml") + main_component_path = os.path.join(plugin_path, "PreviewMain.qml") + self.addDisplayComponent("menu", menu_component_path) + self.addDisplayComponent("main", main_component_path) diff --git a/plugins/PreviewStage/__init__.py b/plugins/PreviewStage/__init__.py new file mode 100644 index 0000000000..424f573e4a --- /dev/null +++ b/plugins/PreviewStage/__init__.py @@ -0,0 +1,22 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from . import PreviewStage + +from UM.i18n import i18nCatalog +i18n_catalog = i18nCatalog("cura") + + +def getMetaData(): + return { + "stage": { + "name": i18n_catalog.i18nc("@item:inmenu", "Preview"), + "weight": 1 + } + } + + +def register(app): + return { + "stage": PreviewStage.PreviewStage(app) + } diff --git a/plugins/PreviewStage/plugin.json b/plugins/PreviewStage/plugin.json new file mode 100644 index 0000000000..e1e4288bae --- /dev/null +++ b/plugins/PreviewStage/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Preview Stage", + "author": "Ultimaker B.V.", + "version": "1.0.1", + "description": "Provides a preview stage in Cura.", + "api": "6.0", + "i18n-catalog": "cura" +} \ No newline at end of file diff --git a/plugins/RemovableDriveOutputDevice/plugin.json b/plugins/RemovableDriveOutputDevice/plugin.json index 36bb9ae186..5523d6b1c1 100644 --- a/plugins/RemovableDriveOutputDevice/plugin.json +++ b/plugins/RemovableDriveOutputDevice/plugin.json @@ -2,7 +2,7 @@ "name": "Removable Drive Output Device Plugin", "author": "Ultimaker B.V.", "description": "Provides removable drive hotplugging and writing support.", - "version": "1.0.0", - "api": 5, + "version": "1.0.1", + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/SimulationView/LayerSlider.qml b/plugins/SimulationView/LayerSlider.qml index 1552506969..88f298d1f5 100644 --- a/plugins/SimulationView/LayerSlider.qml +++ b/plugins/SimulationView/LayerSlider.qml @@ -13,23 +13,20 @@ Item { id: sliderRoot - // handle properties - property real handleSize: 10 + // Handle properties + property real handleSize: UM.Theme.getSize("slider_handle").width property real handleRadius: handleSize / 2 property real minimumRangeHandleSize: handleSize / 2 - property color upperHandleColor: "black" - property color lowerHandleColor: "black" - property color rangeHandleColor: "black" - property color handleActiveColor: "white" - property real handleLabelWidth: width + property color upperHandleColor: UM.Theme.getColor("slider_handle") + property color lowerHandleColor: UM.Theme.getColor("slider_handle") + property color rangeHandleColor: UM.Theme.getColor("slider_groove_fill") + property color handleActiveColor: UM.Theme.getColor("slider_handle_active") property var activeHandle: upperHandle - // track properties - property real trackThickness: 4 // width of the slider track - property real trackRadius: trackThickness / 2 - property color trackColor: "white" - property real trackBorderWidth: 1 // width of the slider track border - property color trackBorderColor: "black" + // Track properties + property real trackThickness: UM.Theme.getSize("slider_groove").width // width of the slider track + property real trackRadius: UM.Theme.getSize("slider_groove_radius").width + property color trackColor: UM.Theme.getColor("slider_groove") // value properties property real maximumValue: 100 @@ -80,7 +77,7 @@ Item return Math.min(Math.max(value, sliderRoot.minimumValue), sliderRoot.maximumValue) } - // slider track + // Slider track Rectangle { id: track @@ -90,8 +87,6 @@ Item radius: sliderRoot.trackRadius anchors.centerIn: sliderRoot color: sliderRoot.trackColor - border.width: sliderRoot.trackBorderWidth - border.color: sliderRoot.trackBorderColor visible: sliderRoot.layersVisible } @@ -106,7 +101,7 @@ Item anchors.horizontalCenter: sliderRoot.horizontalCenter visible: sliderRoot.layersVisible - // set the new value when dragging + // Set the new value when dragging function onHandleDragged() { sliderRoot.manuallyChanged = true @@ -140,9 +135,10 @@ Item Rectangle { - width: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth + width: sliderRoot.trackThickness height: parent.height + sliderRoot.handleSize anchors.centerIn: parent + radius: sliderRoot.trackRadius color: sliderRoot.rangeHandleColor } @@ -275,7 +271,7 @@ Item id: upperHandleLabel height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height - x: parent.x - width - UM.Theme.getSize("default_margin").width + x: parent.x - parent.width - width anchors.verticalCenter: parent.verticalCenter target: Qt.point(sliderRoot.width, y + height / 2) visible: sliderRoot.activeHandle == parent @@ -385,9 +381,9 @@ Item id: lowerHandleLabel height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height - x: parent.x - width - UM.Theme.getSize("default_margin").width + x: parent.x - parent.width - width anchors.verticalCenter: parent.verticalCenter - target: Qt.point(sliderRoot.width, y + height / 2) + target: Qt.point(sliderRoot.width + width, y + height / 2) visible: sliderRoot.activeHandle == parent // custom properties diff --git a/plugins/SimulationView/PathSlider.qml b/plugins/SimulationView/PathSlider.qml index f3c28fb5f7..c7a43c6407 100644 --- a/plugins/SimulationView/PathSlider.qml +++ b/plugins/SimulationView/PathSlider.qml @@ -14,19 +14,17 @@ Item id: sliderRoot // handle properties - property real handleSize: 10 + property real handleSize: UM.Theme.getSize("slider_handle").width property real handleRadius: handleSize / 2 - property color handleColor: "black" - property color handleActiveColor: "white" - property color rangeColor: "black" + property color handleColor: UM.Theme.getColor("slider_handle") + property color handleActiveColor: UM.Theme.getColor("slider_handle_active") + property color rangeColor: UM.Theme.getColor("slider_groove_fill") property real handleLabelWidth: width // track properties - property real trackThickness: 4 // width of the slider track - property real trackRadius: trackThickness / 2 - property color trackColor: "white" - property real trackBorderWidth: 1 // width of the slider track border - property color trackBorderColor: "black" + property real trackThickness: UM.Theme.getSize("slider_groove").width + property real trackRadius: UM.Theme.getSize("slider_groove_radius").width + property color trackColor: UM.Theme.getColor("slider_groove") // value properties property real maximumValue: 100 @@ -68,8 +66,6 @@ Item radius: sliderRoot.trackRadius anchors.centerIn: sliderRoot color: sliderRoot.trackColor - border.width: sliderRoot.trackBorderWidth - border.color: sliderRoot.trackBorderColor visible: sliderRoot.pathsVisible } @@ -86,9 +82,10 @@ Item Rectangle { - height: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth + height: sliderRoot.trackThickness width: parent.width + sliderRoot.handleSize anchors.centerIn: parent + radius: sliderRoot.trackRadius color: sliderRoot.rangeColor } } diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 0ae8b4d9e4..3b2db2efac 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -16,6 +16,7 @@ from UM.Mesh.MeshBuilder import MeshBuilder from UM.Message import Message from UM.Platform import Platform from UM.PluginRegistry import PluginRegistry +from UM.Qt.QtApplication import QtApplication from UM.Resources import Resources from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator @@ -26,8 +27,8 @@ from UM.View.GL.OpenGL import OpenGL from UM.View.GL.OpenGLContext import OpenGLContext from UM.View.GL.ShaderProgram import ShaderProgram -from UM.View.View import View from UM.i18n import i18nCatalog +from cura.CuraView import CuraView from cura.Scene.ConvexHullNode import ConvexHullNode from cura.CuraApplication import CuraApplication @@ -48,15 +49,15 @@ catalog = i18nCatalog("cura") ## View used to display g-code paths. -class SimulationView(View): - # Must match SimulationView.qml +class SimulationView(CuraView): + # Must match SimulationViewMenuComponent.qml LAYER_VIEW_TYPE_MATERIAL_TYPE = 0 LAYER_VIEW_TYPE_LINE_TYPE = 1 LAYER_VIEW_TYPE_FEEDRATE = 2 LAYER_VIEW_TYPE_THICKNESS = 3 - def __init__(self) -> None: - super().__init__() + def __init__(self, parent = None) -> None: + super().__init__(parent) self._max_layers = 0 self._current_layer_num = 0 @@ -113,6 +114,16 @@ class SimulationView(View): self._wireprint_warning_message = Message(catalog.i18nc("@info:status", "Cura does not accurately display layers when Wire Printing is enabled"), title = catalog.i18nc("@info:title", "Simulation View")) + QtApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated) + + def _onEngineCreated(self) -> None: + plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId()) + if plugin_path: + self.addDisplayComponent("main", os.path.join(plugin_path, "SimulationViewMainComponent.qml")) + self.addDisplayComponent("menu", os.path.join(plugin_path, "SimulationViewMenuComponent.qml")) + else: + Logger.log("e", "Unable to find the path for %s", self.getPluginId()) + def _evaluateCompatibilityMode(self) -> bool: return OpenGLContext.isLegacyOpenGL() or bool(Application.getInstance().getPreferences().getValue("view/force_layer_view_compatibility_mode")) @@ -331,12 +342,16 @@ class SimulationView(View): return self._extruder_count def getMinFeedrate(self) -> float: + if abs(self._min_feedrate - sys.float_info.max) < 10: # Some lenience due to floating point rounding. + return 0.0 # If it's still max-float, there are no measurements. Use 0 then. return self._min_feedrate def getMaxFeedrate(self) -> float: return self._max_feedrate def getMinThickness(self) -> float: + if abs(self._min_thickness - sys.float_info.max) < 10: # Some lenience due to floating point rounding. + return 0.0 # If it's still max-float, there are no measurements. Use 0 then. return self._min_thickness def getMaxThickness(self) -> float: diff --git a/plugins/SimulationView/SimulationView.qml b/plugins/SimulationView/SimulationView.qml deleted file mode 100644 index be124157fb..0000000000 --- a/plugins/SimulationView/SimulationView.qml +++ /dev/null @@ -1,808 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.4 -import QtQuick.Controls 1.2 -import QtQuick.Layouts 1.1 -import QtQuick.Controls.Styles 1.1 - -import UM 1.0 as UM -import Cura 1.0 as Cura - -Item -{ - id: base - width: - { - if (UM.SimulationView.compatibilityMode) - { - return UM.Theme.getSize("layerview_menu_size_compatibility").width; - } - else - { - return UM.Theme.getSize("layerview_menu_size").width; - } - } - height: { - if (viewSettings.collapsed) - { - if (UM.SimulationView.compatibilityMode) - { - return UM.Theme.getSize("layerview_menu_size_compatibility_collapsed").height; - } - return UM.Theme.getSize("layerview_menu_size_collapsed").height; - } - else if (UM.SimulationView.compatibilityMode) - { - return UM.Theme.getSize("layerview_menu_size_compatibility").height; - } - else if (UM.Preferences.getValue("layerview/layer_view_type") == 0) - { - return UM.Theme.getSize("layerview_menu_size_material_color_mode").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height) - } - else - { - return UM.Theme.getSize("layerview_menu_size").height + UM.SimulationView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height) - } - } - Behavior on height { NumberAnimation { duration: 100 } } - - property var buttonTarget: - { - if(parent != null) - { - var force_binding = parent.y; // ensure this gets reevaluated when the panel moves - return base.mapFromItem(parent.parent, parent.buttonTarget.x, parent.buttonTarget.y) - } - return Qt.point(0,0) - } - - Rectangle - { - id: layerViewMenu - anchors.right: parent.right - anchors.top: parent.top - width: parent.width - height: parent.height - clip: true - z: layerSlider.z - 1 - color: UM.Theme.getColor("tool_panel_background") - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - - Button { - id: collapseButton - anchors.top: parent.top - anchors.topMargin: Math.round(UM.Theme.getSize("default_margin").height + (UM.Theme.getSize("layerview_row").height - UM.Theme.getSize("default_margin").height) / 2) - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height - - onClicked: viewSettings.collapsed = !viewSettings.collapsed - - style: ButtonStyle - { - background: UM.RecolorImage - { - width: control.width - height: control.height - sourceSize.width: width - sourceSize.height: width - color: UM.Theme.getColor("setting_control_text") - source: viewSettings.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom") - } - label: Label{ } - } - } - - ColumnLayout - { - id: viewSettings - - property bool collapsed: false - property var extruder_opacities: UM.Preferences.getValue("layerview/extruder_opacities").split("|") - property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves") - property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers") - property bool show_skin: UM.Preferences.getValue("layerview/show_skin") - property bool show_infill: UM.Preferences.getValue("layerview/show_infill") - // if we are in compatibility mode, we only show the "line type" - property bool show_legend: UM.SimulationView.compatibilityMode ? true : UM.Preferences.getValue("layerview/layer_view_type") == 1 - property bool show_gradient: UM.SimulationView.compatibilityMode ? false : UM.Preferences.getValue("layerview/layer_view_type") == 2 || UM.Preferences.getValue("layerview/layer_view_type") == 3 - property bool show_feedrate_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 2 - property bool show_thickness_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 3 - property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers") - property int top_layer_count: UM.Preferences.getValue("view/top_layer_count") - - anchors.top: parent.top - anchors.topMargin: UM.Theme.getSize("default_margin").height - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - spacing: UM.Theme.getSize("layerview_row_spacing").height - - Label - { - id: layerViewTypesLabel - anchors.left: parent.left - text: catalog.i18nc("@label","Color scheme") - font: UM.Theme.getFont("default"); - visible: !UM.SimulationView.compatibilityMode - Layout.fillWidth: true - color: UM.Theme.getColor("setting_control_text") - } - - ListModel // matches SimulationView.py - { - id: layerViewTypes - } - - Component.onCompleted: - { - layerViewTypes.append({ - text: catalog.i18nc("@label:listbox", "Material Color"), - type_id: 0 - }) - layerViewTypes.append({ - text: catalog.i18nc("@label:listbox", "Line Type"), - type_id: 1 - }) - layerViewTypes.append({ - text: catalog.i18nc("@label:listbox", "Feedrate"), - type_id: 2 - }) - layerViewTypes.append({ - text: catalog.i18nc("@label:listbox", "Layer thickness"), - type_id: 3 // these ids match the switching in the shader - }) - } - - ComboBox - { - id: layerTypeCombobox - anchors.left: parent.left - Layout.fillWidth: true - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - model: layerViewTypes - visible: !UM.SimulationView.compatibilityMode - style: UM.Theme.styles.combobox - anchors.right: parent.right - - onActivated: - { - UM.Preferences.setValue("layerview/layer_view_type", index); - } - - Component.onCompleted: - { - currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type"); - updateLegends(currentIndex); - } - - function updateLegends(type_id) - { - // update visibility of legends - viewSettings.show_legend = UM.SimulationView.compatibilityMode || (type_id == 1); - viewSettings.show_gradient = !UM.SimulationView.compatibilityMode && (type_id == 2 || type_id == 3); - viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2); - viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3); - } - } - - Label - { - id: compatibilityModeLabel - anchors.left: parent.left - text: catalog.i18nc("@label","Compatibility Mode") - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - visible: UM.SimulationView.compatibilityMode - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - } - - Item - { - height: Math.round(UM.Theme.getSize("default_margin").width / 2) - width: width - } - - Connections - { - target: UM.Preferences - onPreferenceChanged: - { - layerTypeCombobox.currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type"); - layerTypeCombobox.updateLegends(layerTypeCombobox.currentIndex); - playButton.pauseSimulation(); - viewSettings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|"); - viewSettings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves"); - viewSettings.show_helpers = UM.Preferences.getValue("layerview/show_helpers"); - viewSettings.show_skin = UM.Preferences.getValue("layerview/show_skin"); - viewSettings.show_infill = UM.Preferences.getValue("layerview/show_infill"); - viewSettings.only_show_top_layers = UM.Preferences.getValue("view/only_show_top_layers"); - viewSettings.top_layer_count = UM.Preferences.getValue("view/top_layer_count"); - } - } - - Repeater - { - model: Cura.ExtrudersModel{} - CheckBox - { - id: extrudersModelCheckBox - checked: viewSettings.extruder_opacities[index] > 0.5 || viewSettings.extruder_opacities[index] == undefined || viewSettings.extruder_opacities[index] == "" - onClicked: - { - viewSettings.extruder_opacities[index] = checked ? 1.0 : 0.0 - UM.Preferences.setValue("layerview/extruder_opacities", viewSettings.extruder_opacities.join("|")); - } - visible: !UM.SimulationView.compatibilityMode - enabled: index + 1 <= 4 - Rectangle - { - anchors.verticalCenter: parent.verticalCenter - anchors.right: extrudersModelCheckBox.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: model.color - radius: Math.round(width / 2) - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - visible: !viewSettings.show_legend & !viewSettings.show_gradient - } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - style: UM.Theme.styles.checkbox - Label - { - text: model.name - elide: Text.ElideRight - color: UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default") - anchors.verticalCenter: parent.verticalCenter - anchors.left: extrudersModelCheckBox.left; - anchors.right: extrudersModelCheckBox.right; - anchors.leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width/2) - anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2 - } - } - } - - Repeater - { - model: ListModel - { - id: typesLegendModel - Component.onCompleted: - { - typesLegendModel.append({ - label: catalog.i18nc("@label", "Show Travels"), - initialValue: viewSettings.show_travel_moves, - preference: "layerview/show_travel_moves", - colorId: "layerview_move_combing" - }); - typesLegendModel.append({ - label: catalog.i18nc("@label", "Show Helpers"), - initialValue: viewSettings.show_helpers, - preference: "layerview/show_helpers", - colorId: "layerview_support" - }); - typesLegendModel.append({ - label: catalog.i18nc("@label", "Show Shell"), - initialValue: viewSettings.show_skin, - preference: "layerview/show_skin", - colorId: "layerview_inset_0" - }); - typesLegendModel.append({ - label: catalog.i18nc("@label", "Show Infill"), - initialValue: viewSettings.show_infill, - preference: "layerview/show_infill", - colorId: "layerview_infill" - }); - } - } - - CheckBox - { - id: legendModelCheckBox - checked: model.initialValue - onClicked: - { - UM.Preferences.setValue(model.preference, checked); - } - Rectangle - { - anchors.verticalCenter: parent.verticalCenter - anchors.right: legendModelCheckBox.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: UM.Theme.getColor(model.colorId) - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - visible: viewSettings.show_legend - } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - style: UM.Theme.styles.checkbox - Label - { - text: label - font: UM.Theme.getFont("default") - elide: Text.ElideRight - color: UM.Theme.getColor("setting_control_text") - anchors.verticalCenter: parent.verticalCenter - anchors.left: legendModelCheckBox.left; - anchors.right: legendModelCheckBox.right; - anchors.leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width/2) - anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2 - } - } - } - - CheckBox - { - checked: viewSettings.only_show_top_layers - onClicked: - { - UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0); - } - text: catalog.i18nc("@label", "Only Show Top Layers") - visible: UM.SimulationView.compatibilityMode - style: UM.Theme.styles.checkbox - } - CheckBox - { - checked: viewSettings.top_layer_count == 5 - onClicked: - { - UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1); - } - text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top") - visible: UM.SimulationView.compatibilityMode - style: UM.Theme.styles.checkbox - } - - Repeater - { - model: ListModel - { - id: typesLegendModelNoCheck - Component.onCompleted: - { - typesLegendModelNoCheck.append({ - label: catalog.i18nc("@label", "Top / Bottom"), - colorId: "layerview_skin", - }); - typesLegendModelNoCheck.append({ - label: catalog.i18nc("@label", "Inner Wall"), - colorId: "layerview_inset_x", - }); - } - } - - Label - { - text: label - visible: viewSettings.show_legend - id: typesLegendModelLabel - Rectangle - { - anchors.verticalCenter: parent.verticalCenter - anchors.right: typesLegendModelLabel.right - width: UM.Theme.getSize("layerview_legend_size").width - height: UM.Theme.getSize("layerview_legend_size").height - color: UM.Theme.getColor(model.colorId) - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - visible: viewSettings.show_legend - } - Layout.fillWidth: true - Layout.preferredHeight: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height - Layout.preferredWidth: UM.Theme.getSize("layerview_row").width - color: UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default") - } - } - - // Text for the minimum, maximum and units for the feedrates and layer thickness - Item - { - id: gradientLegend - visible: viewSettings.show_gradient - width: parent.width - height: UM.Theme.getSize("layerview_row").height - anchors - { - topMargin: UM.Theme.getSize("slider_layerview_margin").height - horizontalCenter: parent.horizontalCenter - } - - Label - { - text: minText() - anchors.left: parent.left - color: UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default") - - function minText() - { - if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) - { - // Feedrate selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 2) - { - return parseFloat(UM.SimulationView.getMinFeedrate()).toFixed(2) - } - // Layer thickness selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 3) - { - return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2) - } - } - return catalog.i18nc("@label","min") - } - } - - Label - { - text: unitsText() - anchors.horizontalCenter: parent.horizontalCenter - color: UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default") - - function unitsText() - { - if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) - { - // Feedrate selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 2) - { - return "mm/s" - } - // Layer thickness selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 3) - { - return "mm" - } - } - return "" - } - } - - Label - { - text: maxText() - anchors.right: parent.right - color: UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default") - - function maxText() - { - if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) - { - // Feedrate selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 2) - { - return parseFloat(UM.SimulationView.getMaxFeedrate()).toFixed(2) - } - // Layer thickness selected - if (UM.Preferences.getValue("layerview/layer_view_type") == 3) - { - return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2) - } - } - return catalog.i18nc("@label","max") - } - } - } - - // Gradient colors for feedrate - Rectangle - { // In QML 5.9 can be changed by LinearGradient - // Invert values because then the bar is rotated 90 degrees - id: feedrateGradient - visible: viewSettings.show_feedrate_gradient - anchors.left: parent.right - height: parent.width - width: Math.round(UM.Theme.getSize("layerview_row").height * 1.5) - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - transform: Rotation {origin.x: 0; origin.y: 0; angle: 90} - gradient: Gradient - { - GradientStop - { - position: 0.000 - color: Qt.rgba(1, 0.5, 0, 1) - } - GradientStop - { - position: 0.625 - color: Qt.rgba(0.375, 0.5, 0, 1) - } - GradientStop - { - position: 0.75 - color: Qt.rgba(0.25, 1, 0, 1) - } - GradientStop - { - position: 1.0 - color: Qt.rgba(0, 0, 1, 1) - } - } - } - - // Gradient colors for layer thickness (similar to parula colormap) - Rectangle // In QML 5.9 can be changed by LinearGradient - { - // Invert values because then the bar is rotated 90 degrees - id: thicknessGradient - visible: viewSettings.show_thickness_gradient - anchors.left: parent.right - height: parent.width - width: Math.round(UM.Theme.getSize("layerview_row").height * 1.5) - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - transform: Rotation {origin.x: 0; origin.y: 0; angle: 90} - gradient: Gradient - { - GradientStop - { - position: 0.000 - color: Qt.rgba(1, 1, 0, 1) - } - GradientStop - { - position: 0.25 - color: Qt.rgba(1, 0.75, 0.25, 1) - } - GradientStop - { - position: 0.5 - color: Qt.rgba(0, 0.75, 0.5, 1) - } - GradientStop - { - position: 0.75 - color: Qt.rgba(0, 0.375, 0.75, 1) - } - GradientStop - { - position: 1.0 - color: Qt.rgba(0, 0, 0.5, 1) - } - } - } - } - } - - Item - { - id: slidersBox - - width: parent.width - visible: UM.SimulationView.layerActivity && CuraApplication.platformActivity - - anchors - { - top: parent.bottom - topMargin: UM.Theme.getSize("slider_layerview_margin").height - left: parent.left - } - - PathSlider - { - id: pathSlider - - height: UM.Theme.getSize("slider_handle").width - anchors.left: playButton.right - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.right: parent.right - visible: !UM.SimulationView.compatibilityMode - - // custom properties - handleValue: UM.SimulationView.currentPath - maximumValue: UM.SimulationView.numPaths - handleSize: UM.Theme.getSize("slider_handle").width - trackThickness: UM.Theme.getSize("slider_groove").width - trackColor: UM.Theme.getColor("slider_groove") - trackBorderColor: UM.Theme.getColor("slider_groove_border") - handleColor: UM.Theme.getColor("slider_handle") - handleActiveColor: UM.Theme.getColor("slider_handle_active") - rangeColor: UM.Theme.getColor("slider_groove_fill") - - // update values when layer data changes - Connections - { - target: UM.SimulationView - onMaxPathsChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath) - onCurrentPathChanged: - { - // Only pause the simulation when the layer was changed manually, not when the simulation is running - if (pathSlider.manuallyChanged) - { - playButton.pauseSimulation() - } - pathSlider.setHandleValue(UM.SimulationView.currentPath) - } - } - - // make sure the slider handlers show the correct value after switching views - Component.onCompleted: - { - pathSlider.setHandleValue(UM.SimulationView.currentPath) - } - } - - LayerSlider - { - id: layerSlider - - width: UM.Theme.getSize("slider_handle").width - height: UM.Theme.getSize("layerview_menu_size").height - - anchors - { - top: !UM.SimulationView.compatibilityMode ? pathSlider.bottom : parent.top - topMargin: !UM.SimulationView.compatibilityMode ? UM.Theme.getSize("default_margin").height : 0 - right: parent.right - rightMargin: UM.Theme.getSize("slider_layerview_margin").width - } - - // custom properties - upperValue: UM.SimulationView.currentLayer - lowerValue: UM.SimulationView.minimumLayer - maximumValue: UM.SimulationView.numLayers - handleSize: UM.Theme.getSize("slider_handle").width - trackThickness: UM.Theme.getSize("slider_groove").width - trackColor: UM.Theme.getColor("slider_groove") - trackBorderColor: UM.Theme.getColor("slider_groove_border") - upperHandleColor: UM.Theme.getColor("slider_handle") - lowerHandleColor: UM.Theme.getColor("slider_handle") - rangeHandleColor: UM.Theme.getColor("slider_groove_fill") - handleActiveColor: UM.Theme.getColor("slider_handle_active") - handleLabelWidth: UM.Theme.getSize("slider_layerview_background").width - - // update values when layer data changes - Connections - { - target: UM.SimulationView - onMaxLayersChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer) - onMinimumLayerChanged: layerSlider.setLowerValue(UM.SimulationView.minimumLayer) - onCurrentLayerChanged: - { - // Only pause the simulation when the layer was changed manually, not when the simulation is running - if (layerSlider.manuallyChanged) - { - playButton.pauseSimulation() - } - layerSlider.setUpperValue(UM.SimulationView.currentLayer) - } - } - - // make sure the slider handlers show the correct value after switching views - Component.onCompleted: - { - layerSlider.setLowerValue(UM.SimulationView.minimumLayer) - layerSlider.setUpperValue(UM.SimulationView.currentLayer) - } - } - - // Play simulation button - Button - { - id: playButton - iconSource: "./resources/simulation_resume.svg" - style: UM.Theme.styles.small_tool_button - visible: !UM.SimulationView.compatibilityMode - anchors - { - verticalCenter: pathSlider.verticalCenter - } - - property var status: 0 // indicates if it's stopped (0) or playing (1) - - onClicked: - { - switch(status) - { - case 0: - { - resumeSimulation() - break - } - case 1: - { - pauseSimulation() - break - } - } - } - - function pauseSimulation() - { - UM.SimulationView.setSimulationRunning(false) - iconSource = "./resources/simulation_resume.svg" - simulationTimer.stop() - status = 0 - layerSlider.manuallyChanged = true - pathSlider.manuallyChanged = true - } - - function resumeSimulation() - { - UM.SimulationView.setSimulationRunning(true) - iconSource = "./resources/simulation_pause.svg" - simulationTimer.start() - layerSlider.manuallyChanged = false - pathSlider.manuallyChanged = false - } - } - - Timer - { - id: simulationTimer - interval: 100 - running: false - repeat: true - onTriggered: - { - var currentPath = UM.SimulationView.currentPath - var numPaths = UM.SimulationView.numPaths - var currentLayer = UM.SimulationView.currentLayer - var numLayers = UM.SimulationView.numLayers - // When the user plays the simulation, if the path slider is at the end of this layer, we start - // the simulation at the beginning of the current layer. - if (playButton.status == 0) - { - if (currentPath >= numPaths) - { - UM.SimulationView.setCurrentPath(0) - } - else - { - UM.SimulationView.setCurrentPath(currentPath+1) - } - } - // If the simulation is already playing and we reach the end of a layer, then it automatically - // starts at the beginning of the next layer. - else - { - if (currentPath >= numPaths) - { - // At the end of the model, the simulation stops - if (currentLayer >= numLayers) - { - playButton.pauseSimulation() - } - else - { - UM.SimulationView.setCurrentLayer(currentLayer+1) - UM.SimulationView.setCurrentPath(0) - } - } - else - { - UM.SimulationView.setCurrentPath(currentPath+1) - } - } - // The status must be set here instead of in the resumeSimulation function otherwise it won't work - // correctly, because part of the logic is in this trigger function. - playButton.status = 1 - } - } - } - - FontMetrics - { - id: fontMetrics - font: UM.Theme.getFont("default") - } -} diff --git a/plugins/SimulationView/SimulationViewMainComponent.qml b/plugins/SimulationView/SimulationViewMainComponent.qml new file mode 100644 index 0000000000..16b049c921 --- /dev/null +++ b/plugins/SimulationView/SimulationViewMainComponent.qml @@ -0,0 +1,211 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.4 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls.Styles 1.1 + +import UM 1.4 as UM +import Cura 1.0 as Cura + +Item +{ + property bool is_simulation_playing: false + visible: UM.SimulationView.layerActivity && CuraApplication.platformActivity + + PathSlider + { + id: pathSlider + height: UM.Theme.getSize("slider_handle").width + width: UM.Theme.getSize("slider_layerview_size").height + + anchors.bottom: parent.bottom + anchors.bottomMargin: UM.Theme.getSize("default_margin").height + + anchors.horizontalCenter: parent.horizontalCenter + + visible: !UM.SimulationView.compatibilityMode + + // Custom properties + handleValue: UM.SimulationView.currentPath + maximumValue: UM.SimulationView.numPaths + + // Update values when layer data changes. + Connections + { + target: UM.SimulationView + onMaxPathsChanged: pathSlider.setHandleValue(UM.SimulationView.currentPath) + onCurrentPathChanged: + { + // Only pause the simulation when the layer was changed manually, not when the simulation is running + if (pathSlider.manuallyChanged) + { + playButton.pauseSimulation() + } + pathSlider.setHandleValue(UM.SimulationView.currentPath) + } + } + + // Ensure that the slider handlers show the correct value after switching views. + Component.onCompleted: + { + pathSlider.setHandleValue(UM.SimulationView.currentPath) + } + + } + + UM.SimpleButton + { + id: playButton + iconSource: !is_simulation_playing ? "./resources/simulation_resume.svg": "./resources/simulation_pause.svg" + width: UM.Theme.getSize("small_button").width + height: UM.Theme.getSize("small_button").height + hoverColor: UM.Theme.getColor("slider_handle_active") + color: UM.Theme.getColor("slider_handle") + iconMargin: UM.Theme.getSize("thick_lining").width + visible: !UM.SimulationView.compatibilityMode + + Connections + { + target: UM.Preferences + onPreferenceChanged: + { + playButton.pauseSimulation() + } + } + + anchors + { + right: pathSlider.left + verticalCenter: pathSlider.verticalCenter + } + + onClicked: + { + if(is_simulation_playing) + { + pauseSimulation() + } + else + { + resumeSimulation() + } + } + + function pauseSimulation() + { + UM.SimulationView.setSimulationRunning(false) + simulationTimer.stop() + is_simulation_playing = false + layerSlider.manuallyChanged = true + pathSlider.manuallyChanged = true + } + + function resumeSimulation() + { + UM.SimulationView.setSimulationRunning(true) + simulationTimer.start() + layerSlider.manuallyChanged = false + pathSlider.manuallyChanged = false + } + } + + Timer + { + id: simulationTimer + interval: 100 + running: false + repeat: true + onTriggered: + { + var currentPath = UM.SimulationView.currentPath + var numPaths = UM.SimulationView.numPaths + var currentLayer = UM.SimulationView.currentLayer + var numLayers = UM.SimulationView.numLayers + + // When the user plays the simulation, if the path slider is at the end of this layer, we start + // the simulation at the beginning of the current layer. + if (!is_simulation_playing) + { + if (currentPath >= numPaths) + { + UM.SimulationView.setCurrentPath(0) + } + else + { + UM.SimulationView.setCurrentPath(currentPath + 1) + } + } + // If the simulation is already playing and we reach the end of a layer, then it automatically + // starts at the beginning of the next layer. + else + { + if (currentPath >= numPaths) + { + // At the end of the model, the simulation stops + if (currentLayer >= numLayers) + { + playButton.pauseSimulation() + } + else + { + UM.SimulationView.setCurrentLayer(currentLayer + 1) + UM.SimulationView.setCurrentPath(0) + } + } + else + { + UM.SimulationView.setCurrentPath(currentPath + 1) + } + } + // The status must be set here instead of in the resumeSimulation function otherwise it won't work + // correctly, because part of the logic is in this trigger function. + is_simulation_playing = true + } + } + + LayerSlider + { + id: layerSlider + + width: UM.Theme.getSize("slider_handle").width + height: UM.Theme.getSize("slider_layerview_size").height + + anchors + { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: UM.Theme.getSize("default_margin").width + } + + // Custom properties + upperValue: UM.SimulationView.currentLayer + lowerValue: UM.SimulationView.minimumLayer + maximumValue: UM.SimulationView.numLayers + + // Update values when layer data changes + Connections + { + target: UM.SimulationView + onMaxLayersChanged: layerSlider.setUpperValue(UM.SimulationView.currentLayer) + onMinimumLayerChanged: layerSlider.setLowerValue(UM.SimulationView.minimumLayer) + onCurrentLayerChanged: + { + // Only pause the simulation when the layer was changed manually, not when the simulation is running + if (layerSlider.manuallyChanged) + { + playButton.pauseSimulation() + } + layerSlider.setUpperValue(UM.SimulationView.currentLayer) + } + } + + // Make sure the slider handlers show the correct value after switching views + Component.onCompleted: + { + layerSlider.setLowerValue(UM.SimulationView.minimumLayer) + layerSlider.setUpperValue(UM.SimulationView.currentLayer) + } + } +} \ No newline at end of file diff --git a/plugins/SimulationView/SimulationViewMenuComponent.qml b/plugins/SimulationView/SimulationViewMenuComponent.qml new file mode 100644 index 0000000000..4c952d4c43 --- /dev/null +++ b/plugins/SimulationView/SimulationViewMenuComponent.qml @@ -0,0 +1,551 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.4 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls.Styles 1.1 +import QtGraphicalEffects 1.0 + +import UM 1.0 as UM +import Cura 1.0 as Cura + + +Cura.ExpandableComponent +{ + id: base + + contentHeaderTitle: catalog.i18nc("@label", "Color scheme") + + Connections + { + target: UM.Preferences + onPreferenceChanged: + { + layerTypeCombobox.currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type") + layerTypeCombobox.updateLegends(layerTypeCombobox.currentIndex) + viewSettings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|") + viewSettings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves") + viewSettings.show_helpers = UM.Preferences.getValue("layerview/show_helpers") + viewSettings.show_skin = UM.Preferences.getValue("layerview/show_skin") + viewSettings.show_infill = UM.Preferences.getValue("layerview/show_infill") + viewSettings.only_show_top_layers = UM.Preferences.getValue("view/only_show_top_layers") + viewSettings.top_layer_count = UM.Preferences.getValue("view/top_layer_count") + } + } + + headerItem: Item + { + Label + { + id: colorSchemeLabel + text: catalog.i18nc("@label", "Color scheme") + verticalAlignment: Text.AlignVCenter + height: parent.height + elide: Text.ElideRight + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering + } + + Label + { + text: layerTypeCombobox.currentText + verticalAlignment: Text.AlignVCenter + anchors + { + left: colorSchemeLabel.right + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + } + height: parent.height + elide: Text.ElideRight + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text") + renderType: Text.NativeRendering + } + } + + contentItem: Column + { + id: viewSettings + + property var extruder_opacities: UM.Preferences.getValue("layerview/extruder_opacities").split("|") + property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves") + property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers") + property bool show_skin: UM.Preferences.getValue("layerview/show_skin") + property bool show_infill: UM.Preferences.getValue("layerview/show_infill") + + // If we are in compatibility mode, we only show the "line type" + property bool show_legend: UM.SimulationView.compatibilityMode ? true : UM.Preferences.getValue("layerview/layer_view_type") == 1 + property bool show_gradient: UM.SimulationView.compatibilityMode ? false : UM.Preferences.getValue("layerview/layer_view_type") == 2 || UM.Preferences.getValue("layerview/layer_view_type") == 3 + property bool show_feedrate_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 2 + property bool show_thickness_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 3 + property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers") + property int top_layer_count: UM.Preferences.getValue("view/top_layer_count") + + width: UM.Theme.getSize("layerview_menu_size").width - 2 * UM.Theme.getSize("default_margin").width + height: implicitHeight + + spacing: UM.Theme.getSize("layerview_row_spacing").height + + ListModel // matches SimulationView.py + { + id: layerViewTypes + } + + Component.onCompleted: + { + layerViewTypes.append({ + text: catalog.i18nc("@label:listbox", "Material Color"), + type_id: 0 + }) + layerViewTypes.append({ + text: catalog.i18nc("@label:listbox", "Line Type"), + type_id: 1 + }) + layerViewTypes.append({ + text: catalog.i18nc("@label:listbox", "Feedrate"), + type_id: 2 + }) + layerViewTypes.append({ + text: catalog.i18nc("@label:listbox", "Layer thickness"), + type_id: 3 // these ids match the switching in the shader + }) + } + + ComboBox + { + id: layerTypeCombobox + width: parent.width + model: layerViewTypes + visible: !UM.SimulationView.compatibilityMode + style: UM.Theme.styles.combobox + + onActivated: + { + UM.Preferences.setValue("layerview/layer_view_type", index); + } + + Component.onCompleted: + { + currentIndex = UM.SimulationView.compatibilityMode ? 1 : UM.Preferences.getValue("layerview/layer_view_type"); + updateLegends(currentIndex); + } + + function updateLegends(type_id) + { + // Update the visibility of the legends. + viewSettings.show_legend = UM.SimulationView.compatibilityMode || (type_id == 1); + viewSettings.show_gradient = !UM.SimulationView.compatibilityMode && (type_id == 2 || type_id == 3); + viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2); + viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3); + } + } + + Label + { + id: compatibilityModeLabel + text: catalog.i18nc("@label", "Compatibility Mode") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + visible: UM.SimulationView.compatibilityMode + height: UM.Theme.getSize("layerview_row").height + width: parent.width + renderType: Text.NativeRendering + } + + Item // Spacer + { + height: UM.Theme.getSize("narrow_margin").width + width: width + } + + Repeater + { + model: CuraApplication.getExtrudersModel() + + CheckBox + { + id: extrudersModelCheckBox + checked: viewSettings.extruder_opacities[index] > 0.5 || viewSettings.extruder_opacities[index] == undefined || viewSettings.extruder_opacities[index] == "" + height: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height + width: parent.width + visible: !UM.SimulationView.compatibilityMode + enabled: index < 4 + + onClicked: + { + viewSettings.extruder_opacities[index] = checked ? 1.0 : 0.0 + UM.Preferences.setValue("layerview/extruder_opacities", viewSettings.extruder_opacities.join("|")); + } + + style: UM.Theme.styles.checkbox + + + UM.RecolorImage + { + id: swatch + anchors.verticalCenter: parent.verticalCenter + anchors.right: extrudersModelCheckBox.right + width: UM.Theme.getSize("layerview_legend_size").width + height: UM.Theme.getSize("layerview_legend_size").height + source: UM.Theme.getIcon("extruder_button") + color: model.color + } + + Label + { + text: model.name + elide: Text.ElideRight + color: UM.Theme.getColor("setting_control_text") + font: UM.Theme.getFont("default") + anchors + { + verticalCenter: parent.verticalCenter + left: extrudersModelCheckBox.left + right: extrudersModelCheckBox.right + leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width / 2) + rightMargin: UM.Theme.getSize("default_margin").width * 2 + } + renderType: Text.NativeRendering + } + } + } + + Repeater + { + model: ListModel + { + id: typesLegendModel + Component.onCompleted: + { + typesLegendModel.append({ + label: catalog.i18nc("@label", "Travels"), + initialValue: viewSettings.show_travel_moves, + preference: "layerview/show_travel_moves", + colorId: "layerview_move_combing" + }); + typesLegendModel.append({ + label: catalog.i18nc("@label", "Helpers"), + initialValue: viewSettings.show_helpers, + preference: "layerview/show_helpers", + colorId: "layerview_support" + }); + typesLegendModel.append({ + label: catalog.i18nc("@label", "Shell"), + initialValue: viewSettings.show_skin, + preference: "layerview/show_skin", + colorId: "layerview_inset_0" + }); + typesLegendModel.append({ + label: catalog.i18nc("@label", "Infill"), + initialValue: viewSettings.show_infill, + preference: "layerview/show_infill", + colorId: "layerview_infill" + }); + } + } + + CheckBox + { + id: legendModelCheckBox + checked: model.initialValue + onClicked: UM.Preferences.setValue(model.preference, checked) + height: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height + width: parent.width + + style: UM.Theme.styles.checkbox + + Rectangle + { + anchors.verticalCenter: parent.verticalCenter + anchors.right: legendModelCheckBox.right + width: UM.Theme.getSize("layerview_legend_size").width + height: UM.Theme.getSize("layerview_legend_size").height + color: UM.Theme.getColor(model.colorId) + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + visible: viewSettings.show_legend + } + + Label + { + text: label + font: UM.Theme.getFont("default") + elide: Text.ElideRight + renderType: Text.NativeRendering + color: UM.Theme.getColor("setting_control_text") + anchors.verticalCenter: parent.verticalCenter + anchors.left: legendModelCheckBox.left + anchors.right: legendModelCheckBox.right + anchors.leftMargin: UM.Theme.getSize("checkbox").width + Math.round(UM.Theme.getSize("default_margin").width / 2) + anchors.rightMargin: UM.Theme.getSize("default_margin").width * 2 + } + } + } + + CheckBox + { + checked: viewSettings.only_show_top_layers + onClicked: UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0) + text: catalog.i18nc("@label", "Only Show Top Layers") + visible: UM.SimulationView.compatibilityMode + style: UM.Theme.styles.checkbox + width: parent.width + } + + CheckBox + { + checked: viewSettings.top_layer_count == 5 + onClicked: UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1) + text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top") + width: parent.width + visible: UM.SimulationView.compatibilityMode + style: UM.Theme.styles.checkbox + } + + Repeater + { + model: ListModel + { + id: typesLegendModelNoCheck + Component.onCompleted: + { + typesLegendModelNoCheck.append({ + label: catalog.i18nc("@label", "Top / Bottom"), + colorId: "layerview_skin", + }); + typesLegendModelNoCheck.append({ + label: catalog.i18nc("@label", "Inner Wall"), + colorId: "layerview_inset_x", + }); + } + } + + Label + { + text: label + visible: viewSettings.show_legend + id: typesLegendModelLabel + + height: UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("default_lining").height + width: parent.width + color: UM.Theme.getColor("setting_control_text") + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + Rectangle + { + anchors.verticalCenter: parent.verticalCenter + anchors.right: typesLegendModelLabel.right + + width: UM.Theme.getSize("layerview_legend_size").width + height: UM.Theme.getSize("layerview_legend_size").height + + color: UM.Theme.getColor(model.colorId) + + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + } + } + } + + // Text for the minimum, maximum and units for the feedrates and layer thickness + Item + { + id: gradientLegend + visible: viewSettings.show_gradient + width: parent.width + height: UM.Theme.getSize("layerview_row").height + + Label //Minimum value. + { + text: + { + if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) + { + // Feedrate selected + if (UM.Preferences.getValue("layerview/layer_view_type") == 2) + { + return parseFloat(UM.SimulationView.getMinFeedrate()).toFixed(2) + } + // Layer thickness selected + if (UM.Preferences.getValue("layerview/layer_view_type") == 3) + { + return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2) + } + } + return catalog.i18nc("@label","min") + } + anchors.left: parent.left + color: UM.Theme.getColor("setting_control_text") + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + } + + Label //Unit in the middle. + { + text: + { + if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) + { + // Feedrate selected + if (UM.Preferences.getValue("layerview/layer_view_type") == 2) + { + return "mm/s" + } + // Layer thickness selected + if (UM.Preferences.getValue("layerview/layer_view_type") == 3) + { + return "mm" + } + } + return "" + } + + anchors.horizontalCenter: parent.horizontalCenter + color: UM.Theme.getColor("setting_control_text") + font: UM.Theme.getFont("default") + } + + Label //Maximum value. + { + text: { + if (UM.SimulationView.layerActivity && CuraApplication.platformActivity) + { + // Feedrate selected + if (UM.Preferences.getValue("layerview/layer_view_type") == 2) + { + return parseFloat(UM.SimulationView.getMaxFeedrate()).toFixed(2) + } + // Layer thickness selected + if (UM.Preferences.getValue("layerview/layer_view_type") == 3) + { + return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2) + } + } + return catalog.i18nc("@label","max") + } + + anchors.right: parent.right + color: UM.Theme.getColor("setting_control_text") + font: UM.Theme.getFont("default") + } + } + + // Gradient colors for feedrate + Rectangle + { + id: feedrateGradient + visible: viewSettings.show_feedrate_gradient + anchors.left: parent.left + anchors.right: parent.right + height: Math.round(UM.Theme.getSize("layerview_row").height * 1.5) + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + + LinearGradient + { + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("default_lining").width + right: parent.right + rightMargin: UM.Theme.getSize("default_lining").width + top: parent.top + topMargin: UM.Theme.getSize("default_lining").width + bottom: parent.bottom + bottomMargin: UM.Theme.getSize("default_lining").width + } + start: Qt.point(0, 0) + end: Qt.point(parent.width, 0) + gradient: Gradient + { + GradientStop + { + position: 0.000 + color: Qt.rgba(0, 0, 1, 1) + } + GradientStop + { + position: 0.25 + color: Qt.rgba(0.25, 1, 0, 1) + } + GradientStop + { + position: 0.375 + color: Qt.rgba(0.375, 0.5, 0, 1) + } + GradientStop + { + position: 1.0 + color: Qt.rgba(1, 0.5, 0, 1) + } + } + } + } + + // Gradient colors for layer thickness (similar to parula colormap) + Rectangle + { + id: thicknessGradient + visible: viewSettings.show_thickness_gradient + anchors.left: parent.left + anchors.right: parent.right + height: Math.round(UM.Theme.getSize("layerview_row").height * 1.5) + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + + LinearGradient + { + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("default_lining").width + right: parent.right + rightMargin: UM.Theme.getSize("default_lining").width + top: parent.top + topMargin: UM.Theme.getSize("default_lining").width + bottom: parent.bottom + bottomMargin: UM.Theme.getSize("default_lining").width + } + start: Qt.point(0, 0) + end: Qt.point(parent.width, 0) + gradient: Gradient + { + GradientStop + { + position: 0.000 + color: Qt.rgba(0, 0, 0.5, 1) + } + GradientStop + { + position: 0.25 + color: Qt.rgba(0, 0.375, 0.75, 1) + } + GradientStop + { + position: 0.5 + color: Qt.rgba(0, 0.75, 0.5, 1) + } + GradientStop + { + position: 0.75 + color: Qt.rgba(1, 0.75, 0.25, 1) + } + GradientStop + { + position: 1.0 + color: Qt.rgba(1, 1, 0, 1) + } + } + } + } + } + + FontMetrics + { + id: fontMetrics + font: UM.Theme.getFont("default") + } +} diff --git a/plugins/SimulationView/__init__.py b/plugins/SimulationView/__init__.py index 360fdc1de9..420ee60660 100644 --- a/plugins/SimulationView/__init__.py +++ b/plugins/SimulationView/__init__.py @@ -8,19 +8,21 @@ from . import SimulationViewProxy, SimulationView catalog = i18nCatalog("cura") + def getMetaData(): return { "view": { "name": catalog.i18nc("@item:inlistbox", "Layer view"), - "view_panel": "SimulationView.qml", - "weight": 2 + "weight": 0 } } + def createSimulationViewProxy(engine, script_engine): return SimulationViewProxy.SimulationViewProxy() + def register(app): simulation_view = SimulationView.SimulationView() qmlRegisterSingletonType(SimulationViewProxy.SimulationViewProxy, "UM", 1, 0, "SimulationView", simulation_view.getProxy) - return { "view": SimulationView.SimulationView()} + return { "view": simulation_view} diff --git a/plugins/SimulationView/layers.shader b/plugins/SimulationView/layers.shader index 30f23a3189..69c7c61ee5 100644 --- a/plugins/SimulationView/layers.shader +++ b/plugins/SimulationView/layers.shader @@ -49,12 +49,13 @@ fragment = // discard movements discard; } - // support: 4, 5, 7, 10 + // support: 4, 5, 7, 10, 11 (prime tower) if ((u_show_helpers == 0) && ( ((v_line_type >= 3.5) && (v_line_type <= 4.5)) || + ((v_line_type >= 4.5) && (v_line_type <= 5.5)) || ((v_line_type >= 6.5) && (v_line_type <= 7.5)) || ((v_line_type >= 9.5) && (v_line_type <= 10.5)) || - ((v_line_type >= 4.5) && (v_line_type <= 5.5)) + ((v_line_type >= 10.5) && (v_line_type <= 11.5)) )) { discard; } diff --git a/plugins/SimulationView/layers3d.shader b/plugins/SimulationView/layers3d.shader index de2b9335d8..a277606509 100644 --- a/plugins/SimulationView/layers3d.shader +++ b/plugins/SimulationView/layers3d.shader @@ -154,7 +154,7 @@ geometry41core = if ((u_show_travel_moves == 0) && ((v_line_type[0] == 8) || (v_line_type[0] == 9))) { return; } - if ((u_show_helpers == 0) && ((v_line_type[0] == 4) || (v_line_type[0] == 5) || (v_line_type[0] == 7) || (v_line_type[0] == 10))) { + if ((u_show_helpers == 0) && ((v_line_type[0] == 4) || (v_line_type[0] == 5) || (v_line_type[0] == 7) || (v_line_type[0] == 10) || v_line_type[0] == 11)) { return; } if ((u_show_skin == 0) && ((v_line_type[0] == 1) || (v_line_type[0] == 2) || (v_line_type[0] == 3))) { diff --git a/plugins/SimulationView/layers_shadow.shader b/plugins/SimulationView/layers_shadow.shader index 7ceccff21e..6149cc1703 100644 --- a/plugins/SimulationView/layers_shadow.shader +++ b/plugins/SimulationView/layers_shadow.shader @@ -45,19 +45,23 @@ fragment = void main() { - if ((u_show_travel_moves == 0) && (v_line_type >= 7.5) && (v_line_type <= 9.5)) { // actually, 8 and 9 + if ((u_show_travel_moves == 0) && (v_line_type >= 7.5) && (v_line_type <= 9.5)) + { // actually, 8 and 9 // discard movements discard; } - // support: 4, 5, 7, 10 + // support: 4, 5, 7, 10, 11 if ((u_show_helpers == 0) && ( ((v_line_type >= 3.5) && (v_line_type <= 4.5)) || ((v_line_type >= 6.5) && (v_line_type <= 7.5)) || ((v_line_type >= 9.5) && (v_line_type <= 10.5)) || - ((v_line_type >= 4.5) && (v_line_type <= 5.5)) - )) { + ((v_line_type >= 4.5) && (v_line_type <= 5.5)) || + ((v_line_type >= 10.5) && (v_line_type <= 11.5)) + )) + { discard; } + // skin: 1, 2, 3 if ((u_show_skin == 0) && ( (v_line_type >= 0.5) && (v_line_type <= 3.5) @@ -65,7 +69,8 @@ fragment = discard; } // infill: - if ((u_show_infill == 0) && (v_line_type >= 5.5) && (v_line_type <= 6.5)) { + if ((u_show_infill == 0) && (v_line_type >= 5.5) && (v_line_type <= 6.5)) + { // discard movements discard; } @@ -117,12 +122,13 @@ fragment41core = // discard movements discard; } - // helpers: 4, 5, 7, 10 + // helpers: 4, 5, 7, 10, 11 if ((u_show_helpers == 0) && ( ((v_line_type >= 3.5) && (v_line_type <= 4.5)) || ((v_line_type >= 6.5) && (v_line_type <= 7.5)) || ((v_line_type >= 9.5) && (v_line_type <= 10.5)) || - ((v_line_type >= 4.5) && (v_line_type <= 5.5)) + ((v_line_type >= 4.5) && (v_line_type <= 5.5)) || + ((v_line_type >= 10.5) && (v_line_type <= 11.5)) )) { discard; } diff --git a/plugins/SimulationView/plugin.json b/plugins/SimulationView/plugin.json index 93df98068f..3ccf91b9e6 100644 --- a/plugins/SimulationView/plugin.json +++ b/plugins/SimulationView/plugin.json @@ -1,8 +1,8 @@ { "name": "Simulation View", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides the Simulation view.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/SliceInfoPlugin/plugin.json b/plugins/SliceInfoPlugin/plugin.json index 939e5ff235..8ff0e194fb 100644 --- a/plugins/SliceInfoPlugin/plugin.json +++ b/plugins/SliceInfoPlugin/plugin.json @@ -1,8 +1,8 @@ { "name": "Slice info", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Submits anonymous slice info. Can be disabled through preferences.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index b9ad5c8829..797d6dabec 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -12,7 +12,6 @@ from UM.Math.Color import Color from UM.View.GL.OpenGL import OpenGL from cura.Settings.ExtruderManager import ExtruderManager -from cura.Settings.ExtrudersModel import ExtrudersModel import math @@ -29,13 +28,16 @@ class SolidView(View): self._non_printing_shader = None self._support_mesh_shader = None - self._extruders_model = ExtrudersModel() + self._extruders_model = None self._theme = None def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() + if not self._extruders_model: + self._extruders_model = Application.getInstance().getExtrudersModel() + if not self._theme: self._theme = Application.getInstance().getTheme() diff --git a/plugins/SolidView/__init__.py b/plugins/SolidView/__init__.py index db2e48f489..34148fcf05 100644 --- a/plugins/SolidView/__init__.py +++ b/plugins/SolidView/__init__.py @@ -10,7 +10,8 @@ def getMetaData(): return { "view": { "name": i18n_catalog.i18nc("@item:inmenu", "Solid view"), - "weight": 0 + "weight": 0, + "visible": False } } diff --git a/plugins/SolidView/plugin.json b/plugins/SolidView/plugin.json index e70ec224dd..b3f62221c5 100644 --- a/plugins/SolidView/plugin.json +++ b/plugins/SolidView/plugin.json @@ -1,8 +1,8 @@ { "name": "Solid View", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides a normal solid mesh view.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } \ No newline at end of file diff --git a/plugins/SupportEraser/plugin.json b/plugins/SupportEraser/plugin.json index 7af35e0fb5..fa6d6d230e 100644 --- a/plugins/SupportEraser/plugin.json +++ b/plugins/SupportEraser/plugin.json @@ -1,8 +1,8 @@ { "name": "Support Eraser", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Creates an eraser mesh to block the printing of support in certain places", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/Toolbox/plugin.json b/plugins/Toolbox/plugin.json index 2557185524..61dc0429f5 100644 --- a/plugins/Toolbox/plugin.json +++ b/plugins/Toolbox/plugin.json @@ -1,7 +1,7 @@ { "name": "Toolbox", "author": "Ultimaker B.V.", - "version": "1.0.0", - "api": 5, + "version": "1.0.1", + "api": "6.0", "description": "Find, manage and install new Cura packages." } diff --git a/plugins/Toolbox/resources/qml/RatingWidget.qml b/plugins/Toolbox/resources/qml/RatingWidget.qml new file mode 100644 index 0000000000..441cf238f7 --- /dev/null +++ b/plugins/Toolbox/resources/qml/RatingWidget.qml @@ -0,0 +1,106 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import UM 1.0 as UM +import Cura 1.1 as Cura +Item +{ + id: ratingWidget + + property real rating: 0 + property int indexHovered: -1 + property string packageId: "" + + property int userRating: 0 + property bool canRate: false + + signal rated(int rating) + + width: contentRow.width + height: contentRow.height + MouseArea + { + id: mouseArea + anchors.fill: parent + hoverEnabled: ratingWidget.canRate + acceptedButtons: Qt.NoButton + onExited: + { + if(ratingWidget.canRate) + { + ratingWidget.indexHovered = -1 + } + } + + Row + { + id: contentRow + height: childrenRect.height + Repeater + { + model: 5 // We need to get 5 stars + Button + { + id: control + hoverEnabled: true + onHoveredChanged: + { + if(hovered && ratingWidget.canRate) + { + indexHovered = index + } + } + + ToolTip.visible: control.hovered && !ratingWidget.canRate + ToolTip.text: !Cura.API.account.isLoggedIn ? catalog.i18nc("@label", "You need to login first before you can rate"): catalog.i18nc("@label", "You need to install the package before you can rate") + + property bool isStarFilled: + { + // If the entire widget is hovered, override the actual rating. + if(ratingWidget.indexHovered >= 0) + { + return indexHovered >= index + } + + if(ratingWidget.userRating > 0) + { + return userRating >= index +1 + } + + return rating >= index + 1 + } + + contentItem: Item {} + height: UM.Theme.getSize("rating_star").height + width: UM.Theme.getSize("rating_star").width + background: UM.RecolorImage + { + source: UM.Theme.getIcon(control.isStarFilled ? "star_filled" : "star_empty") + sourceSize.width: width + sourceSize.height: height + + // Unfilled stars should always have the default color. Only filled stars should change on hover + color: + { + if(!ratingWidget.canRate) + { + return UM.Theme.getColor("rating_star") + } + if((ratingWidget.indexHovered >= 0 || ratingWidget.userRating > 0) && isStarFilled) + { + return UM.Theme.getColor("primary") + } + return UM.Theme.getColor("rating_star") + } + } + onClicked: + { + if(ratingWidget.canRate) + { + rated(index + 1) // Notify anyone who cares about this. + } + } + } + } + } + } +} \ No newline at end of file diff --git a/plugins/Toolbox/resources/qml/SmallRatingWidget.qml b/plugins/Toolbox/resources/qml/SmallRatingWidget.qml new file mode 100644 index 0000000000..965b81dc0f --- /dev/null +++ b/plugins/Toolbox/resources/qml/SmallRatingWidget.qml @@ -0,0 +1,36 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.4 +import UM 1.1 as UM +import Cura 1.1 as Cura + +Row +{ + id: rating + height: UM.Theme.getSize("rating_star").height + visible: model.average_rating > 0 //Has a rating at all. + spacing: UM.Theme.getSize("thick_lining").width + width: starIcon.width + spacing + numRatingsLabel.width + UM.RecolorImage + { + id: starIcon + source: UM.Theme.getIcon("star_filled") + color: model.user_rating == 0 ? UM.Theme.getColor("rating_star") : UM.Theme.getColor("primary") + height: UM.Theme.getSize("rating_star").height + width: UM.Theme.getSize("rating_star").width + sourceSize.height: height + sourceSize.width: width + } + + Label + { + id: numRatingsLabel + text: model.average_rating != undefined ? model.average_rating.toFixed(1) + " (" + model.num_ratings + " " + catalog.i18nc("@label", "ratings") + ")": "" + verticalAlignment: Text.AlignVCenter + height: starIcon.height + width: contentWidth + anchors.verticalCenter: starIcon.verticalCenter + color: starIcon.color + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + } +} \ No newline at end of file diff --git a/plugins/Toolbox/resources/qml/Toolbox.qml b/plugins/Toolbox/resources/qml/Toolbox.qml index 9a98c998b0..d15d98eed7 100644 --- a/plugins/Toolbox/resources/qml/Toolbox.qml +++ b/plugins/Toolbox/resources/qml/Toolbox.qml @@ -14,17 +14,17 @@ Window modality: Qt.ApplicationModal flags: Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint - width: 720 * screenScaleFactor - height: 640 * screenScaleFactor + width: Math.floor(720 * screenScaleFactor) + height: Math.floor(640 * screenScaleFactor) minimumWidth: width maximumWidth: minimumWidth minimumHeight: height maximumHeight: minimumHeight - color: UM.Theme.getColor("sidebar") + color: UM.Theme.getColor("main_background") UM.I18nCatalog { id: catalog - name:"cura" + name: "cura" } Item { @@ -38,7 +38,7 @@ Window { id: mainView width: parent.width - z: -1 + z: parent.z - 1 anchors { top: header.bottom @@ -95,6 +95,7 @@ Window licenseDialog.show(); } } + ToolboxLicenseDialog { id: licenseDialog diff --git a/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml b/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml index 4aaea20813..b653f1a73b 100644 --- a/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml +++ b/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.3 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM @@ -55,10 +55,11 @@ Item bottomMargin: UM.Theme.getSize("default_margin").height } text: details.name || "" - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") wrapMode: Text.WordWrap width: parent.width height: UM.Theme.getSize("toolbox_property_label").height + renderType: Text.NativeRendering } Label { @@ -70,6 +71,7 @@ Item left: title.left topMargin: UM.Theme.getSize("default_margin").height } + renderType: Text.NativeRendering } Column { @@ -86,14 +88,16 @@ Item Label { text: catalog.i18nc("@label", "Website") + ":" - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering } Label { text: catalog.i18nc("@label", "Email") + ":" - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering } } Column @@ -118,10 +122,11 @@ Item } return "" } - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") linkColor: UM.Theme.getColor("text_link") onLinkActivated: Qt.openUrlExternally(link) + renderType: Text.NativeRendering } Label @@ -134,10 +139,11 @@ Item } return "" } - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") linkColor: UM.Theme.getColor("text_link") onLinkActivated: Qt.openUrlExternally(link) + renderType: Text.NativeRendering } } Rectangle diff --git a/plugins/Toolbox/resources/qml/ToolboxBackColumn.qml b/plugins/Toolbox/resources/qml/ToolboxBackColumn.qml index 8524b7d1e5..dba9f19ccd 100644 --- a/plugins/Toolbox/resources/qml/ToolboxBackColumn.qml +++ b/plugins/Toolbox/resources/qml/ToolboxBackColumn.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM @@ -61,9 +61,15 @@ Item id: labelStyle text: control.text color: control.enabled ? (control.hovered ? UM.Theme.getColor("primary") : UM.Theme.getColor("text")) : UM.Theme.getColor("text_inactive") - font: UM.Theme.getFont("default_bold") - horizontalAlignment: Text.AlignRight + font: UM.Theme.getFont("medium_bold") + horizontalAlignment: Text.AlignLeft + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + } width: control.width + renderType: Text.NativeRendering } } } diff --git a/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml b/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml index a48cb2ee3f..db4e8c628f 100644 --- a/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml +++ b/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM @@ -36,12 +36,19 @@ Item var pg_name = "printingGuidelines" return (pg_name in packageData.links) ? packageData.links[pg_name] : undefined } + + property var materialWebsiteUrl: + { + var pg_name = "website" + return (pg_name in packageData.links) ? packageData.links[pg_name] : undefined + } anchors.topMargin: UM.Theme.getSize("default_margin").height height: visible ? childrenRect.height : 0 visible: packageData.type == "material" && (packageData.has_configs || technicalDataSheetUrl !== undefined || - safetyDataSheetUrl !== undefined || printingGuidelinesUrl !== undefined) + safetyDataSheetUrl !== undefined || printingGuidelinesUrl !== undefined || + materialWebsiteUrl !== undefined) Item { @@ -60,6 +67,7 @@ Item wrapMode: Text.WordWrap color: UM.Theme.getColor("text_medium") font: UM.Theme.getFont("medium") + renderType: Text.NativeRendering } TableView @@ -83,7 +91,7 @@ Item model: packageData.supported_configs headerDelegate: Rectangle { - color: UM.Theme.getColor("sidebar") + color: UM.Theme.getColor("main_background") height: UM.Theme.getSize("toolbox_chart_row").height Label { @@ -92,6 +100,7 @@ Item text: styleData.value || "" color: UM.Theme.getColor("text") font: UM.Theme.getFont("default_bold") + renderType: Text.NativeRendering } Rectangle { @@ -111,6 +120,7 @@ Item text: styleData.value || "" color: UM.Theme.getColor("text_medium") font: UM.Theme.getFont("default") + renderType: Text.NativeRendering } } itemDelegate: Item @@ -123,6 +133,7 @@ Item text: styleData.value || "" color: UM.Theme.getColor("text_medium") font: UM.Theme.getFont("default") + renderType: Text.NativeRendering } } @@ -137,6 +148,7 @@ Item elide: Text.ElideRight color: UM.Theme.getColor("text_medium") font: UM.Theme.getFont("default") + renderType: Text.NativeRendering } } @@ -180,7 +192,8 @@ Item anchors.top: combatibilityItem.bottom anchors.topMargin: UM.Theme.getSize("default_margin").height / 2 visible: base.technicalDataSheetUrl !== undefined || - base.safetyDataSheetUrl !== undefined || base.printingGuidelinesUrl !== undefined + base.safetyDataSheetUrl !== undefined || base.printingGuidelinesUrl !== undefined || + base.materialWebsiteUrl !== undefined height: visible ? contentHeight : 0 text: { @@ -208,11 +221,22 @@ Item var pg_name = catalog.i18nc("@action:label", "Printing Guidelines") result += "%2".arg(base.printingGuidelinesUrl).arg(pg_name) } + if (base.materialWebsiteUrl !== undefined) + { + if (result.length > 0) + { + result += "
" + } + var pg_name = catalog.i18nc("@action:label", "Website") + result += "%2".arg(base.materialWebsiteUrl).arg(pg_name) + } + return result } - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") linkColor: UM.Theme.getColor("text_link") onLinkActivated: Qt.openUrlExternally(link) + renderType: Text.NativeRendering } } diff --git a/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml b/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml index 2c5d08aa72..e238132680 100644 --- a/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml +++ b/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 +import QtQuick 2.10 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 import QtQuick.Layouts 1.1 @@ -66,6 +66,7 @@ UM.Dialog anchors.right: parent.right font: UM.Theme.getFont("default") wrapMode: Text.WordWrap + renderType: Text.NativeRendering } // Buttons diff --git a/plugins/Toolbox/resources/qml/ToolboxDetailList.qml b/plugins/Toolbox/resources/qml/ToolboxDetailList.qml index 2e5eae098c..4e44ea7d0b 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDetailList.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDetailList.qml @@ -26,10 +26,19 @@ Item } height: childrenRect.height + 2 * UM.Theme.getSize("wide_margin").height spacing: UM.Theme.getSize("default_margin").height + Repeater { model: toolbox.packagesModel - delegate: ToolboxDetailTile {} + delegate: Loader + { + // FIXME: When using asynchronous loading, on Mac and Windows, the tile may fail to load complete, + // leaving an empty space below the title part. We turn it off for now to make it work on Mac and + // Windows. + // Can be related to this QT bug: https://bugreports.qt.io/browse/QTBUG-50992 + asynchronous: false + source: "ToolboxDetailTile.qml" + } } } } diff --git a/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml b/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml index 437a2ef351..fef2732af9 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml @@ -1,11 +1,13 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.3 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM +import Cura 1.1 as Cura + Item { id: page @@ -24,7 +26,7 @@ Item right: parent.right rightMargin: UM.Theme.getSize("wide_margin").width } - height: UM.Theme.getSize("toolbox_detail_header").height + height: childrenRect.height + 3 * UM.Theme.getSize("default_margin").width Rectangle { id: thumbnail @@ -37,7 +39,7 @@ Item leftMargin: UM.Theme.getSize("wide_margin").width topMargin: UM.Theme.getSize("wide_margin").height } - color: white //Always a white background for image (regardless of theme). + color: UM.Theme.getColor("main_background") Image { anchors.fill: parent @@ -55,16 +57,21 @@ Item top: thumbnail.top left: thumbnail.right leftMargin: UM.Theme.getSize("default_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("wide_margin").width - bottomMargin: UM.Theme.getSize("default_margin").height } text: details === null ? "" : (details.name || "") - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") - wrapMode: Text.WordWrap - width: parent.width - height: UM.Theme.getSize("toolbox_property_label").height + width: contentWidth + height: contentHeight + renderType: Text.NativeRendering + } + + SmallRatingWidget + { + anchors.left: title.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.verticalCenter: title.verticalCenter + property var model: details } Column @@ -81,27 +88,38 @@ Item height: childrenRect.height Label { - text: catalog.i18nc("@label", "Version") + ":" - font: UM.Theme.getFont("very_small") + text: catalog.i18nc("@label", "Your rating") + ":" + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering + } + Label + { + text: catalog.i18nc("@label", "Version") + ":" + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering } Label { text: catalog.i18nc("@label", "Last updated") + ":" - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering } Label { text: catalog.i18nc("@label", "Author") + ":" - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering } Label { text: catalog.i18nc("@label", "Downloads") + ":" - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering } } Column @@ -116,11 +134,54 @@ Item } spacing: Math.floor(UM.Theme.getSize("narrow_margin").height) height: childrenRect.height + RatingWidget + { + id: rating + visible: details.type == "plugin" + packageId: details.id != undefined ? details.id: "" + userRating: details.user_rating != undefined ? details.user_rating: 0 + canRate: toolbox.isInstalled(details.id) && Cura.API.account.isLoggedIn + + onRated: + { + toolbox.ratePackage(details.id, rating) + // HACK: This is a far from optimal solution, but without major refactoring, this is the best we can + // do. Since a rework of this is scheduled, it shouldn't live that long... + var index = toolbox.pluginsAvailableModel.find("id", details.id) + if(index != -1) + { + if(details.user_rating == 0) // User never rated before. + { + toolbox.pluginsAvailableModel.setProperty(index, "num_ratings", details.num_ratings + 1) + } + + toolbox.pluginsAvailableModel.setProperty(index, "user_rating", rating) + + + // Hack; This is because the current selection is an outdated copy, so we need to re-copy it. + base.selection = toolbox.pluginsAvailableModel.getItem(index) + return + } + index = toolbox.pluginsShowcaseModel.find("id", details.id) + if(index != -1) + { + if(details.user_rating == 0) // User never rated before. + { + toolbox.pluginsShowcaseModel.setProperty(index, "user_rating", rating) + } + toolbox.pluginsShowcaseModel.setProperty(index, "num_ratings", details.num_ratings + 1) + + // Hack; This is because the current selection is an outdated copy, so we need to re-copy it. + base.selection = toolbox.pluginsShowcaseModel.getItem(index) + } + } + } Label { text: details === null ? "" : (details.version || catalog.i18nc("@label", "Unknown")) - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") + renderType: Text.NativeRendering } Label { @@ -133,8 +194,9 @@ Item var date = new Date(details.last_updated) return date.toLocaleString(UM.Preferences.getValue("general/language")) } - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") + renderType: Text.NativeRendering } Label { @@ -144,34 +206,25 @@ Item { return "" } - if (details.author_email) - { - return "" + details.author_name + "" - } else { return "" + details.author_name + "" } } - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") linkColor: UM.Theme.getColor("text_link") onLinkActivated: Qt.openUrlExternally(link) + renderType: Text.NativeRendering } Label { text: details === null ? "" : (details.download_count || catalog.i18nc("@label", "Unknown")) - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") + renderType: Text.NativeRendering } } - Rectangle - { - color: UM.Theme.getColor("lining") - width: parent.width - height: UM.Theme.getSize("default_lining").height - anchors.bottom: parent.bottom - } } ToolboxDetailList { diff --git a/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml b/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml index 9061a8e06b..43f97baf3f 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM @@ -31,17 +31,19 @@ Item wrapMode: Text.WordWrap color: UM.Theme.getColor("text") font: UM.Theme.getFont("medium_bold") + renderType: Text.NativeRendering } Label { anchors.top: packageName.bottom width: parent.width text: model.description - maximumLineCount: 6 + maximumLineCount: 25 elide: Text.ElideRight wrapMode: Text.WordWrap color: UM.Theme.getColor("text") font: UM.Theme.getFont("default") + renderType: Text.NativeRendering } } diff --git a/plugins/Toolbox/resources/qml/ToolboxDetailTileActions.qml b/plugins/Toolbox/resources/qml/ToolboxDetailTileActions.qml index cd1e4cdbda..87fc5d6955 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDetailTileActions.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDetailTileActions.qml @@ -1,40 +1,69 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM +import Cura 1.1 as Cura Column { property bool installed: toolbox.isInstalled(model.id) property bool canUpdate: toolbox.canUpdate(model.id) + property bool loginRequired: model.login_required && !Cura.API.account.isLoggedIn + width: UM.Theme.getSize("toolbox_action_button").width spacing: UM.Theme.getSize("narrow_margin").height - ToolboxProgressButton + Item { - id: installButton - active: toolbox.isDownloading && toolbox.activePackage == model - complete: installed - readyAction: function() + width: installButton.width + height: installButton.height + ToolboxProgressButton { - toolbox.activePackage = model - toolbox.startDownload(model.download_url) + id: installButton + active: toolbox.isDownloading && toolbox.activePackage == model + onReadyAction: + { + toolbox.activePackage = model + toolbox.startDownload(model.download_url) + } + onActiveAction: toolbox.cancelDownload() + + // Don't allow installing while another download is running + enabled: installed || (!(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired) + opacity: enabled ? 1.0 : 0.5 + visible: !updateButton.visible && !installed// Don't show when the update button is visible } - activeAction: function() + + Cura.SecondaryButton { - toolbox.cancelDownload() + visible: installed + onClicked: toolbox.viewCategory = "installed" + text: catalog.i18nc("@action:button", "Installed") + fixedWidthMode: true + width: installButton.width + height: installButton.height } - completeAction: function() + } + + Label + { + wrapMode: Text.WordWrap + text: catalog.i18nc("@label:The string between and is the highlighted link", "Log in is required to install or update") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + linkColor: UM.Theme.getColor("text_link") + visible: loginRequired + width: installButton.width + renderType: Text.NativeRendering + + MouseArea { - toolbox.viewCategory = "installed" + anchors.fill: parent + onClicked: Cura.API.account.login() } - // Don't allow installing while another download is running - enabled: installed || !(toolbox.isDownloading && toolbox.activePackage != model) - opacity: enabled ? 1.0 : 0.5 - visible: !updateButton.visible // Don't show when the update button is visible } ToolboxProgressButton @@ -44,24 +73,28 @@ Column readyLabel: catalog.i18nc("@action:button", "Update") activeLabel: catalog.i18nc("@action:button", "Updating") completeLabel: catalog.i18nc("@action:button", "Updated") - readyAction: function() + + onReadyAction: { toolbox.activePackage = model toolbox.update(model.id) } - activeAction: function() - { - toolbox.cancelDownload() - } + onActiveAction: toolbox.cancelDownload() // Don't allow installing while another download is running - enabled: !(toolbox.isDownloading && toolbox.activePackage != model) + enabled: !(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired opacity: enabled ? 1.0 : 0.5 visible: canUpdate } + Connections { target: toolbox onInstallChanged: installed = toolbox.isInstalled(model.id) onMetadataChanged: canUpdate = toolbox.canUpdate(model.id) + onFilterChanged: + { + installed = toolbox.isInstalled(model.id) + canUpdate = toolbox.canUpdate(model.id) + } } } diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml index c586828969..a9fcb39b28 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 @@ -22,9 +22,10 @@ Column text: gridArea.heading width: parent.width color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("medium") + font: UM.Theme.getFont("large") + renderType: Text.NativeRendering } - GridLayout + Grid { id: grid width: parent.width - 2 * parent.padding @@ -34,10 +35,12 @@ Column Repeater { model: gridArea.model - delegate: ToolboxDownloadsGridTile + delegate: Loader { - Layout.preferredWidth: (grid.width - (grid.columns - 1) * grid.columnSpacing) / grid.columns - Layout.preferredHeight: UM.Theme.getSize("toolbox_thumbnail_small").height + asynchronous: true + width: Math.round((grid.width - (grid.columns - 1) * grid.columnSpacing) / grid.columns) + height: UM.Theme.getSize("toolbox_thumbnail_small").height + source: "ToolboxDownloadsGridTile.qml" } } } diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml index 887140bbfa..a11c6ee963 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml @@ -1,11 +1,12 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.3 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import UM 1.1 as UM +import Cura 1.1 as Cura Item { @@ -14,91 +15,13 @@ Item property int installedPackages: (toolbox.viewCategory == "material" && model.type === undefined) ? toolbox.getNumberOfInstalledPackagesByAuthor(model.id) : (toolbox.isInstalled(model.id) ? 1 : 0) height: childrenRect.height Layout.alignment: Qt.AlignTop | Qt.AlignLeft - Rectangle - { - id: highlight - anchors.fill: parent - opacity: 0.0 - color: UM.Theme.getColor("primary") - } - Row - { - width: parent.width - height: childrenRect.height - spacing: Math.floor(UM.Theme.getSize("narrow_margin").width) - Rectangle - { - id: thumbnail - width: UM.Theme.getSize("toolbox_thumbnail_small").width - height: UM.Theme.getSize("toolbox_thumbnail_small").height - color: "white" - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") - Image - { - anchors.centerIn: parent - width: UM.Theme.getSize("toolbox_thumbnail_small").width - UM.Theme.getSize("wide_margin").width - height: UM.Theme.getSize("toolbox_thumbnail_small").height - UM.Theme.getSize("wide_margin").width - fillMode: Image.PreserveAspectFit - source: model.icon_url || "../images/logobot.svg" - mipmap: true - } - UM.RecolorImage - { - width: (parent.width * 0.4) | 0 - height: (parent.height * 0.4) | 0 - anchors - { - bottom: parent.bottom - right: parent.right - } - sourceSize.width: width - sourceSize.height: height - visible: installedPackages != 0 - color: (installedPackages == packageCount) ? UM.Theme.getColor("primary") : UM.Theme.getColor("border") - source: "../images/installed_check.svg" - } - } - Column - { - width: parent.width - thumbnail.width - parent.spacing - spacing: Math.floor(UM.Theme.getSize("narrow_margin").width) - Label - { - id: name - text: model.name - width: parent.width - wrapMode: Text.WordWrap - color: UM.Theme.getColor("text") - font: UM.Theme.getFont("default_bold") - } - Label - { - id: info - text: model.description - maximumLineCount: 2 - elide: Text.ElideRight - width: parent.width - wrapMode: Text.WordWrap - color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("very_small") - } - } - } + MouseArea { anchors.fill: parent hoverEnabled: true - onEntered: - { - thumbnail.border.color = UM.Theme.getColor("primary") - highlight.opacity = 0.1 - } - onExited: - { - thumbnail.border.color = UM.Theme.getColor("lining") - highlight.opacity = 0.0 - } + onEntered: thumbnail.border.color = UM.Theme.getColor("primary") + onExited: thumbnail.border.color = UM.Theme.getColor("lining") onClicked: { base.selection = model @@ -128,4 +51,83 @@ Item } } } + + Rectangle + { + id: thumbnail + width: UM.Theme.getSize("toolbox_thumbnail_small").width + height: UM.Theme.getSize("toolbox_thumbnail_small").height + color: UM.Theme.getColor("main_background") + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + + Image + { + anchors.centerIn: parent + width: UM.Theme.getSize("toolbox_thumbnail_small").width - UM.Theme.getSize("wide_margin").width + height: UM.Theme.getSize("toolbox_thumbnail_small").height - UM.Theme.getSize("wide_margin").width + fillMode: Image.PreserveAspectFit + source: model.icon_url || "../images/logobot.svg" + mipmap: true + } + UM.RecolorImage + { + width: (parent.width * 0.4) | 0 + height: (parent.height * 0.4) | 0 + anchors + { + bottom: parent.bottom + right: parent.right + } + sourceSize.height: height + visible: installedPackages != 0 + color: (installedPackages == packageCount) ? UM.Theme.getColor("primary") : UM.Theme.getColor("border") + source: "../images/installed_check.svg" + } + } + Item + { + anchors + { + left: thumbnail.right + leftMargin: Math.floor(UM.Theme.getSize("narrow_margin").width) + right: parent.right + top: parent.top + bottom: parent.bottom + } + + Label + { + id: name + text: model.name + width: parent.width + elide: Text.ElideRight + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("default_bold") + } + Label + { + id: info + text: model.description + elide: Text.ElideRight + width: parent.width + wrapMode: Text.WordWrap + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("default") + anchors.top: name.bottom + anchors.bottom: rating.top + verticalAlignment: Text.AlignVCenter + maximumLineCount: 2 + } + SmallRatingWidget + { + id: rating + anchors + { + bottom: parent.bottom + left: parent.left + right: parent.right + } + } + } } diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml index 46f5debfdd..795622cf82 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM @@ -23,30 +23,34 @@ Rectangle text: catalog.i18nc("@label", "Featured") width: parent.width color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("medium") + font: UM.Theme.getFont("large") + renderType: Text.NativeRendering } Grid { height: childrenRect.height spacing: UM.Theme.getSize("wide_margin").width columns: 3 - anchors - { - horizontalCenter: parent.horizontalCenter - } + anchors.horizontalCenter: parent.horizontalCenter + Repeater { - model: { - if ( toolbox.viewCategory == "plugin" ) + model: + { + if (toolbox.viewCategory == "plugin") { return toolbox.pluginsShowcaseModel } - if ( toolbox.viewCategory == "material" ) + if (toolbox.viewCategory == "material") { return toolbox.materialsShowcaseModel } } - delegate: ToolboxDownloadsShowcaseTile {} + delegate: Loader + { + asynchronous: true + source: "ToolboxDownloadsShowcaseTile.qml" + } } } } diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml index 4fb70541d2..c8c1e56c82 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 @@ -13,92 +13,79 @@ Rectangle property int installedPackages: toolbox.viewCategory == "material" ? toolbox.getNumberOfInstalledPackagesByAuthor(model.id) : (toolbox.isInstalled(model.id) ? 1 : 0) id: tileBase width: UM.Theme.getSize("toolbox_thumbnail_large").width + (2 * UM.Theme.getSize("default_lining").width) - height: thumbnail.height + packageNameBackground.height + (2 * UM.Theme.getSize("default_lining").width) + height: thumbnail.height + packageName.height + rating.height + UM.Theme.getSize("default_margin").width border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") - color: "transparent" - Rectangle + color: UM.Theme.getColor("main_background") + Image { id: thumbnail - color: "white" - width: UM.Theme.getSize("toolbox_thumbnail_large").width - height: UM.Theme.getSize("toolbox_thumbnail_large").height + height: UM.Theme.getSize("toolbox_thumbnail_large").height - 4 * UM.Theme.getSize("default_margin").height + width: UM.Theme.getSize("toolbox_thumbnail_large").height - 4 * UM.Theme.getSize("default_margin").height + fillMode: Image.PreserveAspectFit + source: model.icon_url || "../images/logobot.svg" + mipmap: true anchors { top: parent.top + topMargin: UM.Theme.getSize("default_margin").height horizontalCenter: parent.horizontalCenter - topMargin: UM.Theme.getSize("default_lining").width } - Image + } + Label + { + id: packageName + text: model.name + anchors { - anchors.centerIn: parent - width: UM.Theme.getSize("toolbox_thumbnail_large").width - 2 * UM.Theme.getSize("default_margin").width - height: UM.Theme.getSize("toolbox_thumbnail_large").height - 2 * UM.Theme.getSize("default_margin").height - fillMode: Image.PreserveAspectFit - source: model.icon_url || "../images/logobot.svg" - mipmap: true + horizontalCenter: parent.horizontalCenter + top: thumbnail.bottom } - UM.RecolorImage + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + renderType: Text.NativeRendering + height: UM.Theme.getSize("toolbox_heading_label").height + width: parent.width - UM.Theme.getSize("default_margin").width + wrapMode: Text.WordWrap + elide: Text.ElideRight + font: UM.Theme.getFont("medium_bold") + } + UM.RecolorImage + { + width: (parent.width * 0.20) | 0 + height: width + anchors { - width: (parent.width * 0.3) | 0 - height: (parent.height * 0.3) | 0 - anchors - { - bottom: parent.bottom - right: parent.right - bottomMargin: UM.Theme.getSize("default_lining").width - } - sourceSize.width: width - sourceSize.height: height - visible: installedPackages != 0 - color: (installedPackages == packageCount) ? UM.Theme.getColor("primary") : UM.Theme.getColor("border") - source: "../images/installed_check.svg" + bottom: bottomBorder.top + right: parent.right } + visible: installedPackages != 0 + color: (installedPackages == packageCount) ? UM.Theme.getColor("primary") : UM.Theme.getColor("border") + source: "../images/installed_check.svg" + } + + SmallRatingWidget + { + id: rating + anchors.bottom: parent.bottom + anchors.bottomMargin: UM.Theme.getSize("narrow_margin").height + anchors.horizontalCenter: parent.horizontalCenter } Rectangle { - id: packageNameBackground + id: bottomBorder color: UM.Theme.getColor("primary") - anchors - { - top: thumbnail.bottom - horizontalCenter: parent.horizontalCenter - } - height: UM.Theme.getSize("toolbox_heading_label").height + anchors.bottom: parent.bottom width: parent.width - Label - { - id: packageName - text: model.name - anchors - { - horizontalCenter: parent.horizontalCenter - } - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - height: UM.Theme.getSize("toolbox_heading_label").height - width: parent.width - wrapMode: Text.WordWrap - color: UM.Theme.getColor("button_text") - font: UM.Theme.getFont("medium_bold") - } + height: UM.Theme.getSize("toolbox_header_highlight").height } + MouseArea { anchors.fill: parent hoverEnabled: true - onEntered: - { - packageName.color = UM.Theme.getColor("button_text_hover") - packageNameBackground.color = UM.Theme.getColor("primary_hover") - tileBase.border.color = UM.Theme.getColor("primary_hover") - } - onExited: - { - packageName.color = UM.Theme.getColor("button_text") - packageNameBackground.color = UM.Theme.getColor("primary") - tileBase.border.color = UM.Theme.getColor("lining") - } + onEntered: tileBase.border.color = UM.Theme.getColor("primary") + onExited: tileBase.border.color = UM.Theme.getColor("lining") onClicked: { base.selection = model diff --git a/plugins/Toolbox/resources/qml/ToolboxErrorPage.qml b/plugins/Toolbox/resources/qml/ToolboxErrorPage.qml index 600ae2b39f..e57e63dbb9 100644 --- a/plugins/Toolbox/resources/qml/ToolboxErrorPage.qml +++ b/plugins/Toolbox/resources/qml/ToolboxErrorPage.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -18,5 +18,6 @@ Rectangle { centerIn: parent } + renderType: Text.NativeRendering } } diff --git a/plugins/Toolbox/resources/qml/ToolboxFooter.qml b/plugins/Toolbox/resources/qml/ToolboxFooter.qml index 5c2a6577ad..6f46e939ff 100644 --- a/plugins/Toolbox/resources/qml/ToolboxFooter.qml +++ b/plugins/Toolbox/resources/qml/ToolboxFooter.qml @@ -1,22 +1,24 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick 2.10 +import QtQuick.Controls 2.3 + import UM 1.1 as UM +import Cura 1.0 as Cura Item { id: footer width: parent.width anchors.bottom: parent.bottom - height: visible ? Math.floor(UM.Theme.getSize("toolbox_footer").height) : 0 + height: visible ? UM.Theme.getSize("toolbox_footer").height : 0 + Label { text: catalog.i18nc("@info", "You will need to restart Cura before changes in packages have effect.") color: UM.Theme.getColor("text") - height: Math.floor(UM.Theme.getSize("toolbox_footer_button").height) + height: UM.Theme.getSize("toolbox_footer_button").height verticalAlignment: Text.AlignVCenter anchors { @@ -26,12 +28,12 @@ Item right: restartButton.right rightMargin: UM.Theme.getSize("default_margin").width } - + renderType: Text.NativeRendering } - Button + + Cura.PrimaryButton { id: restartButton - text: catalog.i18nc("@info:button", "Quit Cura") anchors { top: parent.top @@ -39,26 +41,11 @@ Item right: parent.right rightMargin: UM.Theme.getSize("wide_margin").width } - iconName: "dialog-restart" + height: UM.Theme.getSize("toolbox_footer_button").height + text: catalog.i18nc("@info:button", "Quit Cura") onClicked: toolbox.restart() - style: ButtonStyle - { - background: Rectangle - { - implicitWidth: UM.Theme.getSize("toolbox_footer_button").width - implicitHeight: Math.floor(UM.Theme.getSize("toolbox_footer_button").height) - color: control.hovered ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary") - } - label: Label - { - color: UM.Theme.getColor("button_text") - font: UM.Theme.getFont("default_bold") - text: control.text - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - } - } } + ToolboxShadow { visible: footer.visible diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml index e683f89823..a85a69cbac 100644 --- a/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml +++ b/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Dialogs 1.1 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 @@ -21,44 +21,40 @@ ScrollView Column { spacing: UM.Theme.getSize("default_margin").height + visible: toolbox.pluginsInstalledModel.items.length > 0 + height: childrenRect.height + 4 * UM.Theme.getSize("default_margin").height + anchors { right: parent.right left: parent.left - leftMargin: UM.Theme.getSize("wide_margin").width - topMargin: UM.Theme.getSize("wide_margin").height - bottomMargin: UM.Theme.getSize("wide_margin").height + margins: UM.Theme.getSize("default_margin").width top: parent.top } - height: childrenRect.height + 4 * UM.Theme.getSize("default_margin").height + Label { - visible: toolbox.pluginsInstalledModel.items.length > 0 - width: parent.width + width: page.width text: catalog.i18nc("@title:tab", "Plugins") color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("medium") + font: UM.Theme.getFont("large") + renderType: Text.NativeRendering } Rectangle { - visible: toolbox.pluginsInstalledModel.items.length > 0 color: "transparent" width: parent.width - height: childrenRect.height + 1 * UM.Theme.getSize("default_lining").width + height: childrenRect.height + UM.Theme.getSize("default_margin").width border.color: UM.Theme.getColor("lining") border.width: UM.Theme.getSize("default_lining").width Column { - height: childrenRect.height anchors { top: parent.top right: parent.right left: parent.left - leftMargin: UM.Theme.getSize("default_margin").width - rightMargin: UM.Theme.getSize("default_margin").width - topMargin: UM.Theme.getSize("default_lining").width - bottomMargin: UM.Theme.getSize("default_lining").width + margins: UM.Theme.getSize("default_margin").width } Repeater { @@ -70,32 +66,27 @@ ScrollView } Label { - visible: toolbox.materialsInstalledModel.items.length > 0 - width: page.width text: catalog.i18nc("@title:tab", "Materials") color: UM.Theme.getColor("text_medium") font: UM.Theme.getFont("medium") + renderType: Text.NativeRendering } + Rectangle { - visible: toolbox.materialsInstalledModel.items.length > 0 color: "transparent" width: parent.width - height: childrenRect.height + 1 * UM.Theme.getSize("default_lining").width + height: childrenRect.height + UM.Theme.getSize("default_margin").width border.color: UM.Theme.getColor("lining") border.width: UM.Theme.getSize("default_lining").width Column { - height: Math.max( UM.Theme.getSize("wide_margin").height, childrenRect.height) anchors { top: parent.top right: parent.right left: parent.left - leftMargin: UM.Theme.getSize("default_margin").width - rightMargin: UM.Theme.getSize("default_margin").width - topMargin: UM.Theme.getSize("default_lining").width - bottomMargin: UM.Theme.getSize("default_lining").width + margins: UM.Theme.getSize("default_margin").width } Repeater { diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml index b16564fdd2..f50c3f3ac6 100644 --- a/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM @@ -30,6 +30,7 @@ Item CheckBox { id: disableButton + anchors.verticalCenter: pluginInfo.verticalCenter checked: isEnabled visible: model.type == "plugin" width: visible ? UM.Theme.getSize("checkbox").width : 0 @@ -49,17 +50,20 @@ Item width: parent.width height: Math.floor(UM.Theme.getSize("toolbox_property_label").height) wrapMode: Text.WordWrap - font: UM.Theme.getFont("default_bold") + font: UM.Theme.getFont("large_bold") color: pluginInfo.color + renderType: Text.NativeRendering } Label { text: model.description + font: UM.Theme.getFont("default") maximumLineCount: 3 elide: Text.ElideRight width: parent.width wrapMode: Text.WordWrap color: pluginInfo.color + renderType: Text.NativeRendering } } Column @@ -80,6 +84,7 @@ Item return model.author_name } } + font: UM.Theme.getFont("medium") width: parent.width height: Math.floor(UM.Theme.getSize("toolbox_property_label").height) wrapMode: Text.WordWrap @@ -88,16 +93,19 @@ Item onLinkActivated: Qt.openUrlExternally("mailto:" + model.author_email + "?Subject=Cura: " + model.name + " Plugin") color: model.enabled ? UM.Theme.getColor("text") : UM.Theme.getColor("lining") linkColor: UM.Theme.getColor("text_link") + renderType: Text.NativeRendering } Label { text: model.version + font: UM.Theme.getFont("default") width: parent.width height: UM.Theme.getSize("toolbox_property_label").height color: UM.Theme.getColor("text") verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft + renderType: Text.NativeRendering } } ToolboxInstalledTileActions diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml index 8fd88b1cfd..61af84fbe5 100644 --- a/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml +++ b/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml @@ -1,15 +1,18 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM +import Cura 1.1 as Cura + Column { property bool canUpdate: false property bool canDowngrade: false + property bool loginRequired: model.login_required && !Cura.API.account.isLoggedIn width: UM.Theme.getSize("toolbox_action_button").width spacing: UM.Theme.getSize("narrow_margin").height @@ -21,6 +24,7 @@ Column font: UM.Theme.getFont("default") wrapMode: Text.WordWrap width: parent.width + renderType: Text.NativeRendering } ToolboxProgressButton @@ -30,59 +34,49 @@ Column readyLabel: catalog.i18nc("@action:button", "Update") activeLabel: catalog.i18nc("@action:button", "Updating") completeLabel: catalog.i18nc("@action:button", "Updated") - readyAction: function() + onReadyAction: { toolbox.activePackage = model toolbox.update(model.id) } - activeAction: function() - { - toolbox.cancelDownload() - } + onActiveAction: toolbox.cancelDownload() + // Don't allow installing while another download is running - enabled: !(toolbox.isDownloading && toolbox.activePackage != model) + enabled: !(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired opacity: enabled ? 1.0 : 0.5 visible: canUpdate } - Button + Label + { + wrapMode: Text.WordWrap + text: catalog.i18nc("@label:The string between and is the highlighted link", "Log in is required to update") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + linkColor: UM.Theme.getColor("text_link") + visible: loginRequired + width: updateButton.width + renderType: Text.NativeRendering + + MouseArea + { + anchors.fill: parent + onClicked: Cura.API.account.login() + } + } + + Cura.SecondaryButton { id: removeButton text: canDowngrade ? catalog.i18nc("@action:button", "Downgrade") : catalog.i18nc("@action:button", "Uninstall") visible: !model.is_bundled && model.is_installed enabled: !toolbox.isDownloading - style: ButtonStyle - { - background: Rectangle - { - implicitWidth: UM.Theme.getSize("toolbox_action_button").width - implicitHeight: UM.Theme.getSize("toolbox_action_button").height - color: "transparent" - border - { - width: UM.Theme.getSize("default_lining").width - color: - { - if (control.hovered) - { - return UM.Theme.getColor("primary_hover") - } - else - { - return UM.Theme.getColor("lining") - } - } - } - } - label: Label - { - text: control.text - color: UM.Theme.getColor("text") - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - font: UM.Theme.getFont("default") - } - } + + width: UM.Theme.getSize("toolbox_action_button").width + height: UM.Theme.getSize("toolbox_action_button").height + + fixedWidthMode: true + onClicked: toolbox.checkPackageUsageAndUninstall(model.id) Connections { diff --git a/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml b/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml index b8baf7bc83..40b22c268d 100644 --- a/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml +++ b/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 +import QtQuick 2.10 import QtQuick.Dialogs 1.1 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 @@ -32,6 +32,7 @@ UM.Dialog anchors.right: parent.right text: licenseDialog.pluginName + catalog.i18nc("@label", "This plugin contains a license.\nYou need to accept this license to install this plugin.\nDo you agree with the terms below?") wrapMode: Text.Wrap + renderType: Text.NativeRendering } TextArea { diff --git a/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml b/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml index 1ba271dcab..025239bd43 100644 --- a/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml +++ b/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml @@ -1,7 +1,7 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.7 +import QtQuick 2.10 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 @@ -18,5 +18,6 @@ Rectangle { centerIn: parent } + renderType: Text.NativeRendering } } diff --git a/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml b/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml index 2744e40ec9..933e3a5900 100644 --- a/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml +++ b/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml @@ -5,6 +5,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM +import Cura 1.0 as Cura Item @@ -18,16 +19,19 @@ Item property var activeLabel: catalog.i18nc("@action:button", "Cancel") property var completeLabel: catalog.i18nc("@action:button", "Installed") - property var readyAction: null // Action when button is ready and clicked (likely install) - property var activeAction: null // Action when button is active and clicked (likely cancel) - property var completeAction: null // Action when button is complete and clicked (likely go to installed) + signal readyAction() // Action when button is ready and clicked (likely install) + signal activeAction() // Action when button is active and clicked (likely cancel) + signal completeAction() // Action when button is complete and clicked (likely go to installed) width: UM.Theme.getSize("toolbox_action_button").width height: UM.Theme.getSize("toolbox_action_button").height - Button + Cura.PrimaryButton { id: button + width: UM.Theme.getSize("toolbox_action_button").width + height: UM.Theme.getSize("toolbox_action_button").height + fixedWidthMode: true text: { if (complete) @@ -47,101 +51,15 @@ Item { if (complete) { - return completeAction() + completeAction() } else if (active) { - return activeAction() + activeAction() } else { - return readyAction() - } - } - style: ButtonStyle - { - background: Rectangle - { - implicitWidth: UM.Theme.getSize("toolbox_action_button").width - implicitHeight: UM.Theme.getSize("toolbox_action_button").height - color: - { - if (base.complete) - { - return "transparent" - } - else - { - if (control.hovered) - { - return UM.Theme.getColor("primary_hover") - } - else - { - return UM.Theme.getColor("primary") - } - } - } - border - { - width: - { - if (base.complete) - { - UM.Theme.getSize("default_lining").width - } - else - { - return 0 - } - } - color: - { - if (control.hovered) - { - return UM.Theme.getColor("primary_hover") - } - else - { - return UM.Theme.getColor("lining") - } - } - } - } - label: Label - { - text: control.text - color: - { - if (base.complete) - { - return UM.Theme.getColor("text") - } - else - { - if (control.hovered) - { - return UM.Theme.getColor("button_text_hover") - } - else - { - return UM.Theme.getColor("button_text") - } - } - } - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - font: - { - if (base.complete) - { - return UM.Theme.getFont("default") - } - else - { - return UM.Theme.getFont("default_bold") - } - } + readyAction() } } } diff --git a/plugins/Toolbox/resources/qml/ToolboxTabButton.qml b/plugins/Toolbox/resources/qml/ToolboxTabButton.qml index 22fb6d73ca..5e1aeaa636 100644 --- a/plugins/Toolbox/resources/qml/ToolboxTabButton.qml +++ b/plugins/Toolbox/resources/qml/ToolboxTabButton.qml @@ -1,51 +1,51 @@ // Copyright (c) 2018 Ultimaker B.V. // Toolbox is released under the terms of the LGPLv3 or higher. -import QtQuick 2.2 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick 2.10 +import QtQuick.Controls 2.3 import UM 1.1 as UM Button { + id: control property bool active: false - style: ButtonStyle + hoverEnabled: true + + background: Item { - background: Rectangle + implicitWidth: UM.Theme.getSize("toolbox_header_tab").width + implicitHeight: UM.Theme.getSize("toolbox_header_tab").height + Rectangle { - color: "transparent" - implicitWidth: UM.Theme.getSize("toolbox_header_tab").width - implicitHeight: UM.Theme.getSize("toolbox_header_tab").height - Rectangle - { - visible: control.active - color: UM.Theme.getColor("sidebar_header_highlight_hover") - anchors.bottom: parent.bottom - width: parent.width - height: UM.Theme.getSize("sidebar_header_highlight").height - } - } - label: Label - { - text: control.text - color: - { - if(control.hovered) - { - return UM.Theme.getColor("topbar_button_text_hovered"); - } - if(control.active) - { - return UM.Theme.getColor("topbar_button_text_active"); - } - else - { - return UM.Theme.getColor("topbar_button_text_inactive"); - } - } - font: control.enabled ? (control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")) : UM.Theme.getFont("default_italic") - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter + visible: control.active + color: UM.Theme.getColor("primary") + anchors.bottom: parent.bottom + width: parent.width + height: UM.Theme.getSize("toolbox_header_highlight").height } } -} + contentItem: Label + { + id: label + text: control.text + color: + { + if(control.hovered) + { + return UM.Theme.getColor("toolbox_header_button_text_hovered"); + } + if(control.active) + { + return UM.Theme.getColor("toolbox_header_button_text_active"); + } + else + { + return UM.Theme.getColor("toolbox_header_button_text_inactive"); + } + } + font: control.enabled ? (control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")) : UM.Theme.getFont("default_italic") + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + renderType: Text.NativeRendering + } +} \ No newline at end of file diff --git a/plugins/Toolbox/src/AuthorsModel.py b/plugins/Toolbox/src/AuthorsModel.py index bea3893504..877f8256ee 100644 --- a/plugins/Toolbox/src/AuthorsModel.py +++ b/plugins/Toolbox/src/AuthorsModel.py @@ -2,18 +2,19 @@ # Cura is released under the terms of the LGPLv3 or higher. import re -from typing import Dict +from typing import Dict, List, Optional, Union from PyQt5.QtCore import Qt, pyqtProperty, pyqtSignal from UM.Qt.ListModel import ListModel + ## Model that holds cura packages. By setting the filter property the instances held by this model can be changed. class AuthorsModel(ListModel): - def __init__(self, parent = None): + def __init__(self, parent = None) -> None: super().__init__(parent) - self._metadata = None + self._metadata = None # type: Optional[List[Dict[str, Union[str, List[str], int]]]] self.addRoleName(Qt.UserRole + 1, "id") self.addRoleName(Qt.UserRole + 2, "name") @@ -25,39 +26,40 @@ class AuthorsModel(ListModel): self.addRoleName(Qt.UserRole + 8, "description") # List of filters for queries. The result is the union of the each list of results. - self._filter = {} # type: Dict[str,str] + self._filter = {} # type: Dict[str, str] - def setMetadata(self, data): - self._metadata = data - self._update() + def setMetadata(self, data: List[Dict[str, Union[str, List[str], int]]]): + if self._metadata != data: + self._metadata = data + self._update() - def _update(self): - items = [] + def _update(self) -> None: + items = [] # type: List[Dict[str, Union[str, List[str], int, None]]] if not self._metadata: - self.setItems([]) + self.setItems(items) return for author in self._metadata: items.append({ - "id": author["author_id"], - "name": author["display_name"], - "email": author["email"] if "email" in author else None, - "website": author["website"], - "package_count": author["package_count"] if "package_count" in author else 0, - "package_types": author["package_types"] if "package_types" in author else [], - "icon_url": author["icon_url"] if "icon_url" in author else None, - "description": "Material and quality profiles from {author_name}".format(author_name = author["display_name"]) + "id": author.get("author_id"), + "name": author.get("display_name"), + "email": author.get("email"), + "website": author.get("website"), + "package_count": author.get("package_count", 0), + "package_types": author.get("package_types", []), + "icon_url": author.get("icon_url"), + "description": "Material and quality profiles from {author_name}".format(author_name = author.get("display_name", "")) }) # Filter on all the key-word arguments. for key, value in self._filter.items(): if key is "package_types": - key_filter = lambda item, value = value: value in item["package_types"] + key_filter = lambda item, value = value: value in item["package_types"] # type: ignore elif "*" in value: - key_filter = lambda item, key = key, value = value: self._matchRegExp(item, key, value) + key_filter = lambda item, key = key, value = value: self._matchRegExp(item, key, value) # type: ignore else: - key_filter = lambda item, key = key, value = value: self._matchString(item, key, value) - items = filter(key_filter, items) + key_filter = lambda item, key = key, value = value: self._matchString(item, key, value) # type: ignore + items = filter(key_filter, items) # type: ignore # Execute all filters. filtered_items = list(items) diff --git a/plugins/Toolbox/src/PackagesModel.py b/plugins/Toolbox/src/PackagesModel.py index a31facf75a..d94fdf6bb7 100644 --- a/plugins/Toolbox/src/PackagesModel.py +++ b/plugins/Toolbox/src/PackagesModel.py @@ -33,20 +33,25 @@ class PackagesModel(ListModel): self.addRoleName(Qt.UserRole + 12, "last_updated") self.addRoleName(Qt.UserRole + 13, "is_bundled") self.addRoleName(Qt.UserRole + 14, "is_active") - 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 + 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") self.addRoleName(Qt.UserRole + 18, "download_count") self.addRoleName(Qt.UserRole + 19, "tags") self.addRoleName(Qt.UserRole + 20, "links") self.addRoleName(Qt.UserRole + 21, "website") + self.addRoleName(Qt.UserRole + 22, "login_required") + self.addRoleName(Qt.UserRole + 23, "average_rating") + self.addRoleName(Qt.UserRole + 24, "num_ratings") + self.addRoleName(Qt.UserRole + 25, "user_rating") # List of filters for queries. The result is the union of the each list of results. self._filter = {} # type: Dict[str, str] def setMetadata(self, data): - self._metadata = data - self._update() + if self._metadata != data: + self._metadata = data + self._update() def _update(self): items = [] @@ -99,6 +104,10 @@ class PackagesModel(ListModel): "tags": package["tags"] if "tags" in package else [], "links": links_dict, "website": package["website"] if "website" in package else None, + "login_required": "login-required" in package.get("tags", []), + "average_rating": float(package.get("rating", {}).get("average", 0)), + "num_ratings": package.get("rating", {}).get("count", 0), + "user_rating": package.get("rating", {}).get("user_rating", 0) }) # Filter on all the key-word arguments. diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py index 562a964f01..ccd181cdbc 100644 --- a/plugins/Toolbox/src/Toolbox.py +++ b/plugins/Toolbox/src/Toolbox.py @@ -13,11 +13,11 @@ from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkRepl from UM.Logger import Logger from UM.PluginRegistry import PluginRegistry from UM.Extension import Extension -from UM.Qt.ListModel import ListModel from UM.i18n import i18nCatalog from UM.Version import Version -import cura +from cura import ApplicationMetadata +from cura import UltimakerCloudAuthentication from cura.CuraApplication import CuraApplication from .AuthorsModel import AuthorsModel @@ -31,17 +31,14 @@ i18n_catalog = i18nCatalog("cura") ## The Toolbox class is responsible of communicating with the server through the API class Toolbox(QObject, Extension): - DEFAULT_CLOUD_API_ROOT = "https://api.ultimaker.com" #type: str - DEFAULT_CLOUD_API_VERSION = 1 #type: int - def __init__(self, application: CuraApplication) -> None: super().__init__() self._application = application # type: CuraApplication - self._sdk_version = None # type: Optional[Union[str, int]] - self._cloud_api_version = None # type: Optional[int] - self._cloud_api_root = None # type: Optional[str] + self._sdk_version = ApplicationMetadata.CuraSDKVersion # type: Union[str, int] + self._cloud_api_version = UltimakerCloudAuthentication.CuraCloudAPIVersion # type: int + self._cloud_api_root = UltimakerCloudAuthentication.CuraCloudAPIRoot # type: str self._api_url = None # type: Optional[str] # Network: @@ -50,47 +47,35 @@ class Toolbox(QObject, Extension): self._download_progress = 0 # type: float self._is_downloading = False # type: bool self._network_manager = None # type: Optional[QNetworkAccessManager] - self._request_header = [ - b"User-Agent", - str.encode( - "%s/%s (%s %s)" % ( - self._application.getApplicationName(), - self._application.getVersion(), - platform.system(), - platform.machine(), - ) - ) - ] + self._request_headers = [] # type: List[Tuple[bytes, bytes]] + self._updateRequestHeader() + + self._request_urls = {} # type: Dict[str, QUrl] self._to_update = [] # type: List[str] # Package_ids that are waiting to be updated self._old_plugin_ids = set() # type: Set[str] self._old_plugin_metadata = dict() # type: Dict[str, Dict[str, Any]] - # Data: - self._metadata = { + # The responses as given by the server parsed to a list. + self._server_response_data = { "authors": [], - "packages": [], - "plugins_showcase": [], - "plugins_available": [], - "plugins_installed": [], - "materials_showcase": [], - "materials_available": [], - "materials_installed": [], - "materials_generic": [] + "packages": [] } # type: Dict[str, List[Any]] # Models: self._models = { "authors": AuthorsModel(self), "packages": PackagesModel(self), - "plugins_showcase": PackagesModel(self), - "plugins_available": PackagesModel(self), - "plugins_installed": PackagesModel(self), - "materials_showcase": AuthorsModel(self), - "materials_available": AuthorsModel(self), - "materials_installed": PackagesModel(self), - "materials_generic": PackagesModel(self) - } # type: Dict[str, ListModel] + } # type: Dict[str, Union[AuthorsModel, PackagesModel]] + + self._plugins_showcase_model = PackagesModel(self) + self._plugins_available_model = PackagesModel(self) + self._plugins_installed_model = PackagesModel(self) + + self._materials_showcase_model = AuthorsModel(self) + self._materials_available_model = AuthorsModel(self) + self._materials_installed_model = PackagesModel(self) + self._materials_generic_model = PackagesModel(self) # These properties are for keeping track of the UI state: # ---------------------------------------------------------------------- @@ -120,6 +105,7 @@ class Toolbox(QObject, Extension): self._restart_dialog_message = "" # type: str self._application.initializationFinished.connect(self._onAppInitialized) + self._application.getCuraAPI().account.loginStateChanged.connect(self._updateRequestHeader) # Signals: # -------------------------------------------------------------------------- @@ -139,12 +125,38 @@ class Toolbox(QObject, Extension): showLicenseDialog = pyqtSignal() uninstallVariablesChanged = pyqtSignal() + def _updateRequestHeader(self): + self._request_headers = [ + (b"User-Agent", + str.encode( + "%s/%s (%s %s)" % ( + self._application.getApplicationName(), + self._application.getVersion(), + platform.system(), + platform.machine(), + ) + )) + ] + access_token = self._application.getCuraAPI().account.accessToken + if access_token: + self._request_headers.append((b"Authorization", "Bearer {}".format(access_token).encode())) + def _resetUninstallVariables(self) -> None: self._package_id_to_uninstall = None # type: Optional[str] self._package_name_to_uninstall = "" self._package_used_materials = [] # type: List[Tuple[GlobalStack, str, str]] self._package_used_qualities = [] # type: List[Tuple[GlobalStack, str, str]] + @pyqtSlot(str, int) + def ratePackage(self, package_id: str, rating: int) -> None: + url = QUrl("{base_url}/packages/{package_id}/ratings".format(base_url=self._api_url, package_id = package_id)) + + self._rate_request = QNetworkRequest(url) + for header_name, header_value in self._request_headers: + cast(QNetworkRequest, self._rate_request).setRawHeader(header_name, header_value) + data = "{\"data\": {\"cura_version\": \"%s\", \"rating\": %i}}" % (Version(self._application.getVersion()), rating) + self._rate_reply = cast(QNetworkAccessManager, self._network_manager).put(self._rate_request, data.encode()) + @pyqtSlot(result = str) def getLicenseDialogPluginName(self) -> str: return self._license_dialog_plugin_name @@ -168,9 +180,6 @@ class Toolbox(QObject, Extension): def _onAppInitialized(self) -> None: self._plugin_registry = self._application.getPluginRegistry() self._package_manager = self._application.getPackageManager() - self._sdk_version = self._getSDKVersion() - self._cloud_api_version = self._getCloudAPIVersion() - self._cloud_api_root = self._getCloudAPIRoot() self._api_url = "{cloud_api_root}/cura-packages/v{cloud_api_version}/cura/v{sdk_version}".format( cloud_api_root = self._cloud_api_root, cloud_api_version = self._cloud_api_version, @@ -178,44 +187,9 @@ class Toolbox(QObject, Extension): ) self._request_urls = { "authors": QUrl("{base_url}/authors".format(base_url = self._api_url)), - "packages": QUrl("{base_url}/packages".format(base_url = self._api_url)), - "plugins_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)), - "plugins_available": QUrl("{base_url}/packages?package_type=plugin".format(base_url = self._api_url)), - "materials_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)), - "materials_available": QUrl("{base_url}/packages?package_type=material".format(base_url = self._api_url)), - "materials_generic": QUrl("{base_url}/packages?package_type=material&tags=generic".format(base_url = self._api_url)) + "packages": QUrl("{base_url}/packages".format(base_url = self._api_url)) } - # Get the API root for the packages API depending on Cura version settings. - def _getCloudAPIRoot(self) -> str: - if not hasattr(cura, "CuraVersion"): - return self.DEFAULT_CLOUD_API_ROOT - if not hasattr(cura.CuraVersion, "CuraCloudAPIRoot"): # type: ignore - return self.DEFAULT_CLOUD_API_ROOT - if not cura.CuraVersion.CuraCloudAPIRoot: # type: ignore - return self.DEFAULT_CLOUD_API_ROOT - return cura.CuraVersion.CuraCloudAPIRoot # type: ignore - - # Get the cloud API version from CuraVersion - def _getCloudAPIVersion(self) -> int: - if not hasattr(cura, "CuraVersion"): - return self.DEFAULT_CLOUD_API_VERSION - if not hasattr(cura.CuraVersion, "CuraCloudAPIVersion"): # type: ignore - return self.DEFAULT_CLOUD_API_VERSION - if not cura.CuraVersion.CuraCloudAPIVersion: # type: ignore - return self.DEFAULT_CLOUD_API_VERSION - return cura.CuraVersion.CuraCloudAPIVersion # type: ignore - - # Get the packages version depending on Cura version settings. - def _getSDKVersion(self) -> Union[int, str]: - if not hasattr(cura, "CuraVersion"): - return self._application.getAPIVersion().getMajor() - if not hasattr(cura.CuraVersion, "CuraSDKVersion"): # type: ignore - return self._application.getAPIVersion().getMajor() - if not cura.CuraVersion.CuraSDKVersion: # type: ignore - return self._application.getAPIVersion().getMajor() - return cura.CuraVersion.CuraSDKVersion # type: ignore - @pyqtSlot() def browsePackages(self) -> None: # Create the network manager: @@ -231,12 +205,6 @@ class Toolbox(QObject, Extension): # Make remote requests: self._makeRequestByType("packages") self._makeRequestByType("authors") - # TODO: Uncomment in the future when the tag-filtered api calls work in the cloud server - # self._makeRequestByType("plugins_showcase") - # self._makeRequestByType("plugins_available") - # self._makeRequestByType("materials_showcase") - # self._makeRequestByType("materials_available") - # self._makeRequestByType("materials_generic") # Gather installed packages: self._updateInstalledModels() @@ -267,12 +235,17 @@ class Toolbox(QObject, Extension): def _convertPluginMetadata(self, plugin_data: Dict[str, Any]) -> Optional[Dict[str, Any]]: try: + highest_sdk_version_supported = Version(0) + for supported_version in plugin_data["plugin"]["supported_sdk_versions"]: + if supported_version > highest_sdk_version_supported: + highest_sdk_version_supported = supported_version + formatted = { "package_id": plugin_data["id"], "package_type": "plugin", "display_name": plugin_data["plugin"]["name"], "package_version": plugin_data["plugin"]["version"], - "sdk_version": plugin_data["plugin"]["api"], + "sdk_version": highest_sdk_version_supported, "author": { "author_id": plugin_data["plugin"]["author"], "display_name": plugin_data["plugin"]["author"] @@ -281,7 +254,7 @@ class Toolbox(QObject, Extension): "description": plugin_data["plugin"]["description"] } return formatted - except: + except KeyError: Logger.log("w", "Unable to convert plugin meta data %s", str(plugin_data)) return None @@ -319,13 +292,10 @@ class Toolbox(QObject, Extension): if plugin_id not in all_plugin_package_ids) self._old_plugin_metadata = {k: v for k, v in self._old_plugin_metadata.items() if k in self._old_plugin_ids} - self._metadata["plugins_installed"] = all_packages["plugin"] + list(self._old_plugin_metadata.values()) - self._models["plugins_installed"].setMetadata(self._metadata["plugins_installed"]) + self._plugins_installed_model.setMetadata(all_packages["plugin"] + list(self._old_plugin_metadata.values())) self.metadataChanged.emit() if "material" in all_packages: - self._metadata["materials_installed"] = all_packages["material"] - # TODO: ADD MATERIALS HERE ONCE MATERIALS PORTION OF TOOLBOX IS LIVE - self._models["materials_installed"].setMetadata(self._metadata["materials_installed"]) + self._materials_installed_model.setMetadata(all_packages["material"]) self.metadataChanged.emit() @pyqtSlot(str) @@ -479,7 +449,7 @@ class Toolbox(QObject, Extension): def getRemotePackage(self, package_id: str) -> Optional[Dict]: # TODO: make the lookup in a dict, not a loop. canUpdate is called for every item. remote_package = None - for package in self._metadata["packages"]: + for package in self._server_response_data["packages"]: if package["package_id"] == package_id: remote_package = package break @@ -491,11 +461,8 @@ class Toolbox(QObject, Extension): def canUpdate(self, package_id: str) -> bool: local_package = self._package_manager.getInstalledPackageInfo(package_id) if local_package is None: - Logger.log("i", "Could not find package [%s] as installed in the package manager, fall back to check the old plugins", - package_id) local_package = self.getOldPluginPackageMetadata(package_id) if local_package is None: - Logger.log("i", "Could not find package [%s] in the old plugins", package_id) return False remote_package = self.getRemotePackage(package_id) @@ -545,8 +512,8 @@ class Toolbox(QObject, Extension): @pyqtSlot(str, result = int) def getNumberOfInstalledPackagesByAuthor(self, author_id: str) -> int: count = 0 - for package in self._metadata["materials_installed"]: - if package["author"]["author_id"] == author_id: + for package in self._materials_installed_model.items: + if package["author_id"] == author_id: count += 1 return count @@ -554,7 +521,7 @@ class Toolbox(QObject, Extension): @pyqtSlot(str, result = int) def getTotalNumberOfMaterialPackagesByAuthor(self, author_id: str) -> int: count = 0 - for package in self._metadata["packages"]: + for package in self._server_response_data["packages"]: if package["package_type"] == "material": if package["author"]["author_id"] == author_id: count += 1 @@ -568,34 +535,31 @@ class Toolbox(QObject, Extension): # Check for plugins that were installed with the old plugin browser def isOldPlugin(self, plugin_id: str) -> bool: - if plugin_id in self._old_plugin_ids: - return True - return False + return plugin_id in self._old_plugin_ids def getOldPluginPackageMetadata(self, plugin_id: str) -> Optional[Dict[str, Any]]: return self._old_plugin_metadata.get(plugin_id) - def loadingComplete(self) -> bool: + def isLoadingComplete(self) -> bool: populated = 0 - for list in self._metadata.items(): - if len(list) > 0: + for metadata_list in self._server_response_data.items(): + if metadata_list: populated += 1 - if populated == len(self._metadata.items()): - return True - return False + return populated == len(self._server_response_data.items()) # Make API Calls # -------------------------------------------------------------------------- - def _makeRequestByType(self, type: str) -> None: - Logger.log("i", "Marketplace: Requesting %s metadata from server.", type) - request = QNetworkRequest(self._request_urls[type]) - request.setRawHeader(*self._request_header) + def _makeRequestByType(self, request_type: str) -> None: + Logger.log("i", "Requesting %s metadata from server.", request_type) + request = QNetworkRequest(self._request_urls[request_type]) + for header_name, header_value in self._request_headers: + request.setRawHeader(header_name, header_value) if self._network_manager: self._network_manager.get(request) @pyqtSlot(str) def startDownload(self, url: str) -> None: - Logger.log("i", "Marketplace: Attempting to download & install package from %s.", url) + Logger.log("i", "Attempting to download & install package from %s.", url) url = QUrl(url) self._download_request = QNetworkRequest(url) if hasattr(QNetworkRequest, "FollowRedirectsAttribute"): @@ -604,7 +568,8 @@ class Toolbox(QObject, Extension): if hasattr(QNetworkRequest, "RedirectPolicyAttribute"): # Patch for Qt 5.9+ cast(QNetworkRequest, self._download_request).setAttribute(QNetworkRequest.RedirectPolicyAttribute, True) - cast(QNetworkRequest, self._download_request).setRawHeader(*self._request_header) + for header_name, header_value in self._request_headers: + cast(QNetworkRequest, self._download_request).setRawHeader(header_name, header_value) self._download_reply = cast(QNetworkAccessManager, self._network_manager).get(self._download_request) self.setDownloadProgress(0) self.setIsDownloading(True) @@ -612,15 +577,15 @@ class Toolbox(QObject, Extension): @pyqtSlot() def cancelDownload(self) -> None: - Logger.log("i", "Marketplace: User cancelled the download of a package.") + Logger.log("i", "User cancelled the download of a package.") self.resetDownload() def resetDownload(self) -> None: if self._download_reply: try: self._download_reply.downloadProgress.disconnect(self._onDownloadProgress) - except TypeError: #Raised when the method is not connected to the signal yet. - pass #Don't need to disconnect. + except TypeError: # Raised when the method is not connected to the signal yet. + pass # Don't need to disconnect. self._download_reply.abort() self._download_reply = None self._download_request = None @@ -646,22 +611,8 @@ class Toolbox(QObject, Extension): self.resetDownload() return - # HACK: These request are not handled independently at this moment, but together from the "packages" call - do_not_handle = [ - "materials_available", - "materials_showcase", - "materials_generic", - "plugins_available", - "plugins_showcase", - ] - if reply.operation() == QNetworkAccessManager.GetOperation: - for type, url in self._request_urls.items(): - - # HACK: Do nothing because we'll handle these from the "packages" call - if type in do_not_handle: - continue - + for response_type, url in self._request_urls.items(): if reply.url() == url: if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200: try: @@ -674,39 +625,33 @@ class Toolbox(QObject, Extension): return # Create model and apply metadata: - if not self._models[type]: - Logger.log("e", "Could not find the %s model.", type) + if not self._models[response_type]: + Logger.log("e", "Could not find the %s model.", response_type) break - self._metadata[type] = json_data["data"] - self._models[type].setMetadata(self._metadata[type]) + self._server_response_data[response_type] = json_data["data"] + self._models[response_type].setMetadata(self._server_response_data[response_type]) - # Do some auto filtering - # TODO: Make multiple API calls in the future to handle this - if type is "packages": - self._models[type].setFilter({"type": "plugin"}) - self.buildMaterialsModels() - self.buildPluginsModels() - if type is "authors": - self._models[type].setFilter({"package_types": "material"}) - if type is "materials_generic": - self._models[type].setFilter({"tags": "generic"}) + if response_type is "packages": + self._models[response_type].setFilter({"type": "plugin"}) + self.reBuildMaterialsModels() + self.reBuildPluginsModels() + elif response_type is "authors": + self._models[response_type].setFilter({"package_types": "material"}) + self._models[response_type].setFilter({"tags": "generic"}) self.metadataChanged.emit() - if self.loadingComplete() is True: + if self.isLoadingComplete(): self.setViewPage("overview") - return except json.decoder.JSONDecodeError: - Logger.log("w", "Marketplace: Received invalid JSON for %s.", type) + Logger.log("w", "Received invalid JSON for %s.", response_type) break else: self.setViewPage("errored") self.resetDownload() - return - - else: + elif reply.operation() == QNetworkAccessManager.PutOperation: # Ignore any operation that is not a get operation pass @@ -716,7 +661,13 @@ class Toolbox(QObject, Extension): self.setDownloadProgress(new_progress) if bytes_sent == bytes_total: self.setIsDownloading(False) - cast(QNetworkReply, self._download_reply).downloadProgress.disconnect(self._onDownloadProgress) + self._download_reply = cast(QNetworkReply, self._download_reply) + self._download_reply.downloadProgress.disconnect(self._onDownloadProgress) + + # Check if the download was sucessfull + if self._download_reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: + Logger.log("w", "Failed to download package. The following error was returned: %s", json.loads(bytes(self._download_reply.readAll()).decode("utf-8"))) + return # Must not delete the temporary file on Windows self._temp_plugin_file = tempfile.NamedTemporaryFile(mode = "w+b", suffix = ".curapackage", delete = False) file_path = self._temp_plugin_file.name @@ -726,10 +677,10 @@ class Toolbox(QObject, Extension): self._onDownloadComplete(file_path) def _onDownloadComplete(self, file_path: str) -> None: - Logger.log("i", "Marketplace: Download complete.") + Logger.log("i", "Download complete.") package_info = self._package_manager.getPackageInfo(file_path) if not package_info: - Logger.log("w", "Marketplace: Package file [%s] was not a valid CuraPackage.", file_path) + Logger.log("w", "Package file [%s] was not a valid CuraPackage.", file_path) return license_content = self._package_manager.getPackageLicense(file_path) @@ -738,7 +689,6 @@ class Toolbox(QObject, Extension): return self.install(file_path) - return # Getter & Setters for Properties: # -------------------------------------------------------------------------- @@ -761,8 +711,9 @@ class Toolbox(QObject, Extension): return self._is_downloading def setActivePackage(self, package: Dict[str, Any]) -> None: - self._active_package = package - self.activePackageChanged.emit() + if self._active_package != package: + self._active_package = package + self.activePackageChanged.emit() ## The active package is the package that is currently being downloaded @pyqtProperty(QObject, fset = setActivePackage, notify = activePackageChanged) @@ -770,16 +721,18 @@ class Toolbox(QObject, Extension): return self._active_package def setViewCategory(self, category: str = "plugin") -> None: - self._view_category = category - self.viewChanged.emit() + if self._view_category != category: + self._view_category = category + self.viewChanged.emit() @pyqtProperty(str, fset = setViewCategory, notify = viewChanged) def viewCategory(self) -> str: return self._view_category def setViewPage(self, page: str = "overview") -> None: - self._view_page = page - self.viewChanged.emit() + if self._view_page != page: + self._view_page = page + self.viewChanged.emit() @pyqtProperty(str, fset = setViewPage, notify = viewChanged) def viewPage(self) -> str: @@ -787,48 +740,48 @@ class Toolbox(QObject, Extension): # Exposed Models: # -------------------------------------------------------------------------- - @pyqtProperty(QObject, notify = metadataChanged) + @pyqtProperty(QObject, constant=True) def authorsModel(self) -> AuthorsModel: return cast(AuthorsModel, self._models["authors"]) - @pyqtProperty(QObject, notify = metadataChanged) + @pyqtProperty(QObject, constant=True) def packagesModel(self) -> PackagesModel: return cast(PackagesModel, self._models["packages"]) - @pyqtProperty(QObject, notify = metadataChanged) + @pyqtProperty(QObject, constant=True) def pluginsShowcaseModel(self) -> PackagesModel: - return cast(PackagesModel, self._models["plugins_showcase"]) + return self._plugins_showcase_model - @pyqtProperty(QObject, notify = metadataChanged) + @pyqtProperty(QObject, constant=True) def pluginsAvailableModel(self) -> PackagesModel: - return cast(PackagesModel, self._models["plugins_available"]) + return self._plugins_available_model - @pyqtProperty(QObject, notify = metadataChanged) + @pyqtProperty(QObject, constant=True) def pluginsInstalledModel(self) -> PackagesModel: - return cast(PackagesModel, self._models["plugins_installed"]) + return self._plugins_installed_model - @pyqtProperty(QObject, notify = metadataChanged) + @pyqtProperty(QObject, constant=True) def materialsShowcaseModel(self) -> AuthorsModel: - return cast(AuthorsModel, self._models["materials_showcase"]) + return self._materials_showcase_model - @pyqtProperty(QObject, notify = metadataChanged) + @pyqtProperty(QObject, constant=True) def materialsAvailableModel(self) -> AuthorsModel: - return cast(AuthorsModel, self._models["materials_available"]) + return self._materials_available_model - @pyqtProperty(QObject, notify = metadataChanged) + @pyqtProperty(QObject, constant=True) def materialsInstalledModel(self) -> PackagesModel: - return cast(PackagesModel, self._models["materials_installed"]) + return self._materials_installed_model - @pyqtProperty(QObject, notify=metadataChanged) + @pyqtProperty(QObject, constant=True) def materialsGenericModel(self) -> PackagesModel: - return cast(PackagesModel, self._models["materials_generic"]) + return self._materials_generic_model # Filter Models: # -------------------------------------------------------------------------- @pyqtSlot(str, str, str) def filterModelByProp(self, model_type: str, filter_type: str, parameter: str) -> None: if not self._models[model_type]: - Logger.log("w", "Marketplace: Couldn't filter %s model because it doesn't exist.", model_type) + Logger.log("w", "Couldn't filter %s model because it doesn't exist.", model_type) return self._models[model_type].setFilter({filter_type: parameter}) self.filterChanged.emit() @@ -836,7 +789,7 @@ class Toolbox(QObject, Extension): @pyqtSlot(str, "QVariantMap") def setFilters(self, model_type: str, filter_dict: dict) -> None: if not self._models[model_type]: - Logger.log("w", "Marketplace: Couldn't filter %s model because it doesn't exist.", model_type) + Logger.log("w", "Couldn't filter %s model because it doesn't exist.", model_type) return self._models[model_type].setFilter(filter_dict) self.filterChanged.emit() @@ -844,21 +797,21 @@ class Toolbox(QObject, Extension): @pyqtSlot(str) def removeFilters(self, model_type: str) -> None: if not self._models[model_type]: - Logger.log("w", "Marketplace: Couldn't remove filters on %s model because it doesn't exist.", model_type) + Logger.log("w", "Couldn't remove filters on %s model because it doesn't exist.", model_type) return self._models[model_type].setFilter({}) self.filterChanged.emit() # HACK(S): # -------------------------------------------------------------------------- - def buildMaterialsModels(self) -> None: - self._metadata["materials_showcase"] = [] - self._metadata["materials_available"] = [] - self._metadata["materials_generic"] = [] + def reBuildMaterialsModels(self) -> None: + materials_showcase_metadata = [] + materials_available_metadata = [] + materials_generic_metadata = [] - processed_authors = [] # type: List[str] + processed_authors = [] # type: List[str] - for item in self._metadata["packages"]: + for item in self._server_response_data["packages"]: if item["package_type"] == "material": author = item["author"] @@ -867,30 +820,29 @@ class Toolbox(QObject, Extension): # Generic materials to be in the same section if "generic" in item["tags"]: - self._metadata["materials_generic"].append(item) + materials_generic_metadata.append(item) else: if "showcase" in item["tags"]: - self._metadata["materials_showcase"].append(author) + materials_showcase_metadata.append(author) else: - self._metadata["materials_available"].append(author) + materials_available_metadata.append(author) processed_authors.append(author["author_id"]) - self._models["materials_showcase"].setMetadata(self._metadata["materials_showcase"]) - self._models["materials_available"].setMetadata(self._metadata["materials_available"]) - self._models["materials_generic"].setMetadata(self._metadata["materials_generic"]) + self._materials_showcase_model.setMetadata(materials_showcase_metadata) + self._materials_available_model.setMetadata(materials_available_metadata) + self._materials_generic_model.setMetadata(materials_generic_metadata) - def buildPluginsModels(self) -> None: - self._metadata["plugins_showcase"] = [] - self._metadata["plugins_available"] = [] + def reBuildPluginsModels(self) -> None: + plugins_showcase_metadata = [] + plugins_available_metadata = [] - for item in self._metadata["packages"]: + for item in self._server_response_data["packages"]: if item["package_type"] == "plugin": - if "showcase" in item["tags"]: - self._metadata["plugins_showcase"].append(item) + plugins_showcase_metadata.append(item) else: - self._metadata["plugins_available"].append(item) + plugins_available_metadata.append(item) - self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"]) - self._models["plugins_available"].setMetadata(self._metadata["plugins_available"]) + self._plugins_showcase_model.setMetadata(plugins_showcase_metadata) + self._plugins_available_model.setMetadata(plugins_available_metadata) diff --git a/plugins/UFPWriter/plugin.json b/plugins/UFPWriter/plugin.json index ab590353e0..288d6acf77 100644 --- a/plugins/UFPWriter/plugin.json +++ b/plugins/UFPWriter/plugin.json @@ -1,8 +1,8 @@ { "name": "UFP Writer", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides support for writing Ultimaker Format Packages.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/__init__.py b/plugins/UM3NetworkPrinting/__init__.py index e2ad5a2b12..3da7795589 100644 --- a/plugins/UM3NetworkPrinting/__init__.py +++ b/plugins/UM3NetworkPrinting/__init__.py @@ -1,11 +1,15 @@ # Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. - from .src import DiscoverUM3Action from .src import UM3OutputDevicePlugin + def getMetaData(): return {} + def register(app): - return { "output_device": UM3OutputDevicePlugin.UM3OutputDevicePlugin(), "machine_action": DiscoverUM3Action.DiscoverUM3Action()} \ No newline at end of file + return { + "output_device": UM3OutputDevicePlugin.UM3OutputDevicePlugin(), + "machine_action": DiscoverUM3Action.DiscoverUM3Action() + } diff --git a/plugins/UM3NetworkPrinting/plugin.json b/plugins/UM3NetworkPrinting/plugin.json index d415338374..088b4dae6a 100644 --- a/plugins/UM3NetworkPrinting/plugin.json +++ b/plugins/UM3NetworkPrinting/plugin.json @@ -2,7 +2,7 @@ "name": "UM3 Network Connection", "author": "Ultimaker B.V.", "description": "Manages network connections to Ultimaker 3 printers.", - "version": "1.0.0", - "api": 5, + "version": "1.0.1", + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/UM3NetworkPrinting/resources/png/Ultimaker 3 Extended.png b/plugins/UM3NetworkPrinting/resources/png/Ultimaker 3 Extended.png new file mode 100644 index 0000000000..1ce19c2933 Binary files /dev/null and b/plugins/UM3NetworkPrinting/resources/png/Ultimaker 3 Extended.png differ diff --git a/plugins/UM3NetworkPrinting/resources/png/Ultimaker 3.png b/plugins/UM3NetworkPrinting/resources/png/Ultimaker 3.png new file mode 100644 index 0000000000..4639cb3fde Binary files /dev/null and b/plugins/UM3NetworkPrinting/resources/png/Ultimaker 3.png differ diff --git a/plugins/UM3NetworkPrinting/resources/png/Ultimaker S5.png b/plugins/UM3NetworkPrinting/resources/png/Ultimaker S5.png new file mode 100644 index 0000000000..29ba428e38 Binary files /dev/null and b/plugins/UM3NetworkPrinting/resources/png/Ultimaker S5.png differ diff --git a/plugins/UM3NetworkPrinting/resources/qml/CameraButton.qml b/plugins/UM3NetworkPrinting/resources/qml/CameraButton.qml index 7e5c254e5c..6f054f9c19 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/CameraButton.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/CameraButton.qml @@ -8,11 +8,13 @@ import UM 1.3 as UM import Cura 1.0 as Cura Rectangle { + id: base property var iconSource: null; - color: clickArea.containsMouse ? UM.Theme.getColor("primary_hover") : UM.Theme.getColor("primary"); // "Cura Blue" + color: "#0a0850" // TODO: Theme! height: width; radius: Math.round(0.5 * width); - width: 36 * screenScaleFactor; + width: 24 * screenScaleFactor; + property var enabled: true UM.RecolorImage { id: icon; @@ -29,12 +31,18 @@ Rectangle { MouseArea { id: clickArea; anchors.fill: parent; - hoverEnabled: true; + hoverEnabled: base.enabled onClicked: { - if (OutputDevice.activeCameraUrl != "") { - OutputDevice.setActiveCameraUrl(""); - } else { - OutputDevice.setActiveCameraUrl(modelData.cameraUrl); + if (base.enabled) + { + if (OutputDevice.activeCameraUrl != "") + { + OutputDevice.setActiveCameraUrl("") + } + else + { + OutputDevice.setActiveCameraUrl(modelData.cameraUrl) + } } } } diff --git a/plugins/UM3NetworkPrinting/resources/qml/ClusterControlItem.qml b/plugins/UM3NetworkPrinting/resources/qml/ClusterControlItem.qml deleted file mode 100644 index 068c369a3f..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/ClusterControlItem.qml +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.3 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.3 -import UM 1.3 as UM -import Cura 1.0 as Cura - -Component { - Rectangle { - id: base; - property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width; - property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width; - anchors.fill: parent; - color: UM.Theme.getColor("sidebar"); - visible: OutputDevice != null; - - UM.I18nCatalog { - id: catalog; - name: "cura"; - } - - Label { - id: printingLabel; - anchors { - left: parent.left; - leftMargin: 4 * UM.Theme.getSize("default_margin").width; - margins: 2 * UM.Theme.getSize("default_margin").width; - right: parent.right; - top: parent.top; - } - color: UM.Theme.getColor("text"); - elide: Text.ElideRight; - font: UM.Theme.getFont("large"); - text: catalog.i18nc("@label", "Printing"); - } - - Label { - id: managePrintersLabel; - anchors { - bottom: printingLabel.bottom; - right: printerScrollView.right; - rightMargin: 4 * UM.Theme.getSize("default_margin").width; - } - color: UM.Theme.getColor("primary"); // "Cura Blue" - font: UM.Theme.getFont("default"); - linkColor: UM.Theme.getColor("primary"); // "Cura Blue" - text: catalog.i18nc("@label link to connect manager", "Manage printers"); - } - - MouseArea { - anchors.fill: managePrintersLabel; - hoverEnabled: true; - onClicked: Cura.MachineManager.printerOutputDevices[0].openPrinterControlPanel(); - onEntered: managePrintersLabel.font.underline = true; - onExited: managePrintersLabel.font.underline = false; - } - - // Skeleton loading - Column { - id: skeletonLoader; - anchors { - left: parent.left; - leftMargin: UM.Theme.getSize("wide_margin").width; - right: parent.right; - rightMargin: UM.Theme.getSize("wide_margin").width; - top: printingLabel.bottom; - topMargin: UM.Theme.getSize("default_margin").height; - } - spacing: UM.Theme.getSize("default_margin").height - 10; - visible: printerList.count === 0; - - PrinterCard { - printer: null; - } - PrinterCard { - printer: null; - } - } - - // Actual content - ScrollView { - id: printerScrollView; - anchors { - bottom: parent.bottom; - left: parent.left; - right: parent.right; - top: printingLabel.bottom; - topMargin: UM.Theme.getSize("default_margin").height; - } - style: UM.Theme.styles.scrollview; - - ListView { - id: printerList; - property var currentIndex: -1; - anchors { - fill: parent; - leftMargin: UM.Theme.getSize("wide_margin").width; - rightMargin: UM.Theme.getSize("wide_margin").width; - } - delegate: PrinterCard { - printer: modelData; - } - model: OutputDevice.printers; - spacing: UM.Theme.getSize("default_margin").height - 10; - } - } - } -} diff --git a/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml b/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml deleted file mode 100644 index d210ab40f3..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml +++ /dev/null @@ -1,132 +0,0 @@ -// 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.4 -import QtQuick.Controls.Styles 1.4 -import UM 1.3 as UM -import Cura 1.0 as Cura - -Component { - Rectangle { - id: monitorFrame; - property var emphasisColor: UM.Theme.getColor("setting_control_border_highlight"); - property var cornerRadius: UM.Theme.getSize("monitor_corner_radius").width; - color: UM.Theme.getColor("viewport_background"); - height: maximumHeight; - onVisibleChanged: { - if (monitorFrame != null && !monitorFrame.visible) { - OutputDevice.setActiveCameraUrl(""); - } - } - width: maximumWidth; - - UM.I18nCatalog { - id: catalog; - name: "cura"; - } - - Label { - id: manageQueueLabel; - anchors { - bottom: queuedLabel.bottom; - right: queuedPrintJobs.right; - rightMargin: 3 * UM.Theme.getSize("default_margin").width; - } - color: UM.Theme.getColor("primary"); - font: UM.Theme.getFont("default"); - linkColor: UM.Theme.getColor("primary"); - text: catalog.i18nc("@label link to connect manager", "Manage queue"); - } - - MouseArea { - anchors.fill: manageQueueLabel; - hoverEnabled: true; - onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel(); - onEntered: manageQueueLabel.font.underline = true; - onExited: manageQueueLabel.font.underline = false; - } - - Label { - id: queuedLabel; - anchors { - left: queuedPrintJobs.left; - leftMargin: 3 * UM.Theme.getSize("default_margin").width + 5 * screenScaleFactor; - top: parent.top; - topMargin: 2 * UM.Theme.getSize("default_margin").height; - } - color: UM.Theme.getColor("text"); - font: UM.Theme.getFont("large"); - text: catalog.i18nc("@label", "Queued"); - } - - Column { - id: skeletonLoader; - anchors { - bottom: parent.bottom; - bottomMargin: UM.Theme.getSize("default_margin").height; - horizontalCenter: parent.horizontalCenter; - top: queuedLabel.bottom; - topMargin: UM.Theme.getSize("default_margin").height; - } - visible: !queuedPrintJobs.visible; - width: Math.min(800 * screenScaleFactor, maximumWidth); - - PrintJobInfoBlock { - anchors { - left: parent.left; - leftMargin: UM.Theme.getSize("default_margin").width; - right: parent.right; - rightMargin: UM.Theme.getSize("default_margin").width; - } - printJob: null; // Use as skeleton - } - - PrintJobInfoBlock { - anchors { - left: parent.left; - leftMargin: UM.Theme.getSize("default_margin").width; - right: parent.right; - rightMargin: UM.Theme.getSize("default_margin").width; - } - printJob: null; // Use as skeleton - } - } - - ScrollView { - id: queuedPrintJobs; - anchors { - top: queuedLabel.bottom; - topMargin: UM.Theme.getSize("default_margin").height; - horizontalCenter: parent.horizontalCenter; - bottomMargin: UM.Theme.getSize("default_margin").height; - bottom: parent.bottom; - } - style: UM.Theme.styles.scrollview; - visible: OutputDevice.receivedPrintJobs; - width: Math.min(800 * screenScaleFactor, maximumWidth); - - ListView { - id: printJobList; - anchors.fill: parent; - delegate: PrintJobInfoBlock { - anchors { - left: parent.left; - leftMargin: UM.Theme.getSize("default_margin").width; - right: parent.right; - rightMargin: UM.Theme.getSize("default_margin").width; - } - printJob: modelData; - } - model: OutputDevice.queuedPrintJobs; - spacing: UM.Theme.getSize("default_margin").height - 2 * UM.Theme.getSize("monitor_shadow_radius").width; - } - } - - PrinterVideoStream { - anchors.fill: parent; - cameraUrl: OutputDevice.activeCameraUrl; - visible: OutputDevice.activeCameraUrl != ""; - } - } -} diff --git a/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml index 58443115a9..3883a7e285 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml @@ -28,7 +28,7 @@ Cura.MachineAction // Check if there is another instance with the same key if (!manager.existsKey(printerKey)) { - manager.setKey(printerKey) + manager.associateActiveMachineWithPrinterDevice(base.selectedDevice) manager.setGroupName(printerName) // TODO To change when the groups have a name completed() } @@ -64,6 +64,7 @@ Cura.MachineAction width: parent.width text: catalog.i18nc("@title:window", "Connect to Networked Printer") wrapMode: Text.WordWrap + renderType: Text.NativeRendering font.pointSize: 18 } @@ -72,6 +73,7 @@ Cura.MachineAction id: pageDescription width: parent.width wrapMode: Text.WordWrap + renderType: Text.NativeRendering text: catalog.i18nc("@label", "To print directly to your printer over the network, please make sure your printer is connected to the network using a network cable or by connecting your printer to your WIFI network. If you don't connect Cura with your printer, you can still use a USB drive to transfer g-code files to your printer.\n\nSelect your printer from the list below:") } @@ -182,6 +184,7 @@ Cura.MachineAction text: listview.model[index].name color: parent.ListView.isCurrentItem ? palette.highlightedText : palette.text elide: Text.ElideRight + renderType: Text.NativeRendering } MouseArea @@ -204,6 +207,7 @@ Cura.MachineAction anchors.left: parent.left anchors.right: parent.right wrapMode: Text.WordWrap + renderType: Text.NativeRendering text: catalog.i18nc("@label", "If your printer is not listed, read the network printing troubleshooting guide").arg("https://ultimaker.com/en/troubleshooting"); onLinkActivated: Qt.openUrlExternally(link) } @@ -219,8 +223,9 @@ Cura.MachineAction width: parent.width wrapMode: Text.WordWrap text: base.selectedDevice ? base.selectedDevice.name : "" - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") elide: Text.ElideRight + renderType: Text.NativeRendering } Grid { @@ -231,12 +236,14 @@ Cura.MachineAction { width: Math.round(parent.width * 0.5) wrapMode: Text.WordWrap + renderType: Text.NativeRendering text: catalog.i18nc("@label", "Type") } Label { width: Math.round(parent.width * 0.5) wrapMode: Text.WordWrap + renderType: Text.NativeRendering text: { if(base.selectedDevice) @@ -268,24 +275,28 @@ Cura.MachineAction { width: Math.round(parent.width * 0.5) wrapMode: Text.WordWrap + renderType: Text.NativeRendering text: catalog.i18nc("@label", "Firmware version") } Label { width: Math.round(parent.width * 0.5) wrapMode: Text.WordWrap + renderType: Text.NativeRendering text: base.selectedDevice ? base.selectedDevice.firmwareVersion : "" } Label { width: Math.round(parent.width * 0.5) wrapMode: Text.WordWrap + renderType: Text.NativeRendering text: catalog.i18nc("@label", "Address") } Label { width: Math.round(parent.width * 0.5) wrapMode: Text.WordWrap + renderType: Text.NativeRendering text: base.selectedDevice ? base.selectedDevice.ipAddress : "" } } @@ -294,6 +305,7 @@ Cura.MachineAction { width: parent.width wrapMode: Text.WordWrap + renderType: Text.NativeRendering text:{ // The property cluster size does not exist for older UM3 devices. if(!base.selectedDevice || base.selectedDevice.clusterSize == null || base.selectedDevice.clusterSize == 1) @@ -315,6 +327,7 @@ Cura.MachineAction { width: parent.width wrapMode: Text.WordWrap + renderType: Text.NativeRendering visible: base.selectedDevice != null && !base.completeProperties text: catalog.i18nc("@label", "The printer at this address has not yet responded." ) } @@ -358,9 +371,10 @@ Cura.MachineAction Label { - text: catalog.i18nc("@alabel","Enter the IP address or hostname of your printer on the network.") + text: catalog.i18nc("@alabel", "Enter the IP address or hostname of your printer on the network.") width: parent.width wrapMode: Text.WordWrap + renderType: Text.NativeRendering } TextField diff --git a/plugins/UM3NetworkPrinting/resources/qml/ExpandableCard.qml b/plugins/UM3NetworkPrinting/resources/qml/ExpandableCard.qml new file mode 100644 index 0000000000..d4c123652d --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/ExpandableCard.qml @@ -0,0 +1,87 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM +import Cura 1.0 as Cura + +// TODO: Theme & documentation! +// The expandable component has 3 major sub components: +// * The headerItem Always visible and should hold some info about what happens if the component is expanded +// * The popupItem The content that needs to be shown if the component is expanded. +Item +{ + id: base + + property bool expanded: false + property bool enabled: true + property var borderWidth: 1 + property color borderColor: "#CCCCCC" + property color headerBackgroundColor: "white" + property color headerHoverColor: "#e8f2fc" + property color drawerBackgroundColor: "white" + property alias headerItem: header.children + property alias drawerItem: drawer.children + + width: parent.width + height: childrenRect.height + + Rectangle + { + id: header + border + { + color: borderColor + width: borderWidth + } + color: base.enabled && headerMouseArea.containsMouse ? headerHoverColor : headerBackgroundColor + height: childrenRect.height + width: parent.width + Behavior on color + { + ColorAnimation + { + duration: 100 + } + } + } + + MouseArea + { + id: headerMouseArea + anchors.fill: header + onClicked: + { + if (!base.enabled) return + base.expanded = !base.expanded + } + hoverEnabled: base.enabled + } + + Rectangle + { + id: drawer + anchors + { + top: header.bottom + topMargin: -1 + } + border + { + color: borderColor + width: borderWidth + } + clip: true + color: headerBackgroundColor + height: base.expanded ? childrenRect.height : 0 + width: parent.width + Behavior on height + { + NumberAnimation + { + duration: 100 + } + } + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/HorizontalLine.qml b/plugins/UM3NetworkPrinting/resources/qml/HorizontalLine.qml deleted file mode 100644 index aeb92697ad..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/HorizontalLine.qml +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.3 -import QtQuick.Controls 2.0 -import UM 1.3 as UM - -Rectangle { - color: UM.Theme.getColor("monitor_lining_light"); // TODO: Maybe theme separately? Maybe not. - height: UM.Theme.getSize("default_lining").height; - width: parent.width; -} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorBuildplateConfiguration.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorBuildplateConfiguration.qml new file mode 100644 index 0000000000..192a5a7f76 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorBuildplateConfiguration.qml @@ -0,0 +1,74 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +/** + * This component comprises a buildplate icon and the buildplate name. It is + * used by the MonitorPrinterConfiguration component along with two instances + * of MonitorExtruderConfiguration. + * + * NOTE: For most labels, a fixed height with vertical alignment is used to make + * layouts more deterministic (like the fixed-size textboxes used in original + * mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted + * with '// FIXED-LINE-HEIGHT:'. + */ +Item +{ + // The buildplate name + property var buildplate: null + + // Height is one 18px label/icon + height: 18 * screenScaleFactor // TODO: Theme! + width: childrenRect.width + + Row + { + height: parent.height + spacing: UM.Theme.getSize("print_setup_slider_handle").width // TODO: Theme! (Should be same as extruder spacing) + + // This wrapper ensures that the buildplate icon is located centered + // below an extruder icon. + Item + { + height: parent.height + width: 32 * screenScaleFactor // Ensure the icon is centered under the extruder icon (same width) + + Rectangle + { + anchors.centerIn: parent + height: parent.height + width: height + color: buildplateIcon.visible > 0 ? "transparent" : "#eeeeee" // TODO: Theme! + radius: Math.floor(height / 2) + } + + UM.RecolorImage + { + id: buildplateIcon + anchors.centerIn: parent + color: "#0a0850" // TODO: Theme! (Standard purple) + height: parent.height + source: "../svg/icons/buildplate.svg" + width: height + visible: buildplate + } + } + + Label + { + id: buildplateLabel + color: "#191919" // TODO: Theme! + elide: Text.ElideRight + font: UM.Theme.getFont("default") // 12pt, regular + text: buildplate ? buildplate : "" + visible: text !== "" + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorCarousel.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorCarousel.qml new file mode 100644 index 0000000000..de24ee5a8c --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorCarousel.qml @@ -0,0 +1,258 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Controls 2.0 +import QtGraphicalEffects 1.0 +import UM 1.3 as UM + +Item +{ + id: base + + property var currentIndex: 0 + property var tileWidth: 834 * screenScaleFactor // TODO: Theme! + property var tileHeight: 216 * screenScaleFactor // TODO: Theme! + property var tileSpacing: 60 * screenScaleFactor // TODO: Theme! + + // Array/model of printers to populate the carousel with + property var printers: [] + + // Maximum distance the carousel can be shifted + property var maxOffset: (printers.length - 1) * (tileWidth + tileSpacing) + + height: centerSection.height + width: maximumWidth + + // Enable keyboard navigation + Keys.onLeftPressed: navigateTo(currentIndex - 1) + Keys.onRightPressed: navigateTo(currentIndex + 1) + + Item + { + id: leftHint + anchors + { + right: leftButton.left + rightMargin: 12 * screenScaleFactor // TODO: Theme! + left: parent.left + } + height: parent.height + z: 10 + LinearGradient + { + anchors.fill: parent + start: Qt.point(0, 0) + end: Qt.point(leftHint.width, 0) + gradient: Gradient + { + GradientStop + { + position: 0.0 + color: "#fff6f6f6" // TODO: Theme! + } + GradientStop + { + position: 1.0 + color: "#66f6f6f6" // TODO: Theme! + } + } + } + MouseArea + { + anchors.fill: parent + onClicked: navigateTo(currentIndex - 1) + } + } + + Button + { + id: leftButton + anchors + { + verticalCenter: parent.verticalCenter + right: centerSection.left + rightMargin: 12 * screenScaleFactor // TODO: Theme! + } + width: 36 * screenScaleFactor // TODO: Theme! + height: 72 * screenScaleFactor // TODO: Theme! + visible: currentIndex > 0 + hoverEnabled: true + z: 10 + onClicked: navigateTo(currentIndex - 1) + background: Rectangle + { + color: leftButton.hovered ? "#e8f2fc" : "#ffffff" // TODO: Theme! + border.width: 1 * screenScaleFactor // TODO: Theme! + border.color: "#cccccc" // TODO: Theme! + radius: 2 * screenScaleFactor // TODO: Theme! + } + contentItem: Item + { + anchors.fill: parent + UM.RecolorImage + { + anchors.centerIn: parent + width: 18 // TODO: Theme! + height: width // TODO: Theme! + sourceSize.width: width // TODO: Theme! + sourceSize.height: width // TODO: Theme! + color: "#152950" // TODO: Theme! + source: UM.Theme.getIcon("arrow_left") + } + } + } + + Item + { + id: centerSection + anchors + { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + width: tileWidth + height: tiles.height + z: 1 + + Row + { + id: tiles + height: childrenRect.height + width: 5 * tileWidth + 4 * tileSpacing // TODO: Theme! + x: 0 + z: 0 + Behavior on x + { + NumberAnimation + { + duration: 200 + easing.type: Easing.InOutCubic + } + } + spacing: 60 * screenScaleFactor // TODO: Theme! + + Repeater + { + model: printers + MonitorPrinterCard + { + printer: modelData + enabled: model.index == currentIndex + } + } + } + } + + Button + { + id: rightButton + anchors + { + verticalCenter: parent.verticalCenter + left: centerSection.right + leftMargin: 12 * screenScaleFactor // TODO: Theme! + } + width: 36 * screenScaleFactor // TODO: Theme! + height: 72 * screenScaleFactor // TODO: Theme! + z: 10 + visible: currentIndex < printers.length - 1 + onClicked: navigateTo(currentIndex + 1) + hoverEnabled: true + background: Rectangle + { + color: rightButton.hovered ? "#e8f2fc" : "#ffffff" // TODO: Theme! + border.width: 1 * screenScaleFactor // TODO: Theme! + border.color: "#cccccc" // TODO: Theme! + radius: 2 * screenScaleFactor // TODO: Theme! + } + contentItem: Item + { + anchors.fill: parent + UM.RecolorImage + { + anchors.centerIn: parent + width: 18 // TODO: Theme! + height: width // TODO: Theme! + sourceSize.width: width // TODO: Theme! + sourceSize.height: width // TODO: Theme! + color: "#152950" // TODO: Theme! + source: UM.Theme.getIcon("arrow_right") + } + } + } + + Item + { + id: rightHint + anchors + { + left: rightButton.right + leftMargin: 12 * screenScaleFactor // TODO: Theme! + right: parent.right + } + height: centerSection.height + z: 10 + + LinearGradient + { + anchors.fill: parent + start: Qt.point(0, 0) + end: Qt.point(rightHint.width, 0) + gradient: Gradient + { + GradientStop + { + position: 0.0 + color: "#66f6f6f6" // TODO: Theme! + } + GradientStop + { + position: 1.0 + color: "#fff6f6f6" // TODO: Theme! + } + } + } + MouseArea + { + anchors.fill: parent + onClicked: navigateTo(currentIndex + 1) + } + } + + Row + { + id: navigationDots + anchors + { + horizontalCenter: centerSection.horizontalCenter + top: centerSection.bottom + topMargin: 36 * screenScaleFactor // TODO: Theme! + } + spacing: 8 * screenScaleFactor // TODO: Theme! + visible: printers.length > 1 + Repeater + { + model: printers + Button + { + background: Rectangle + { + color: model.index == currentIndex ? "#777777" : "#d8d8d8" // TODO: Theme! + radius: Math.floor(width / 2) + width: 12 * screenScaleFactor // TODO: Theme! + height: width // TODO: Theme! + } + onClicked: navigateTo(model.index) + } + } + } + + function navigateTo( i ) { + if (i >= 0 && i < printers.length) + { + tiles.x = -1 * i * (tileWidth + tileSpacing) + currentIndex = i + } + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorConfigOverrideDialog.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorConfigOverrideDialog.qml new file mode 100644 index 0000000000..1718994d83 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorConfigOverrideDialog.qml @@ -0,0 +1,142 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 +import QtQuick.Dialogs 1.2 +import UM 1.3 as UM + +UM.Dialog +{ + id: overrideConfirmationDialog + + property var printer: null + + minimumWidth: screenScaleFactor * 640; + minimumHeight: screenScaleFactor * 320; + width: minimumWidth + height: minimumHeight + title: catalog.i18nc("@title:window", "Configuration Changes") + rightButtons: + [ + Button + { + id: overrideButton + anchors.margins: UM.Theme.getSize("default_margin").width + text: catalog.i18nc("@action:button", "Override") + onClicked: + { + OutputDevice.forceSendJob(printer.activePrintJob.key) + overrideConfirmationDialog.close() + } + }, + Button + { + id: cancelButton + anchors.margins: UM.Theme.getSize("default_margin").width + text: catalog.i18nc("@action:button", "Cancel") + onClicked: + { + overrideConfirmationDialog.reject() + } + } + ] + + Label + { + anchors + { + fill: parent + margins: 36 * screenScaleFactor // TODO: Theme! + bottomMargin: 56 * screenScaleFactor // TODO: Theme! + } + wrapMode: Text.WordWrap + text: + { + if (!printer || !printer.activePrintJob) + { + return "" + } + var topLine + if (materialsAreKnown(printer.activePrintJob)) + { + topLine = catalog.i18ncp("@label", "The assigned printer, %1, requires the following configuration change:", "The assigned printer, %1, requires the following configuration changes:", printer.activePrintJob.configurationChanges.length).arg(printer.name) + } + else + { + topLine = catalog.i18nc("@label", "The printer %1 is assigned, but the job contains an unknown material configuration.").arg(printer.name) + } + var result = "

" + topLine +"

\n\n" + for (var i = 0; i < printer.activePrintJob.configurationChanges.length; i++) + { + var change = printer.activePrintJob.configurationChanges[i] + var text + switch (change.typeOfChange) + { + case "material_change": + text = catalog.i18nc("@label", "Change material %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName) + break + case "material_insert": + text = catalog.i18nc("@label", "Load %3 as material %1 (This cannot be overridden).").arg(change.index + 1).arg(change.targetName) + break + case "print_core_change": + text = catalog.i18nc("@label", "Change print core %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName) + break + case "buildplate_change": + text = catalog.i18nc("@label", "Change build plate to %1 (This cannot be overridden).").arg(formatBuildPlateType(change.target_name)) + break + default: + text = "unknown" + } + result += "

" + text + "

\n\n" + } + var bottomLine = catalog.i18nc("@label", "Override will use the specified settings with the existing printer configuration. This may result in a failed print.") + result += "

" + bottomLine + "

\n\n" + return result + } + } + // Utils + function formatPrintJobName(name) + { + var extensions = [ ".gcode.gz", ".gz", ".gcode", ".ufp" ] + for (var i = 0; i < extensions.length; i++) + { + var extension = extensions[i] + if (name.slice(-extension.length) === extension) + { + name = name.substring(0, name.length - extension.length) + } + } + return name; + } + function materialsAreKnown(job) + { + var conf0 = job.configuration[0] + if (conf0 && !conf0.material.material) + { + return false + } + var conf1 = job.configuration[1] + if (conf1 && !conf1.material.material) + { + return false + } + return true + } + function formatBuildPlateType(buildPlateType) + { + var translationText = "" + switch (buildPlateType) { + case "glass": + translationText = catalog.i18nc("@label", "Glass") + break + case "aluminum": + translationText = catalog.i18nc("@label", "Aluminum") + break + default: + translationText = null + } + return translationText + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorExtruderConfiguration.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorExtruderConfiguration.qml new file mode 100644 index 0000000000..17c0fa8651 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorExtruderConfiguration.qml @@ -0,0 +1,100 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +/** + * This component comprises a colored extruder icon, the material name, and the + * print core name. It is used by the MonitorPrinterConfiguration component with + * a sibling instance as well as a MonitorBuildplateConfiguration instance. + * + * NOTE: For most labels, a fixed height with vertical alignment is used to make + * layouts more deterministic (like the fixed-size textboxes used in original + * mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted + * with '// FIXED-LINE-HEIGHT:'. + */ +Item +{ + // The material color + property alias color: extruderIcon.color + + // The extruder position; NOTE: Decent human beings count from 0 + property alias position: extruderIcon.position + + // The material name + property alias material: materialLabel.text + + // The print core name (referred to as hotendID in Python) + property alias printCore: printCoreLabel.text + + // Height is 2 x 18px labels, plus 4px spacing between them + height: 40 * screenScaleFactor // TODO: Theme! + width: childrenRect.width + + MonitorIconExtruder + { + id: extruderIcon + color: "#eeeeee" // TODO: Theme! + position: 0 + } + + Rectangle + { + id: materialLabelWrapper + anchors + { + left: extruderIcon.right + leftMargin: 12 * screenScaleFactor // TODO: Theme! + } + color: materialLabel.visible > 0 ? "transparent" : "#eeeeee" // TODO: Theme! + height: 18 * screenScaleFactor // TODO: Theme! + width: Math.max(materialLabel.contentWidth, 60 * screenScaleFactor) // TODO: Theme! + radius: 2 * screenScaleFactor // TODO: Theme! + + Label + { + id: materialLabel + + color: "#191919" // TODO: Theme! + elide: Text.ElideRight + font: UM.Theme.getFont("default") // 12pt, regular + text: "" + visible: text !== "" + + // FIXED-LINE-HEIGHT: + height: parent.height + verticalAlignment: Text.AlignVCenter + } + } + + Rectangle + { + id: printCoreLabelWrapper + anchors + { + left: materialLabelWrapper.left + bottom: parent.bottom + } + color: printCoreLabel.visible > 0 ? "transparent" : "#eeeeee" // TODO: Theme! + height: 18 * screenScaleFactor // TODO: Theme! + width: Math.max(printCoreLabel.contentWidth, 36 * screenScaleFactor) // TODO: Theme! + radius: 2 * screenScaleFactor // TODO: Theme! + + Label + { + id: printCoreLabel + + color: "#191919" // TODO: Theme! + elide: Text.ElideRight + font: UM.Theme.getFont("default_bold") // 12pt, bold + text: "" + visible: text !== "" + + // FIXED-LINE-HEIGHT: + height: parent.height + verticalAlignment: Text.AlignVCenter + } + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorIconExtruder.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorIconExtruder.qml new file mode 100644 index 0000000000..93dbebc8c6 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorIconExtruder.qml @@ -0,0 +1,61 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +/** + * This component is a sort of "super icon" which includes a colored SVG image + * as well as the extruder position number. It is used in the the + * MonitorExtruderConfiguration component. + */ +Item +{ + // The material color + property alias color: icon.color + + // The extruder position; NOTE: Decent human beings count from 0 + property int position: 0 + + // The extruder icon size; NOTE: This shouldn't need to be changed + property int size: 32 // TODO: Theme! + + // THe extruder icon source; NOTE: This shouldn't need to be changed + property string iconSource: "../svg/icons/extruder.svg" + + height: size + width: size + + UM.RecolorImage + { + id: icon + anchors.fill: parent + source: iconSource + width: size + } + + /* + * The label uses some "fancy" math to ensure that if you change the overall + * icon size, the number scales with it. That is to say, the font properties + * are linked to the icon size, NOT the theme. And that's intentional. + */ + Label + { + id: positionLabel + font + { + pointSize: Math.round(size * 0.3125) + weight: Font.Bold + } + height: Math.round(size / 2) * screenScaleFactor + horizontalAlignment: Text.AlignHCenter + text: position + 1 + verticalAlignment: Text.AlignVCenter + width: Math.round(size / 2) * screenScaleFactor + x: Math.round(size * 0.25) * screenScaleFactor + y: Math.round(size * 0.15625) * screenScaleFactor + // TODO: Once 'size' is themed, screenScaleFactor won't be needed + visible: position >= 0 + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml new file mode 100644 index 0000000000..f2b9c3cff7 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobCard.qml @@ -0,0 +1,215 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +/** + * A Print Job Card is essentially just a filled-in Expandable Card item. All + * data within it is derived from being passed a printJob property. + * + * NOTE: For most labels, a fixed height with vertical alignment is used to make + * layouts more deterministic (like the fixed-size textboxes used in original + * mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted + * with '// FIXED-LINE-HEIGHT:'. + */ +Item +{ + id: base + + // The print job which all other data is derived from + property var printJob: null + + width: parent.width + height: childrenRect.height + + ExpandableCard + { + enabled: printJob != null + borderColor: printJob.configurationChanges.length !== 0 ? "#f5a623" : "#CCCCCC" // TODO: Theme! + headerItem: Row + { + height: 48 * screenScaleFactor // TODO: Theme! + anchors.left: parent.left + anchors.leftMargin: 24 * screenScaleFactor // TODO: Theme! + spacing: 18 * screenScaleFactor // TODO: Theme! + + MonitorPrintJobPreview + { + printJob: base.printJob + size: 32 * screenScaleFactor // TODO: Theme! + anchors.verticalCenter: parent.verticalCenter + } + + Item + { + anchors.verticalCenter: parent.verticalCenter + height: 18 * screenScaleFactor // TODO: Theme! + width: 216 * screenScaleFactor // TODO: Theme! (Should match column size) + Rectangle + { + color: "#eeeeee" + width: Math.round(parent.width / 2) + height: parent.height + visible: !printJob + } + Label + { + text: printJob && printJob.name ? printJob.name : "" + color: "#374355" + elide: Text.ElideRight + font: UM.Theme.getFont("medium") // 14pt, regular + visible: printJob + + // FIXED-LINE-HEIGHT: + height: parent.height + verticalAlignment: Text.AlignVCenter + } + } + + Item + { + anchors.verticalCenter: parent.verticalCenter + height: 18 * screenScaleFactor // TODO: Theme! + width: 216 * screenScaleFactor // TODO: Theme! (Should match column size) + Rectangle + { + color: "#eeeeee" + width: Math.round(parent.width / 3) + height: parent.height + visible: !printJob + } + Label + { + text: printJob ? OutputDevice.formatDuration(printJob.timeTotal) : "" + color: "#374355" + elide: Text.ElideRight + font: UM.Theme.getFont("medium") // 14pt, regular + visible: printJob + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + } + + Item + { + anchors.verticalCenter: parent.verticalCenter + height: 18 * screenScaleFactor // TODO: This should be childrenRect.height but QML throws warnings + width: childrenRect.width + + Rectangle + { + color: "#eeeeee" + width: 72 * screenScaleFactor // TODO: Theme! + height: parent.height + visible: !printJob + } + + Label + { + id: printerAssignmentLabel + anchors.verticalCenter: parent.verticalCenter + color: "#374355" + elide: Text.ElideRight + font: UM.Theme.getFont("medium") // 14pt, regular + text: { + if (printJob !== null) { + if (printJob.assignedPrinter == null) + { + if (printJob.state == "error") + { + return catalog.i18nc("@label", "Unavailable printer") + } + return catalog.i18nc("@label", "First available") + } + return printJob.assignedPrinter.name + } + return "" + } + visible: printJob + width: 120 * screenScaleFactor // TODO: Theme! + + // FIXED-LINE-HEIGHT: + height: parent.height + verticalAlignment: Text.AlignVCenter + } + + Row + { + id: printerFamilyPills + anchors + { + left: printerAssignmentLabel.right; + leftMargin: 12 // TODO: Theme! + verticalCenter: parent.verticalCenter + } + height: childrenRect.height + spacing: 6 // TODO: Theme! + visible: printJob + + Repeater + { + id: compatiblePills + delegate: MonitorPrinterPill + { + text: modelData + } + model: printJob ? printJob.compatibleMachineFamilies : [] + } + } + } + } + drawerItem: Row + { + anchors + { + left: parent.left + leftMargin: 74 * screenScaleFactor // TODO: Theme! + } + height: 108 * screenScaleFactor // TODO: Theme! + spacing: 18 * screenScaleFactor // TODO: Theme! + + MonitorPrinterConfiguration + { + id: printerConfiguration + anchors.verticalCenter: parent.verticalCenter + buildplate: "Glass" + configurations: + [ + base.printJob.configuration.extruderConfigurations[0], + base.printJob.configuration.extruderConfigurations[1] + ] + height: 72 * screenScaleFactor // TODO: Theme! + } + Label { + text: printJob && printJob.owner ? printJob.owner : "" + color: "#374355" // TODO: Theme! + elide: Text.ElideRight + font: UM.Theme.getFont("medium") // 14pt, regular + anchors.top: printerConfiguration.top + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + } + } + + PrintJobContextMenu + { + id: contextButton + anchors + { + right: parent.right; + rightMargin: 8 * screenScaleFactor // TODO: Theme! + top: parent.top + topMargin: 8 * screenScaleFactor // TODO: Theme! + } + printJob: base.printJob + width: 32 * screenScaleFactor // TODO: Theme! + height: 32 * screenScaleFactor // TODO: Theme! + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobPreview.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobPreview.qml new file mode 100644 index 0000000000..d0bad63258 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobPreview.qml @@ -0,0 +1,101 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +// TODO: Documentation! +Item +{ + id: printJobPreview + + property var printJob: null + property var size: 256 + + width: size + height: size + + Rectangle + { + anchors.fill: parent + color: printJob ? "transparent" : "#eeeeee" // TODO: Theme! + radius: 8 // TODO: Theme! + Image + { + id: previewImage + anchors.fill: parent + opacity: + { + if (printJob && (printJob.state == "error" || printJob.configurationChanges.length > 0 || !printJob.isActive)) + { + return 0.5 + } + return 1.0 + } + source: printJob ? printJob.previewImageUrl : "" + } + } + + + UM.RecolorImage + { + id: ultiBotImage + + anchors.centerIn: printJobPreview + color: UM.Theme.getColor("monitor_placeholder_image") + height: printJobPreview.height + source: "../svg/ultibot.svg" + sourceSize + { + height: height + width: width + } + /* Since print jobs ALWAYS have an image url, we have to check if that image URL errors or + not in order to determine if we show the placeholder (ultibot) image instead. */ + visible: printJob && previewImage.status == Image.Error + width: printJobPreview.width + } + + UM.RecolorImage + { + id: overlayIcon + anchors.centerIn: printJobPreview + color: UM.Theme.getColor("monitor_image_overlay") + height: 0.5 * printJobPreview.height + source: + { + if (!printJob) + { + return "" + } + if (printJob.configurationChanges.length > 0) + { + return "../svg/warning-icon.svg" + } + switch(printJob.state) + { + case "error": + return "../svg/aborted-icon.svg" + case "wait_cleanup": + return printJob.timeTotal > printJob.timeElapsed ? "../svg/aborted-icon.svg" : "" + case "pausing": + return "../svg/paused-icon.svg" + case "paused": + return "../svg/paused-icon.svg" + case "resuming": + return "../svg/paused-icon.svg" + default: + return "" + } + return "" + } + sourceSize + { + height: height + width: width + } + visible: source != "" + width: 0.5 * printJobPreview.width + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobProgressBar.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobProgressBar.qml new file mode 100644 index 0000000000..d5d4705a36 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrintJobProgressBar.qml @@ -0,0 +1,119 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Controls 1.4 +import UM 1.3 as UM + +/** + * NOTE: For most labels, a fixed height with vertical alignment is used to make + * layouts more deterministic (like the fixed-size textboxes used in original + * mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted + * with '// FIXED-LINE-HEIGHT:'. + */ +Item +{ + id: base + + // The print job which all other information is dervied from + property var printJob: null + + width: childrenRect.width + height: 18 * screenScaleFactor // TODO: Theme! + + ProgressBar + { + id: progressBar + anchors + { + verticalCenter: parent.verticalCenter + } + value: printJob ? printJob.progress : 0 + style: ProgressBarStyle + { + background: Rectangle + { + color: "#f5f5f5" // TODO: Theme! + implicitHeight: visible ? 8 * screenScaleFactor : 0 // TODO: Theme! + implicitWidth: 180 * screenScaleFactor // TODO: Theme! + radius: 2 * screenScaleFactor // TODO: Theme! + } + progress: Rectangle + { + id: progressItem; + color: printJob && printJob.isActive ? "#3282ff" : "#CCCCCC" // TODO: Theme! + radius: 2 * screenScaleFactor // TODO: Theme! + } + } + } + Label + { + id: percentLabel + anchors + { + left: progressBar.right + leftMargin: 18 * screenScaleFactor // TODO: Theme! + } + text: printJob ? Math.round(printJob.progress * 100) + "%" : "0%" + color: printJob && printJob.isActive ? "#374355" : "#babac1" // TODO: Theme! + width: contentWidth + font: UM.Theme.getFont("medium") // 14pt, regular + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + Label + { + id: statusLabel + anchors + { + left: percentLabel.right + leftMargin: 18 * screenScaleFactor // TODO: Theme! + } + color: "#374355" // TODO: Theme! + font: UM.Theme.getFont("medium") // 14pt, regular + text: + { + if (!printJob) + { + return "" + } + switch (printJob.state) + { + case "wait_cleanup": + if (printJob.timeTotal > printJob.timeElapsed) + { + return catalog.i18nc("@label:status", "Aborted") + } + return catalog.i18nc("@label:status", "Finished") + case "finished": + return catalog.i18nc("@label:status", "Finished") + case "sent_to_printer": + return catalog.i18nc("@label:status", "Preparing...") + case "pre_print": + return catalog.i18nc("@label:status", "Preparing...") + case "aborting": // NOTE: Doesn't exist but maybe should someday + return catalog.i18nc("@label:status", "Aborting...") + case "aborted": // NOTE: Unused, see above + return catalog.i18nc("@label:status", "Aborted") + case "pausing": + return catalog.i18nc("@label:status", "Pausing...") + case "paused": + return catalog.i18nc("@label:status", "Paused") + case "resuming": + return catalog.i18nc("@label:status", "Resuming...") + case "queued": + return catalog.i18nc("@label:status", "Action required") + default: + return catalog.i18nc("@label:status", "Finishes %1 at %2".arg(OutputDevice.getDateCompleted( printJob.timeRemaining )).arg(OutputDevice.getTimeCompleted( printJob.timeRemaining ))) + } + } + width: contentWidth + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml new file mode 100644 index 0000000000..facfaaaaaf --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml @@ -0,0 +1,404 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.3 +import QtQuick.Controls 2.0 +import QtQuick.Dialogs 1.1 +import UM 1.3 as UM + +/** + * A Printer Card is has two main components: the printer portion and the print + * job portion, the latter being paired in the UI when a print job is paired + * a printer in-cluster. + * + * NOTE: For most labels, a fixed height with vertical alignment is used to make + * layouts more deterministic (like the fixed-size textboxes used in original + * mock-ups). This is also a stand-in for CSS's 'line-height' property. Denoted + * with '// FIXED-LINE-HEIGHT:'. + */ +Item +{ + id: base + + // The printer which all printer data is derived from + property var printer: null + + property var borderSize: 1 * screenScaleFactor // TODO: Theme, and remove from here + + // If the printer card's controls are enabled. This is used by the carousel + // to prevent opening the context menu or camera while the printer card is not + // "in focus" + property var enabled: true + + width: 834 * screenScaleFactor // TODO: Theme! + height: childrenRect.height + + Rectangle + { + id: background + anchors.fill: parent + color: "#FFFFFF" // TODO: Theme! + border + { + color: "#CCCCCC" // TODO: Theme! + width: borderSize // TODO: Remove once themed + } + radius: 2 * screenScaleFactor // TODO: Theme! + } + + // Printer portion + Item + { + id: printerInfo + + width: parent.width + height: 144 * screenScaleFactor // TODO: Theme! + + Row + { + anchors + { + left: parent.left + leftMargin: 36 * screenScaleFactor // TODO: Theme! + verticalCenter: parent.verticalCenter + } + spacing: 18 * screenScaleFactor // TODO: Theme! + + Rectangle + { + id: printerImage + width: 108 * screenScaleFactor // TODO: Theme! + height: 108 * screenScaleFactor // TODO: Theme! + color: printer ? "transparent" : "#eeeeee" // TODO: Theme! + radius: 8 // TODO: Theme! + Image + { + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: printer ? "../png/" + printer.type + ".png" : "" + mipmap: true + } + } + + + Item + { + anchors + { + verticalCenter: parent.verticalCenter + } + width: 180 * screenScaleFactor // TODO: Theme! + height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme! + + Rectangle + { + id: printerNameLabel + // color: "#414054" // TODO: Theme! + color: printer ? "transparent" : "#eeeeee" // TODO: Theme! + height: 18 * screenScaleFactor // TODO: Theme! + width: parent.width + radius: 2 * screenScaleFactor // TODO: Theme! + + Label + { + text: printer && printer.name ? printer.name : "" + color: "#414054" // TODO: Theme! + elide: Text.ElideRight + font: UM.Theme.getFont("large") // 16pt, bold + width: parent.width + visible: printer + + // FIXED-LINE-HEIGHT: + height: parent.height + verticalAlignment: Text.AlignVCenter + } + } + + Rectangle + { + color: "#eeeeee" // TODO: Theme! + height: 18 * screenScaleFactor // TODO: Theme! + radius: 2 * screenScaleFactor // TODO: Theme! + visible: !printer + width: 48 * screenScaleFactor // TODO: Theme! + } + MonitorPrinterPill + { + id: printerFamilyPill + anchors + { + top: printerNameLabel.bottom + topMargin: 6 * screenScaleFactor // TODO: Theme! + left: printerNameLabel.left + } + text: printer ? printer.type : "" + } + } + + MonitorPrinterConfiguration + { + id: printerConfiguration + anchors.verticalCenter: parent.verticalCenter + buildplate: printer ? "Glass" : null // 'Glass' as a default + configurations: + { + var configs = [] + if (printer) + { + configs.push(printer.printerConfiguration.extruderConfigurations[0]) + configs.push(printer.printerConfiguration.extruderConfigurations[1]) + } + else + { + configs.push(null, null) + } + return configs + } + height: 72 * screenScaleFactor // TODO: Theme!te theRect's x property + } + + // TODO: Make this work. + PropertyAnimation { target: printerConfiguration; property: "visible"; to: 0; loops: Animation.Infinite; duration: 500 } + } + + + + PrintJobContextMenu + { + id: contextButton + anchors + { + right: parent.right + rightMargin: 12 * screenScaleFactor // TODO: Theme! + top: parent.top + topMargin: 12 * screenScaleFactor // TODO: Theme! + } + printJob: printer ? printer.activePrintJob : null + width: 36 * screenScaleFactor // TODO: Theme! + height: 36 * screenScaleFactor // TODO: Theme! + enabled: base.enabled + visible: printer + } + CameraButton + { + id: cameraButton; + anchors + { + right: parent.right + rightMargin: 20 * screenScaleFactor // TODO: Theme! + bottom: parent.bottom + bottomMargin: 20 * screenScaleFactor // TODO: Theme! + } + iconSource: "../svg/icons/camera.svg" + enabled: base.enabled + visible: printer + } + } + + + // Divider + Rectangle + { + anchors + { + top: printJobInfo.top + left: printJobInfo.left + right: printJobInfo.right + } + height: borderSize // Remove once themed + color: background.border.color + } + + // Print job portion + Rectangle + { + id: printJobInfo + anchors + { + top: printerInfo.bottom + topMargin: -borderSize * screenScaleFactor // TODO: Theme! + } + border + { + color: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 ? "#f5a623" : "transparent" // TODO: Theme! + width: borderSize // TODO: Remove once themed + } + color: "transparent" // TODO: Theme! + height: 84 * screenScaleFactor + borderSize // TODO: Remove once themed + width: parent.width + + Row + { + anchors + { + fill: parent + topMargin: 12 * screenScaleFactor + borderSize // TODO: Theme! + bottomMargin: 12 * screenScaleFactor // TODO: Theme! + leftMargin: 36 * screenScaleFactor // TODO: Theme! + } + height: childrenRect.height + spacing: 18 * screenScaleFactor // TODO: Theme! + + Label + { + id: printerStatus + anchors + { + verticalCenter: parent.verticalCenter + } + color: printer ? "#414054" : "#aaaaaa" // TODO: Theme! + font: UM.Theme.getFont("large_bold") // 16pt, bold + text: { + if (!printer) { + return catalog.i18nc("@label:status", "Loading...") + } + if (printer && printer.state == "disabled") + { + return catalog.i18nc("@label:status", "Unavailable") + } + if (printer && printer.state == "unreachable") + { + return catalog.i18nc("@label:status", "Unavailable") + } + if (printer && !printer.activePrintJob && printer.state == "idle") + { + return catalog.i18nc("@label:status", "Idle") + } + return "" + } + visible: text !== "" + } + + Item + { + anchors + { + verticalCenter: parent.verticalCenter + } + width: printerImage.width + height: 60 * screenScaleFactor // TODO: Theme! + MonitorPrintJobPreview + { + anchors.centerIn: parent + printJob: printer ? printer.activePrintJob : null + size: parent.height + } + visible: printer && printer.activePrintJob && !printerStatus.visible + } + + Item + { + anchors + { + verticalCenter: parent.verticalCenter + } + width: 180 * screenScaleFactor // TODO: Theme! + height: printerNameLabel.height + printerFamilyPill.height + 6 * screenScaleFactor // TODO: Theme! + visible: printer && printer.activePrintJob && !printerStatus.visible + + Label + { + id: printerJobNameLabel + color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? "#414054" : "#babac1" // TODO: Theme! + elide: Text.ElideRight + font: UM.Theme.getFont("large") // 16pt, bold + text: printer && printer.activePrintJob ? printer.activePrintJob.name : "Untitled" // TODO: I18N + width: parent.width + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + + Label + { + id: printerJobOwnerLabel + anchors + { + top: printerJobNameLabel.bottom + topMargin: 6 * screenScaleFactor // TODO: Theme! + left: printerJobNameLabel.left + } + color: printer && printer.activePrintJob && printer.activePrintJob.isActive ? "#53657d" : "#babac1" // TODO: Theme! + elide: Text.ElideRight + font: UM.Theme.getFont("default") // 12pt, regular + text: printer && printer.activePrintJob ? printer.activePrintJob.owner : "Anonymous" // TODO: I18N + width: parent.width + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + } + + MonitorPrintJobProgressBar + { + anchors + { + verticalCenter: parent.verticalCenter + } + printJob: printer && printer.activePrintJob + visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length === 0 && !printerStatus.visible + } + + Label + { + anchors + { + verticalCenter: parent.verticalCenter + } + font: UM.Theme.getFont("default") + text: "Requires configuration changes" + visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + } + + Button + { + id: detailsButton + anchors + { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: 18 * screenScaleFactor // TODO: Theme! + } + background: Rectangle + { + color: "#d8d8d8" // TODO: Theme! + radius: 2 * screenScaleFactor // Todo: Theme! + Rectangle + { + anchors.fill: parent + anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme! + color: detailsButton.hovered ? "#e4e4e4" : "#f0f0f0" // TODO: Theme! + radius: 2 * screenScaleFactor // Todo: Theme! + } + } + contentItem: Label + { + anchors.fill: parent + anchors.bottomMargin: 2 * screenScaleFactor // TODO: Theme! + color: "#1e66d7" // TODO: Theme! + font: UM.Theme.getFont("medium") // 14pt, regular + text: "Details" // TODO: I18NC! + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + height: 18 * screenScaleFactor // TODO: Theme! + } + implicitHeight: 32 * screenScaleFactor // TODO: Theme! + implicitWidth: 96 * screenScaleFactor // TODO: Theme! + visible: printer && printer.activePrintJob && printer.activePrintJob.configurationChanges.length > 0 && !printerStatus.visible + onClicked: base.enabled ? overrideConfirmationDialog.open() : {} + } + } + + MonitorConfigOverrideDialog + { + id: overrideConfirmationDialog + printer: base.printer + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterConfiguration.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterConfiguration.qml new file mode 100644 index 0000000000..debc8b7959 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterConfiguration.qml @@ -0,0 +1,58 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +/** + * The MonitorPrinterConfiguration accepts 2 configuration objects as input and + * applies them to a MonitorBuildplateConfiguration instance and two instances + * of MonitorExtruderConfiguration. It's used in both the MonitorPrintJobCard + * component as well as the MonitorPrinterCard component. + */ +Item +{ + id: base + + // Extracted buildplate configuration + property alias buildplate: buildplateConfig.buildplate + + // Array of extracted extruder configurations + property var configurations: [null,null] + + // Default size, but should be stretched to fill parent + height: 72 * parent.height + width: 450 * screenScaleFactor // TODO: Theme! + + Row + { + id: extruderConfigurationRow + spacing: 18 * screenScaleFactor // TODO: Theme! + + Repeater + { + id: extruderConfigurationRepeater + model: configurations + + MonitorExtruderConfiguration + { + color: modelData && modelData.activeMaterial ? modelData.activeMaterial.color : "#eeeeee" // TODO: Theme! + material: modelData && modelData.activeMaterial ? modelData.activeMaterial.name : "" + position: modelData && typeof(modelData.position) === "number" ? modelData.position : -1 // Use negative one to create empty extruder number + printCore: modelData ? modelData.hotendID : "" + + // Keep things responsive! + width: Math.floor((base.width - (configurations.length - 1) * extruderConfigurationRow.spacing) / configurations.length) + } + + } + } + + MonitorBuildplateConfiguration + { + id: buildplateConfig + anchors.bottom: parent.bottom + buildplate: null + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterPill.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterPill.qml new file mode 100644 index 0000000000..2408089e1e --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterPill.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.4 +import UM 1.2 as UM + +/** + * A MonitorPrinterPill is a blue-colored tag indicating which printers a print + * job is compatible with. It is used by the MonitorPrintJobCard component. + */ +Item +{ + // The printer name + property var text: "" + property var tagText: { + switch(text) { + case "Ultimaker 3": + return "UM 3" + case "Ultimaker 3 Extended": + return "UM 3 EXT" + case "Ultimaker S5": + return "UM S5" + default: + return text + } + } + + implicitHeight: 18 * screenScaleFactor // TODO: Theme! + implicitWidth: Math.max(printerNameLabel.contentWidth + 12 * screenScaleFactor, 36 * screenScaleFactor) // TODO: Theme! + + Rectangle { + id: background + anchors.fill: parent + color: printerNameLabel.visible ? "#e4e4f2" : "#eeeeee"// TODO: Theme! + radius: 2 * screenScaleFactor // TODO: Theme! + } + + Label { + id: printerNameLabel + anchors.centerIn: parent + color: "#535369" // TODO: Theme! + text: tagText + font.pointSize: 10 // TODO: Theme! + visible: text !== "" + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml new file mode 100644 index 0000000000..f2dc09de95 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml @@ -0,0 +1,167 @@ +// 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.4 +import QtQuick.Controls.Styles 1.4 +import UM 1.3 as UM +import Cura 1.0 as Cura + +/** + * This component contains the print job queue, extracted from the primary + * MonitorStage.qml file not for reusability but simply to keep it lean and more + * readable. + */ +Item +{ + Label + { + id: queuedLabel + anchors + { + left: queuedPrintJobs.left + top: parent.top + } + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("large") + text: catalog.i18nc("@label", "Queued") + } + + Item + { + id: manageQueueLabel + anchors + { + right: queuedPrintJobs.right + verticalCenter: queuedLabel.verticalCenter + } + height: 18 * screenScaleFactor // TODO: Theme! + width: childrenRect.width + + UM.RecolorImage + { + id: externalLinkIcon + anchors.verticalCenter: manageQueueLabel.verticalCenter + color: UM.Theme.getColor("text_link") + source: UM.Theme.getIcon("external_link") + width: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!) + height: 16 * screenScaleFactor // TODO: Theme! (Y U NO USE 18 LIKE ALL OTHER ICONS?!) + } + Label + { + id: manageQueueText + anchors + { + left: externalLinkIcon.right + leftMargin: 6 * screenScaleFactor // TODO: Theme! + verticalCenter: externalLinkIcon.verticalCenter + } + color: UM.Theme.getColor("text_link") + font: UM.Theme.getFont("default") // 12pt, regular + linkColor: UM.Theme.getColor("text_link") + text: catalog.i18nc("@label link to connect manager", "Manage queue in Cura Connect") + renderType: Text.NativeRendering + } + } + + MouseArea + { + anchors.fill: manageQueueLabel + hoverEnabled: true + onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel() + onEntered: + { + manageQueueText.font.underline = true + } + onExited: + { + manageQueueText.font.underline = false + } + } + + Row + { + id: printJobQueueHeadings + anchors + { + left: queuedPrintJobs.left + leftMargin: 6 * screenScaleFactor // TODO: Theme! + top: queuedLabel.bottom + topMargin: 24 * screenScaleFactor // TODO: Theme! + } + spacing: 18 * screenScaleFactor // TODO: Theme! + + Label + { + text: catalog.i18nc("@label", "Print jobs") + color: "#666666" + elide: Text.ElideRight + font: UM.Theme.getFont("medium") // 14pt, regular + anchors.verticalCenter: parent.verticalCenter + width: 284 * screenScaleFactor // TODO: Theme! (Should match column size) + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + + Label + { + text: catalog.i18nc("@label", "Total print time") + color: "#666666" + elide: Text.ElideRight + font: UM.Theme.getFont("medium") // 14pt, regular + anchors.verticalCenter: parent.verticalCenter + width: 216 * screenScaleFactor // TODO: Theme! (Should match column size) + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + + Label + { + text: catalog.i18nc("@label", "Waiting for") + color: "#666666" + elide: Text.ElideRight + font: UM.Theme.getFont("medium") // 14pt, regular + anchors.verticalCenter: parent.verticalCenter + width: 216 * screenScaleFactor // TODO: Theme! (Should match column size) + + // FIXED-LINE-HEIGHT: + height: 18 * screenScaleFactor // TODO: Theme! + verticalAlignment: Text.AlignVCenter + } + } + + ScrollView + { + id: queuedPrintJobs + anchors + { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + top: printJobQueueHeadings.bottom + topMargin: 12 * screenScaleFactor // TODO: Theme! + } + style: UM.Theme.styles.scrollview + width: parent.width + + ListView + { + id: printJobList + anchors.fill: parent + delegate: MonitorPrintJobCard + { + anchors + { + left: parent.left + right: parent.right + } + printJob: modelData + } + model: OutputDevice.receivedPrintJobs ? OutputDevice.queuedPrintJobs : [null,null] + spacing: 6 // TODO: Theme! + } + } +} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorStage.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorStage.qml new file mode 100644 index 0000000000..8723e6f46e --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorStage.qml @@ -0,0 +1,94 @@ +// 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.4 +import QtQuick.Controls.Styles 1.4 +import UM 1.3 as UM +import Cura 1.0 as Cura +import QtGraphicalEffects 1.0 + +// This is the root component for the monitor stage. +Component +{ + Item + { + id: monitorFrame + + height: maximumHeight + onVisibleChanged: + { + if (monitorFrame != null && !monitorFrame.visible) + { + OutputDevice.setActiveCameraUrl("") + } + } + width: maximumWidth + + // Enable keyboard navigation. NOTE: This is done here so that we can also potentially + // forward to the queue items in the future. (Deleting selected print job, etc.) + Keys.forwardTo: carousel + Component.onCompleted: forceActiveFocus() + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + LinearGradient + { + anchors.fill: parent + gradient: Gradient + { + GradientStop + { + position: 0.0 + color: "#f6f6f6" // TODO: Theme! + } + GradientStop + { + position: 1.0 + color: "#ffffff" // TODO: Theme! + } + } + } + + Item + { + id: printers + anchors + { + top: parent.top + topMargin: 48 * screenScaleFactor // TODO: Theme! + } + width: parent.width + height: 264 * screenScaleFactor // TODO: Theme! + MonitorCarousel + { + id: carousel + printers: OutputDevice.receivedPrintJobs ? OutputDevice.printers : [null] + } + } + + MonitorQueue + { + id: queue + width: Math.min(834 * screenScaleFactor, maximumWidth) + anchors + { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + top: printers.bottom + topMargin: 48 * screenScaleFactor // TODO: Theme! + } + } + + PrinterVideoStream + { + anchors.fill: parent + cameraUrl: OutputDevice.activeCameraUrl + visible: OutputDevice.activeCameraUrl != "" + } + } +} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintCoreConfiguration.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintCoreConfiguration.qml deleted file mode 100644 index 7bcd9ce6e4..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrintCoreConfiguration.qml +++ /dev/null @@ -1,121 +0,0 @@ -// 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.4 -import QtQuick.Controls.Styles 1.4 -import UM 1.2 as UM - -Item { - id: extruderInfo; - property var printCoreConfiguration: null; - height: childrenRect.height; - width: Math.round(parent.width / 2); - - // Extruder circle - Item { - id: extruderCircle; - height: UM.Theme.getSize("monitor_extruder_circle").height; - width: UM.Theme.getSize("monitor_extruder_circle").width; - - // Loading skeleton - Rectangle { - anchors.fill: parent; - color: UM.Theme.getColor("monitor_skeleton_fill"); - radius: Math.round(width / 2); - visible: !printCoreConfiguration; - } - - // Actual content - Rectangle { - anchors.fill: parent; - border.width: UM.Theme.getSize("monitor_thick_lining").width; - border.color: UM.Theme.getColor("monitor_lining_heavy"); - color: "transparent"; - opacity: { - if (printCoreConfiguration == null || printCoreConfiguration.activeMaterial == null || printCoreConfiguration.hotendID == null) { - return 0.5; - } - return 1; - } - radius: Math.round(width / 2); - visible: printCoreConfiguration; - - Label { - anchors.centerIn: parent; - color: UM.Theme.getColor("text"); - font: UM.Theme.getFont("default_bold"); - text: printCoreConfiguration ? printCoreConfiguration.position + 1 : 0; - } - } - } - - // Print core and material labels - Item { - id: materialLabel - anchors { - left: extruderCircle.right; - leftMargin: UM.Theme.getSize("default_margin").width; - right: parent.right; - top: parent.top; - } - height: UM.Theme.getSize("monitor_text_line").height; - - // Loading skeleton - Rectangle { - anchors.fill: parent; - color: UM.Theme.getColor("monitor_skeleton_fill"); - visible: !extruderInfo.printCoreConfiguration; - } - - // Actual content - Label { - anchors.fill: parent; - elide: Text.ElideRight; - color: UM.Theme.getColor("text"); - font: UM.Theme.getFont("default"); - text: { - if (printCoreConfiguration && printCoreConfiguration.activeMaterial != undefined) { - return printCoreConfiguration.activeMaterial.name; - } - return ""; - } - visible: extruderInfo.printCoreConfiguration; - } - } - - Item { - id: printCoreLabel; - anchors { - left: extruderCircle.right; - leftMargin: UM.Theme.getSize("default_margin").width; - right: parent.right; - top: materialLabel.bottom; - topMargin: Math.floor(UM.Theme.getSize("default_margin").height/4); - } - height: UM.Theme.getSize("monitor_text_line").height; - - // Loading skeleton - Rectangle { - color: UM.Theme.getColor("monitor_skeleton_fill"); - height: parent.height; - visible: !extruderInfo.printCoreConfiguration; - width: Math.round(parent.width / 3); - } - - // Actual content - Label { - color: UM.Theme.getColor("text"); - elide: Text.ElideRight; - font: UM.Theme.getFont("default"); - opacity: 0.6; - text: { - if (printCoreConfiguration != undefined && printCoreConfiguration.hotendID != undefined) { - return printCoreConfiguration.hotendID; - } - return ""; - } - visible: extruderInfo.printCoreConfiguration; - } - } -} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenu.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenu.qml index 11bc913d06..5c5c892dad 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenu.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/PrintJobContextMenu.qml @@ -13,6 +13,7 @@ Item { property var printJob: null; property var started: isStarted(printJob); property var assigned: isAssigned(printJob); + property var enabled: true Button { id: button; @@ -25,14 +26,14 @@ Item { } contentItem: Label { color: UM.Theme.getColor("monitor_context_menu_dots"); - font.pixelSize: 25 * screenScaleFactor; + font.pixelSize: 32 * screenScaleFactor; horizontalAlignment: Text.AlignHCenter; text: button.text; verticalAlignment: Text.AlignVCenter; } height: width; - hoverEnabled: true; - onClicked: parent.switchPopupState(); + hoverEnabled: base.enabled + onClicked: base.enabled ? parent.switchPopupState() : {} text: "\u22EE"; //Unicode; Three stacked points. visible: { if (!printJob) { @@ -41,7 +42,7 @@ Item { var states = ["queued", "sent_to_printer", "pre_print", "printing", "pausing", "paused", "resuming"]; return states.indexOf(printJob.state) !== -1; } - width: 35 * screenScaleFactor; // TODO: Theme! + width: 36 * screenScaleFactor; // TODO: Theme! } Popup { @@ -182,7 +183,7 @@ Item { abortConfirmationDialog.visible = true; popup.close(); } - text: printJob.state == "aborting" ? catalog.i18nc("@label", "Aborting...") : catalog.i18nc("@label", "Abort"); + text: printJob && printJob.state == "aborting" ? catalog.i18nc("@label", "Aborting...") : catalog.i18nc("@label", "Abort"); visible: { if (!printJob) { return false; diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml deleted file mode 100644 index a611cb4ff6..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.2 -import QtQuick.Dialogs 1.1 -import QtQuick.Controls 2.0 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 -import QtQuick.Layouts 1.1 -import QtQuick.Dialogs 1.1 -import UM 1.3 as UM - -Item { - id: root; - property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width; - property var shadowOffset: 2 * screenScaleFactor; - property var debug: false; - property var printJob: null; - width: parent.width; // Bubbles downward - height: childrenRect.height + shadowRadius * 2; // Bubbles upward - - UM.I18nCatalog { - id: catalog; - name: "cura"; - } - - // The actual card (white block) - Rectangle { - // 5px margin, but shifted 2px vertically because of the shadow - anchors { - bottomMargin: root.shadowRadius + root.shadowOffset; - leftMargin: root.shadowRadius; - rightMargin: root.shadowRadius; - topMargin: root.shadowRadius - root.shadowOffset; - } - color: UM.Theme.getColor("monitor_card_background"); - height: childrenRect.height; - layer.enabled: true - layer.effect: DropShadow { - radius: root.shadowRadius - verticalOffset: 2 * screenScaleFactor - color: "#3F000000" // 25% shadow - } - width: parent.width - shadowRadius * 2; - - Column { - height: childrenRect.height; - width: parent.width; - - // Main content - Item { - id: mainContent; - height: 200 * screenScaleFactor; // TODO: Theme! - width: parent.width; - - // Left content - Item { - anchors { - bottom: parent.bottom; - left: parent.left; - margins: UM.Theme.getSize("wide_margin").width; - right: parent.horizontalCenter; - top: parent.top; - } - - Item { - id: printJobName; - width: parent.width; - height: UM.Theme.getSize("monitor_text_line").height; - - Rectangle { - color: UM.Theme.getColor("monitor_skeleton_fill"); - height: parent.height; - visible: !printJob; - width: Math.round(parent.width / 3); - } - Label { - anchors.fill: parent; - color: UM.Theme.getColor("text"); - elide: Text.ElideRight; - font: UM.Theme.getFont("default_bold"); - text: printJob && printJob.name ? printJob.name : ""; // Supress QML warnings - visible: printJob; - } - } - - Item { - id: printJobOwnerName; - anchors { - top: printJobName.bottom; - topMargin: Math.floor(UM.Theme.getSize("default_margin").height / 2); - } - height: UM.Theme.getSize("monitor_text_line").height; - width: parent.width; - - Rectangle { - color: UM.Theme.getColor("monitor_skeleton_fill"); - height: parent.height; - visible: !printJob; - width: Math.round(parent.width / 2); - } - Label { - anchors.fill: parent; - color: UM.Theme.getColor("text"); - elide: Text.ElideRight; - font: UM.Theme.getFont("default"); - text: printJob ? printJob.owner : ""; // Supress QML warnings - visible: printJob; - } - } - - Item { - id: printJobPreview; - property var useUltibot: false; - anchors { - bottom: parent.bottom; - horizontalCenter: parent.horizontalCenter; - top: printJobOwnerName.bottom; - topMargin: UM.Theme.getSize("default_margin").height; - } - width: height; - - // Skeleton - Rectangle { - anchors.fill: parent; - color: UM.Theme.getColor("monitor_skeleton_fill"); - radius: UM.Theme.getSize("default_margin").width; - visible: !printJob; - } - - // Actual content - Image { - id: previewImage; - anchors.fill: parent; - opacity: printJob && printJob.state == "error" ? 0.5 : 1.0; - source: printJob ? printJob.previewImageUrl : ""; - visible: printJob; - } - - UM.RecolorImage { - id: ultiBotImage; - - anchors.centerIn: printJobPreview; - color: UM.Theme.getColor("monitor_placeholder_image"); - height: printJobPreview.height; - source: "../svg/ultibot.svg"; - sourceSize { - height: height; - width: width; - } - /* Since print jobs ALWAYS have an image url, we have to check if that image URL errors or - not in order to determine if we show the placeholder (ultibot) image instead. */ - visible: printJob && previewImage.status == Image.Error; - width: printJobPreview.width; - } - - UM.RecolorImage { - id: statusImage; - anchors.centerIn: printJobPreview; - color: UM.Theme.getColor("monitor_image_overlay"); - height: 0.5 * printJobPreview.height; - source: printJob && printJob.state == "error" ? "../svg/aborted-icon.svg" : ""; - sourceSize { - height: height; - width: width; - } - visible: source != ""; - width: 0.5 * printJobPreview.width; - } - } - - Label { - id: totalTimeLabel; - anchors { - bottom: parent.bottom; - right: parent.right; - } - color: UM.Theme.getColor("text"); - elide: Text.ElideRight; - font: UM.Theme.getFont("default"); - text: printJob ? OutputDevice.formatDuration(printJob.timeTotal) : ""; - } - } - - // Divider - Rectangle { - anchors { - horizontalCenter: parent.horizontalCenter; - verticalCenter: parent.verticalCenter; - } - color: !printJob ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_lining_light"); - height: parent.height - 2 * UM.Theme.getSize("default_margin").height; - width: UM.Theme.getSize("default_lining").width; - } - - // Right content - Item { - anchors { - bottom: parent.bottom; - left: parent.horizontalCenter; - margins: UM.Theme.getSize("wide_margin").width; - right: parent.right; - top: parent.top; - } - - Item { - id: targetPrinterLabel; - height: UM.Theme.getSize("monitor_text_line").height; - width: parent.width; - - Rectangle { - visible: !printJob; - color: UM.Theme.getColor("monitor_skeleton_fill"); - anchors.fill: parent; - } - - Label { - color: UM.Theme.getColor("text"); - elide: Text.ElideRight; - font: UM.Theme.getFont("default_bold"); - text: { - if (printJob !== null) { - if (printJob.assignedPrinter == null) { - if (printJob.state == "error") { - return catalog.i18nc("@label", "Waiting for: Unavailable printer"); - } - return catalog.i18nc("@label", "Waiting for: First available"); - } else { - return catalog.i18nc("@label", "Waiting for: ") + printJob.assignedPrinter.name; - } - } - return ""; - } - visible: printJob; - } - } - - PrinterInfoBlock { - anchors.bottom: parent.bottom; - printer: root.printJon && root.printJob.assignedPrinter; - printJob: root.printJob; - } - } - - PrintJobContextMenu { - id: contextButton; - anchors { - right: mainContent.right; - rightMargin: UM.Theme.getSize("default_margin").width * 3 + root.shadowRadius; - top: mainContent.top; - topMargin: UM.Theme.getSize("default_margin").height; - } - printJob: root.printJob; - visible: root.printJob; - } - } - - Item { - id: configChangesBox; - height: childrenRect.height; - visible: printJob && printJob.configurationChanges.length !== 0; - width: parent.width; - - // Config change toggle - Rectangle { - id: configChangeToggle; - color: { - if (configChangeToggleArea.containsMouse) { - return UM.Theme.getColor("viewport_background"); // TODO: Theme! - } else { - return "transparent"; - } - } - width: parent.width; - height: UM.Theme.getSize("default_margin").height * 4; // TODO: Theme! - anchors { - left: parent.left; - right: parent.right; - top: parent.top; - } - - Rectangle { - color: !printJob ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_lining_light"); - height: UM.Theme.getSize("default_lining").height; - width: parent.width; - } - - UM.RecolorImage { - anchors { - right: configChangeToggleLabel.left; - rightMargin: UM.Theme.getSize("default_margin").width; - verticalCenter: parent.verticalCenter; - } - color: UM.Theme.getColor("text"); - height: 23 * screenScaleFactor; // TODO: Theme! - source: "../svg/warning-icon.svg"; - sourceSize { - height: height; - width: width; - } - width: 23 * screenScaleFactor; // TODO: Theme! - } - - Label { - id: configChangeToggleLabel; - anchors { - horizontalCenter: parent.horizontalCenter; - verticalCenter: parent.verticalCenter; - } - color: UM.Theme.getColor("text"); - font: UM.Theme.getFont("default"); - text: catalog.i18nc("@label", "Configuration change"); - } - - UM.RecolorImage { - anchors { - left: configChangeToggleLabel.right; - leftMargin: UM.Theme.getSize("default_margin").width; - verticalCenter: parent.verticalCenter; - } - color: UM.Theme.getColor("text"); - height: 15 * screenScaleFactor; // TODO: Theme! - source: { - if (configChangeDetails.visible) { - return UM.Theme.getIcon("arrow_top"); - } else { - return UM.Theme.getIcon("arrow_bottom"); - } - } - sourceSize { - width: width; - height: height; - } - width: 15 * screenScaleFactor; // TODO: Theme! - } - - MouseArea { - id: configChangeToggleArea; - anchors.fill: parent; - hoverEnabled: true; - onClicked: { - configChangeDetails.visible = !configChangeDetails.visible; - } - } - } - - // Config change details - Item { - id: configChangeDetails; - anchors.top: configChangeToggle.bottom; - Behavior on height { NumberAnimation { duration: 100 } } - // In case of really massive multi-line configuration changes - height: visible ? Math.max(UM.Theme.getSize("monitor_config_override_box").height, childrenRect.height) : 0; - visible: false; - width: parent.width; - - Item { - anchors { - bottomMargin: UM.Theme.getSize("wide_margin").height; - fill: parent; - leftMargin: UM.Theme.getSize("wide_margin").height * 4; - rightMargin: UM.Theme.getSize("wide_margin").height * 4; - topMargin: UM.Theme.getSize("wide_margin").height; - } - clip: true; - - Label { - anchors.fill: parent; - elide: Text.ElideRight; - color: UM.Theme.getColor("text"); - font: UM.Theme.getFont("default"); - text: { - if (!printJob || printJob.configurationChanges.length === 0) { - return ""; - } - var topLine; - if (materialsAreKnown(printJob)) { - topLine = catalog.i18nc("@label", "The assigned printer, %1, requires the following configuration change(s):").arg(printJob.assignedPrinter.name); - } else { - topLine = catalog.i18nc("@label", "The printer %1 is assigned, but the job contains an unknown material configuration.").arg(printJob.assignedPrinter.name); - } - var result = "

" + topLine +"

"; - for (var i = 0; i < printJob.configurationChanges.length; i++) { - var change = printJob.configurationChanges[i]; - var text; - switch (change.typeOfChange) { - case "material_change": - text = catalog.i18nc("@label", "Change material %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName); - break; - case "material_insert": - text = catalog.i18nc("@label", "Load %3 as material %1 (This cannot be overridden).").arg(change.index + 1).arg(change.targetName); - break; - case "print_core_change": - text = catalog.i18nc("@label", "Change print core %1 from %2 to %3.").arg(change.index + 1).arg(change.originName).arg(change.targetName); - break; - case "buildplate_change": - text = catalog.i18nc("@label", "Change build plate to %1 (This cannot be overridden).").arg(formatBuildPlateType(change.target_name)); - break; - default: - text = ""; - } - result += "

" + text + "

"; - } - return result; - } - wrapMode: Text.WordWrap; - } - - Button { - anchors { - bottom: parent.bottom; - left: parent.left; - } - background: Rectangle { - border { - color: UM.Theme.getColor("monitor_lining_heavy"); - width: UM.Theme.getSize("default_lining").width; - } - color: parent.hovered ? UM.Theme.getColor("monitor_card_background_inactive") : UM.Theme.getColor("monitor_card_background"); - implicitHeight: UM.Theme.getSize("default_margin").height * 3; - implicitWidth: UM.Theme.getSize("default_margin").height * 8; - } - contentItem: Label { - color: UM.Theme.getColor("text"); - font: UM.Theme.getFont("medium"); - horizontalAlignment: Text.AlignHCenter; - text: parent.text; - verticalAlignment: Text.AlignVCenter; - } - onClicked: { - overrideConfirmationDialog.visible = true; - } - text: catalog.i18nc("@label", "Override"); - visible: { - if (printJob && printJob.configurationChanges) { - var length = printJob.configurationChanges.length; - for (var i = 0; i < length; i++) { - var typeOfChange = printJob.configurationChanges[i].typeOfChange; - if (typeOfChange === "material_insert" || typeOfChange === "buildplate_change") { - return false; - } - } - } - return true; - } - } - } - } - - MessageDialog { - id: overrideConfirmationDialog; - Component.onCompleted: visible = false; - icon: StandardIcon.Warning; - onYes: OutputDevice.forceSendJob(printJob.key); - standardButtons: StandardButton.Yes | StandardButton.No; - text: { - if (!printJob) { - return ""; - } - var printJobName = formatPrintJobName(printJob.name); - var confirmText = catalog.i18nc("@label", "Starting a print job with an incompatible configuration could damage your 3D printer. Are you sure you want to override the configuration and print %1?").arg(printJobName); - return confirmText; - } - title: catalog.i18nc("@window:title", "Override configuration configuration and start print"); - } - } - } - } - // Utils - function formatPrintJobName(name) { - var extensions = [ ".gz", ".gcode", ".ufp" ]; - for (var i = 0; i < extensions.length; i++) { - var extension = extensions[i]; - if (name.slice(-extension.length) === extension) { - name = name.substring(0, name.length - extension.length); - } - } - return name; - } - function materialsAreKnown(job) { - var conf0 = job.configuration[0]; - if (conf0 && !conf0.material.material) { - return false; - } - var conf1 = job.configuration[1]; - if (conf1 && !conf1.material.material) { - return false; - } - return true; - } - function formatBuildPlateType(buildPlateType) { - var translationText = ""; - switch (buildPlateType) { - case "glass": - translationText = catalog.i18nc("@label", "Glass"); - break; - case "aluminum": - translationText = catalog.i18nc("@label", "Aluminum"); - break; - default: - translationText = null; - } - return translationText; - } -} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml deleted file mode 100644 index b1a73255f4..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.3 -import QtQuick.Dialogs 1.1 -import QtQuick.Controls 2.0 -import QtQuick.Controls.Styles 1.3 -import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 as LegacyControls -import UM 1.3 as UM - -// Includes print job name, owner, and preview - -Item { - property var job: null; - property var useUltibot: false; - height: 100 * screenScaleFactor; - width: height; - - // Skeleton - Rectangle { - anchors.fill: parent; - color: UM.Theme.getColor("monitor_skeleton_fill"); - radius: UM.Theme.getSize("default_margin").width; - visible: !job; - } - - // Actual content - Image { - id: previewImage; - visible: job; - source: job ? job.previewImageUrl : ""; - opacity: { - if (job == null) { - return 1.0; - } - var states = ["wait_cleanup", "wait_user_action", "error", "paused"]; - if (states.indexOf(job.state) !== -1) { - return 0.5; - } - return 1.0; - } - anchors.fill: parent; - } - - UM.RecolorImage { - id: ultibotImage; - anchors.centerIn: parent; - color: UM.Theme.getColor("monitor_placeholder_image"); // TODO: Theme! - height: parent.height; - source: "../svg/ultibot.svg"; - sourceSize { - height: height; - width: width; - } - /* Since print jobs ALWAYS have an image url, we have to check if that image URL errors or - not in order to determine if we show the placeholder (ultibot) image instead. */ - visible: job && previewImage.status == Image.Error; - width: parent.width; - } - - UM.RecolorImage { - id: statusImage; - anchors.centerIn: parent; - color: "black"; // TODO: Theme! - height: Math.round(0.5 * parent.height); - source: job && job.state == "error" ? "../svg/aborted-icon.svg" : ""; - sourceSize { - height: height; - width: width; - } - visible: source != ""; - width: Math.round(0.5 * parent.width); - } -} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml deleted file mode 100644 index f9f7b5ae87..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.3 -import QtQuick.Controls 2.0 -import UM 1.3 as UM - -Column { - property var job: null; - height: childrenRect.height; - spacing: Math.floor( UM.Theme.getSize("default_margin").height / 2); // TODO: Use explicit theme size - width: parent.width; - - Item { - id: jobName; - height: UM.Theme.getSize("monitor_text_line").height; - width: parent.width; - - // Skeleton loading - Rectangle { - color: UM.Theme.getColor("monitor_skeleton_fill"); - height: parent.height; - visible: !job; - width: Math.round(parent.width / 3); - } - - Label { - anchors.fill: parent; - color: UM.Theme.getColor("text"); - elide: Text.ElideRight; - font: UM.Theme.getFont("default_bold"); - text: job && job.name ? job.name : ""; - visible: job; - } - } - - Item { - id: ownerName; - height: UM.Theme.getSize("monitor_text_line").height; - width: parent.width; - - // Skeleton loading - Rectangle { - color: UM.Theme.getColor("monitor_skeleton_fill"); - height: parent.height; - visible: !job; - width: Math.round(parent.width / 2); - } - - Label { - anchors.fill: parent; - color: UM.Theme.getColor("text") - elide: Text.ElideRight; - font: UM.Theme.getFont("default"); - text: job ? job.owner : ""; - visible: job; - } - } -} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml deleted file mode 100644 index 24beaf70fe..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.3 -import QtQuick.Dialogs 1.1 -import QtQuick.Controls 2.0 -import QtQuick.Controls.Styles 1.3 -import QtGraphicalEffects 1.0 -import UM 1.3 as UM - -Item { - id: root; - property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width; - property var shadowOffset: UM.Theme.getSize("monitor_shadow_offset").width; - property var printer: null; - property var collapsed: true; - height: childrenRect.height + shadowRadius * 2; // Bubbles upward - width: parent.width; // Bubbles downward - - // The actual card (white block) - Rectangle { - // 5px margin, but shifted 2px vertically because of the shadow - anchors { - bottomMargin: root.shadowRadius + root.shadowOffset; - leftMargin: root.shadowRadius; - rightMargin: root.shadowRadius; - topMargin: root.shadowRadius - root.shadowOffset; - } - color: { - if (!printer) { - return UM.Theme.getColor("monitor_card_background_inactive"); - } - if (printer.state == "disabled") { - return UM.Theme.getColor("monitor_card_background_inactive"); - } else { - return UM.Theme.getColor("monitor_card_background"); - } - } - height: childrenRect.height; - layer.effect: DropShadow { - radius: root.shadowRadius; - verticalOffset: root.shadowOffset; - color: "#3F000000"; // 25% shadow - } - layer.enabled: true - width: parent.width - 2 * shadowRadius; - - Column { - id: cardContents; - height: childrenRect.height; - width: parent.width; - - // Main card - Item { - id: mainCard; - anchors { - left: parent.left; - leftMargin: UM.Theme.getSize("default_margin").width; - right: parent.right; - rightMargin: UM.Theme.getSize("default_margin").width; - } - height: 60 * screenScaleFactor + 2 * UM.Theme.getSize("default_margin").height; - width: parent.width; - - // Machine icon - Item { - id: machineIcon; - anchors.verticalCenter: parent.verticalCenter; - height: parent.height - 2 * UM.Theme.getSize("default_margin").width; - width: height; - - // Skeleton - Rectangle { - anchors.fill: parent; - color: UM.Theme.getColor("monitor_skeleton_fill_dark"); - radius: UM.Theme.getSize("default_margin").width; - visible: !printer; - } - - // Content - UM.RecolorImage { - anchors.centerIn: parent; - color: { - if (printer && printer.activePrintJob != undefined) { - return UM.Theme.getColor("monitor_printer_icon"); - } - return UM.Theme.getColor("monitor_printer_icon_inactive"); - } - height: sourceSize.height; - source: { - if (!printer) { - return ""; - } - switch(printer.type) { - case "Ultimaker 3": - return "../svg/UM3-icon.svg"; - case "Ultimaker 3 Extended": - return "../svg/UM3x-icon.svg"; - case "Ultimaker S5": - return "../svg/UMs5-icon.svg"; - } - } - visible: printer; - width: sourceSize.width; - } - } - - // Printer info - Item { - id: printerInfo; - anchors { - left: machineIcon.right; - leftMargin: UM.Theme.getSize("wide_margin").width; - right: collapseIcon.left; - verticalCenter: machineIcon.verticalCenter; - } - height: childrenRect.height; - - // Machine name - Item { - id: machineNameLabel; - height: UM.Theme.getSize("monitor_text_line").height; - width: { - var percent = printer ? 0.75 : 0.3; - return Math.round(parent.width * percent); - } - - // Skeleton - Rectangle { - anchors.fill: parent; - color: UM.Theme.getColor("monitor_skeleton_fill_dark"); - visible: !printer; - } - - // Actual content - Label { - anchors.fill: parent; - color: UM.Theme.getColor("text"); - elide: Text.ElideRight; - font: UM.Theme.getFont("default_bold"); - text: printer ? printer.name : ""; - visible: printer; - width: parent.width; - } - } - - // Job name - Item { - id: activeJobLabel; - anchors { - top: machineNameLabel.bottom; - topMargin: Math.round(UM.Theme.getSize("default_margin").height / 2); - } - height: UM.Theme.getSize("monitor_text_line").height; - width: Math.round(parent.width * 0.75); - - // Skeleton - Rectangle { - anchors.fill: parent; - color: UM.Theme.getColor("monitor_skeleton_fill_dark"); - visible: !printer; - } - - // Actual content - Label { - anchors.fill: parent; - color: UM.Theme.getColor("monitor_text_inactive"); - elide: Text.ElideRight; - font: UM.Theme.getFont("default"); - text: { - if (!printer) { - return ""; - } - if (printer.state == "disabled") { - return catalog.i18nc("@label", "Not available"); - } else if (printer.state == "unreachable") { - return catalog.i18nc("@label", "Unreachable"); - } - if (printer.activePrintJob != null && printer.activePrintJob.name) { - return printer.activePrintJob.name; - } - return catalog.i18nc("@label", "Available"); - } - visible: printer; - } - } - } - - // Collapse icon - UM.RecolorImage { - id: collapseIcon; - anchors { - right: parent.right; - rightMargin: UM.Theme.getSize("default_margin").width; - verticalCenter: parent.verticalCenter; - } - color: UM.Theme.getColor("text"); - height: 15 * screenScaleFactor; // TODO: Theme! - source: root.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom"); - sourceSize { - height: height; - width: width; - } - visible: printer; - width: 15 * screenScaleFactor; // TODO: Theme! - } - - MouseArea { - anchors.fill: parent; - enabled: printer; - onClicked: { - if (model && root.collapsed) { - printerList.currentIndex = model.index; - } else { - printerList.currentIndex = -1; - } - } - } - - Connections { - target: printerList; - onCurrentIndexChanged: { - root.collapsed = printerList.currentIndex != model.index; - } - } - } - // Detailed card - PrinterCardDetails { - collapsed: root.collapsed; - printer: root.printer; - visible: root.printer; - } - - // Progress bar - PrinterCardProgressBar { - visible: printer && printer.activePrintJob != null; - width: parent.width; - } - } - } -} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml deleted file mode 100644 index 31da388b00..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.3 -import QtQuick.Dialogs 1.1 -import QtQuick.Controls 2.0 -import QtQuick.Controls.Styles 1.3 -import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 as LegacyControls -import UM 1.3 as UM - -Item { - id: root; - property var printer: null; - property var printJob: printer ? printer.activePrintJob : null; - property var collapsed: true; - Behavior on height { NumberAnimation { duration: 100 } } - Behavior on opacity { NumberAnimation { duration: 100 } } - height: collapsed ? 0 : childrenRect.height; - opacity: collapsed ? 0 : 1; - width: parent.width; - - Column { - id: contentColumn; - anchors { - left: parent.left; - leftMargin: UM.Theme.getSize("default_margin").width; - right: parent.right; - rightMargin: UM.Theme.getSize("default_margin").width; - } - height: childrenRect.height + UM.Theme.getSize("default_margin").height; - spacing: UM.Theme.getSize("default_margin").height; - width: parent.width; - - HorizontalLine {} - - PrinterInfoBlock { - printer: root.printer; - printJob: root.printer ? root.printer.activePrintJob : null; - } - - HorizontalLine {} - - Row { - height: childrenRect.height; - visible: root.printJob; - width: parent.width; - - PrintJobTitle { - job: root.printer ? root.printer.activePrintJob : null; - } - PrintJobContextMenu { - id: contextButton; - anchors { - right: parent.right; - rightMargin: UM.Theme.getSize("wide_margin").width; - } - printJob: root.printer ? root.printer.activePrintJob : null; - visible: printJob; - } - } - - PrintJobPreview { - anchors.horizontalCenter: parent.horizontalCenter; - job: root.printer && root.printer.activePrintJob ? root.printer.activePrintJob : null; - visible: root.printJob; - } - - CameraButton { - id: showCameraButton; - iconSource: "../svg/camera-icon.svg"; - visible: root.printer; - } - } -} diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml deleted file mode 100644 index e86c959b8c..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.3 -import QtQuick.Controls.Styles 1.3 -import QtQuick.Controls 1.4 -import UM 1.3 as UM - -ProgressBar { - property var progress: { - if (!printer || printer.activePrintJob == null) { - return 0; - } - var result = printer.activePrintJob.timeElapsed / printer.activePrintJob.timeTotal; - if (result > 1.0) { - result = 1.0; - } - return result; - } - style: ProgressBarStyle { - property var remainingTime: { - if (!printer || printer.activePrintJob == null) { - return 0; - } - /* Sometimes total minus elapsed is less than 0. Use Math.max() to prevent remaining - time from ever being less than 0. Negative durations cause strange behavior such - as displaying "-1h -1m". */ - return Math.max(printer.activePrintJob.timeTotal - printer.activePrintJob.timeElapsed, 0); - } - property var progressText: { - if (printer === null ) { - return ""; - } - switch (printer.activePrintJob.state) { - case "wait_cleanup": - if (printer.activePrintJob.timeTotal > printer.activePrintJob.timeElapsed) { - return catalog.i18nc("@label:status", "Aborted"); - } - return catalog.i18nc("@label:status", "Finished"); - case "pre_print": - case "sent_to_printer": - return catalog.i18nc("@label:status", "Preparing"); - case "aborted": - return catalog.i18nc("@label:status", "Aborted"); - case "wait_user_action": - return catalog.i18nc("@label:status", "Aborted"); - case "pausing": - return catalog.i18nc("@label:status", "Pausing"); - case "paused": - return OutputDevice.formatDuration( remainingTime ); - case "resuming": - return catalog.i18nc("@label:status", "Resuming"); - case "queued": - return catalog.i18nc("@label:status", "Action required"); - default: - return OutputDevice.formatDuration( remainingTime ); - } - } - background: Rectangle { - color: UM.Theme.getColor("monitor_progress_background"); - implicitHeight: visible ? 24 : 0; - implicitWidth: 100; - } - progress: Rectangle { - id: progressItem; - color: { - if (! printer || !printer.activePrintJob) { - return "black"; - } - var state = printer.activePrintJob.state - var inactiveStates = [ - "pausing", - "paused", - "resuming", - "wait_cleanup" - ]; - if (inactiveStates.indexOf(state) > -1 && remainingTime > 0) { - return UM.Theme.getColor("monitor_progress_fill_inactive"); - } else { - return UM.Theme.getColor("monitor_progress_fill"); - } - } - - Label { - id: progressLabel; - anchors { - left: parent.left; - leftMargin: getTextOffset(); - } - text: progressText; - anchors.verticalCenter: parent.verticalCenter; - color: progressItem.width + progressLabel.width < control.width ? UM.Theme.getColor("text") : UM.Theme.getColor("monitor_progress_fill_text"); - width: contentWidth; - font: UM.Theme.getFont("default"); - } - - function getTextOffset() { - if (progressItem.width + progressLabel.width + 16 < control.width) { - return progressItem.width + UM.Theme.getSize("default_margin").width; - } else { - return progressItem.width - progressLabel.width - UM.Theme.getSize("default_margin").width; - } - } - } - } - value: progress; - width: parent.width; -} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml deleted file mode 100644 index 0a88b053a8..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml +++ /dev/null @@ -1,32 +0,0 @@ -// 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.4 -import UM 1.2 as UM - -Item { - property alias text: familyNameLabel.text; - property var padding: 3 * screenScaleFactor; // TODO: Theme! - implicitHeight: familyNameLabel.contentHeight + 2 * padding; // Apply the padding to top and bottom. - implicitWidth: Math.max(48 * screenScaleFactor, familyNameLabel.contentWidth + implicitHeight); // The extra height is added to ensure the radius doesn't cut something off. - - Rectangle { - id: background; - anchors { - horizontalCenter: parent.horizontalCenter; - right: parent.right; - } - color: familyNameLabel.text.length < 1 ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_pill_background"); - height: parent.height; - radius: 0.5 * height; - width: parent.width; - } - - Label { - id: familyNameLabel; - anchors.centerIn: parent; - color: UM.Theme.getColor("text"); - text: ""; - } -} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml deleted file mode 100644 index 92a8f1dcb3..0000000000 --- a/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.3 -import QtQuick.Dialogs 1.1 -import QtQuick.Controls 2.0 -import QtQuick.Controls.Styles 1.3 -import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 as LegacyControls -import UM 1.3 as UM - -// Includes printer type pill and extuder configurations - -Item { - id: root; - property var printer: null; - property var printJob: null; - width: parent.width; - height: childrenRect.height; - - // Printer family pills - Row { - id: printerFamilyPills; - anchors { - left: parent.left; - right: parent.right; - } - height: childrenRect.height; - spacing: Math.round(0.5 * UM.Theme.getSize("default_margin").width); - width: parent.width; - - Repeater { - id: compatiblePills; - delegate: PrinterFamilyPill { - text: modelData; - } - model: printJob ? printJob.compatibleMachineFamilies : []; - visible: printJob; - - } - - PrinterFamilyPill { - text: printer ? printer.type : ""; - visible: !compatiblePills.visible && printer; - } - } - - // Extruder info - Row { - id: extrudersInfo; - anchors { - left: parent.left; - right: parent.right; - rightMargin: UM.Theme.getSize("default_margin").width; - top: printerFamilyPills.bottom; - topMargin: UM.Theme.getSize("default_margin").height; - } - height: childrenRect.height; - spacing: UM.Theme.getSize("default_margin").width; - width: parent.width; - - PrintCoreConfiguration { - width: Math.round(parent.width / 2) * screenScaleFactor; - printCoreConfiguration: getExtruderConfig(0); - } - - PrintCoreConfiguration { - width: Math.round(parent.width / 2) * screenScaleFactor; - printCoreConfiguration: getExtruderConfig(1); - } - } - - function getExtruderConfig( i ) { - if (root.printJob) { - // Use more-specific print job if possible - return root.printJob.configuration.extruderConfigurations[i]; - } - if (root.printer) { - return root.printer.printerConfiguration.extruderConfigurations[i]; - } - return null; - } -} \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml b/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml index 105143c851..c99ed1688e 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml @@ -13,8 +13,40 @@ Item { property string activeQualityDefinitionId: Cura.MachineManager.activeQualityDefinitionId; property bool isUM3: activeQualityDefinitionId == "ultimaker3" || activeQualityDefinitionId.match("ultimaker_") != null; property bool printerConnected: Cura.MachineManager.printerConnected; - property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands; - property bool authenticationRequested: printerConnected && (Cura.MachineManager.printerOutputDevices[0].authenticationState == 2 || Cura.MachineManager.printerOutputDevices[0].authenticationState == 5); // AuthState.AuthenticationRequested or AuthenticationReceived. + property bool printerAcceptsCommands: + { + if (printerConnected && Cura.MachineManager.printerOutputDevices[0]) + { + return Cura.MachineManager.printerOutputDevices[0].acceptsCommands + } + return false + } + property bool authenticationRequested: + { + if (printerConnected && Cura.MachineManager.printerOutputDevices[0]) + { + var device = Cura.MachineManager.printerOutputDevices[0] + // AuthState.AuthenticationRequested or AuthState.AuthenticationReceived + return device.authenticationState == 2 || device.authenticationState == 5 + } + return false + } + property var materialNames: + { + if (printerConnected && Cura.MachineManager.printerOutputDevices[0]) + { + return Cura.MachineManager.printerOutputDevices[0].materialNames + } + return null + } + property var hotendIds: + { + if (printerConnected && Cura.MachineManager.printerOutputDevices[0]) + { + return Cura.MachineManager.printerOutputDevices[0].hotendIds + } + return null + } UM.I18nCatalog { id: catalog; @@ -29,7 +61,7 @@ Item { Button { height: UM.Theme.getSize("save_button_save_to_button").height; onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication(); - style: UM.Theme.styles.sidebar_action_button; + style: UM.Theme.styles.print_setup_action_button; text: catalog.i18nc("@action:button", "Request Access"); tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer"); visible: printerConnected && !printerAcceptsCommands && !authenticationRequested; @@ -38,7 +70,7 @@ Item { Button { height: UM.Theme.getSize("save_button_save_to_button").height; onClicked: connectActionDialog.show(); - style: UM.Theme.styles.sidebar_action_button; + style: UM.Theme.styles.print_setup_action_button; text: catalog.i18nc("@action:button", "Connect"); tooltip: catalog.i18nc("@info:tooltip", "Connect to a printer"); visible: !printerConnected; @@ -58,69 +90,4 @@ Item { source: "DiscoverUM3Action.qml"; } } - - Column { - anchors.fill: parent; - objectName: "networkPrinterConnectionInfo"; - spacing: UM.Theme.getSize("default_margin").width; - visible: isUM3; - - Button { - onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication(); - text: catalog.i18nc("@action:button", "Request Access"); - tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer"); - visible: printerConnected && !printerAcceptsCommands && !authenticationRequested; - } - - Row { - anchors { - left: parent.left; - right: parent.right; - } - height: childrenRect.height; - spacing: UM.Theme.getSize("default_margin").width; - visible: printerConnected; - - Column { - Repeater { - model: Cura.ExtrudersModel { - simpleNames: true; - } - - Label { - text: model.name; - } - } - } - - Column { - Repeater { - id: nozzleColumn; - model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].hotendIds : null; - - Label { - text: nozzleColumn.model[index]; - } - } - } - - Column { - Repeater { - id: materialColumn; - model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].materialNames : null; - - Label { - text: materialColumn.model[index]; - } - } - } - } - - Button { - onClicked: manager.loadConfigurationFromPrinter(); - text: catalog.i18nc("@action:button", "Activate Configuration"); - tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura"); - visible: false; // printerConnected && !isClusterPrinter() - } - } } diff --git a/plugins/UM3NetworkPrinting/resources/svg/icons/buildplate.svg b/plugins/UM3NetworkPrinting/resources/svg/icons/buildplate.svg new file mode 100644 index 0000000000..bcb278a8ca --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/svg/icons/buildplate.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/svg/icons/camera.svg b/plugins/UM3NetworkPrinting/resources/svg/icons/camera.svg new file mode 100644 index 0000000000..2eaebb812d --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/svg/icons/camera.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/resources/svg/icons/extruder.svg b/plugins/UM3NetworkPrinting/resources/svg/icons/extruder.svg new file mode 100644 index 0000000000..235cb432e9 --- /dev/null +++ b/plugins/UM3NetworkPrinting/resources/svg/icons/extruder.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py new file mode 100644 index 0000000000..9d6c29c0a4 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudApiClient.py @@ -0,0 +1,166 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import json +from json import JSONDecodeError +from time import time +from typing import Callable, List, Type, TypeVar, Union, Optional, Tuple, Dict, Any, cast + +from PyQt5.QtCore import QUrl +from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply, QNetworkAccessManager + +from UM.Logger import Logger +from cura import UltimakerCloudAuthentication +from cura.API import Account +from .ToolPathUploader import ToolPathUploader +from ..Models import BaseModel +from .Models.CloudClusterResponse import CloudClusterResponse +from .Models.CloudError import CloudError +from .Models.CloudClusterStatus import CloudClusterStatus +from .Models.CloudPrintJobUploadRequest import CloudPrintJobUploadRequest +from .Models.CloudPrintResponse import CloudPrintResponse +from .Models.CloudPrintJobResponse import CloudPrintJobResponse + + +## The generic type variable used to document the methods below. +CloudApiClientModel = TypeVar("CloudApiClientModel", bound = BaseModel) + + +## The cloud API client is responsible for handling the requests and responses from the cloud. +# Each method should only handle models instead of exposing Any HTTP details. +class CloudApiClient: + + # The cloud URL to use for this remote cluster. + ROOT_PATH = UltimakerCloudAuthentication.CuraCloudAPIRoot + CLUSTER_API_ROOT = "{}/connect/v1".format(ROOT_PATH) + CURA_API_ROOT = "{}/cura/v1".format(ROOT_PATH) + + ## Initializes a new cloud API client. + # \param account: The user's account object + # \param on_error: The callback to be called whenever we receive errors from the server. + def __init__(self, account: Account, on_error: Callable[[List[CloudError]], None]) -> None: + super().__init__() + self._manager = QNetworkAccessManager() + self._account = account + self._on_error = on_error + self._upload = None # type: Optional[ToolPathUploader] + # In order to avoid garbage collection we keep the callbacks in this list. + self._anti_gc_callbacks = [] # type: List[Callable[[], None]] + + ## Gets the account used for the API. + @property + def account(self) -> Account: + return self._account + + ## Retrieves all the clusters for the user that is currently logged in. + # \param on_finished: The function to be called after the result is parsed. + def getClusters(self, on_finished: Callable[[List[CloudClusterResponse]], Any]) -> None: + url = "{}/clusters".format(self.CLUSTER_API_ROOT) + reply = self._manager.get(self._createEmptyRequest(url)) + self._addCallback(reply, on_finished, CloudClusterResponse) + + ## Retrieves the status of the given cluster. + # \param cluster_id: The ID of the cluster. + # \param on_finished: The function to be called after the result is parsed. + def getClusterStatus(self, cluster_id: str, on_finished: Callable[[CloudClusterStatus], Any]) -> None: + url = "{}/clusters/{}/status".format(self.CLUSTER_API_ROOT, cluster_id) + reply = self._manager.get(self._createEmptyRequest(url)) + self._addCallback(reply, on_finished, CloudClusterStatus) + + ## Requests the cloud to register the upload of a print job mesh. + # \param request: The request object. + # \param on_finished: The function to be called after the result is parsed. + def requestUpload(self, request: CloudPrintJobUploadRequest, on_finished: Callable[[CloudPrintJobResponse], Any] + ) -> None: + url = "{}/jobs/upload".format(self.CURA_API_ROOT) + body = json.dumps({"data": request.toDict()}) + reply = self._manager.put(self._createEmptyRequest(url), body.encode()) + self._addCallback(reply, on_finished, CloudPrintJobResponse) + + ## Uploads a print job tool path to the cloud. + # \param print_job: The object received after requesting an upload with `self.requestUpload`. + # \param mesh: The tool path data to be uploaded. + # \param on_finished: The function to be called after the upload is successful. + # \param on_progress: A function to be called during upload progress. It receives a percentage (0-100). + # \param on_error: A function to be called if the upload fails. + def uploadToolPath(self, print_job: CloudPrintJobResponse, mesh: bytes, on_finished: Callable[[], Any], + on_progress: Callable[[int], Any], on_error: Callable[[], Any]): + self._upload = ToolPathUploader(self._manager, print_job, mesh, on_finished, on_progress, on_error) + self._upload.start() + + # Requests a cluster to print the given print job. + # \param cluster_id: The ID of the cluster. + # \param job_id: The ID of the print job. + # \param on_finished: The function to be called after the result is parsed. + def requestPrint(self, cluster_id: str, job_id: str, on_finished: Callable[[CloudPrintResponse], Any]) -> None: + url = "{}/clusters/{}/print/{}".format(self.CLUSTER_API_ROOT, cluster_id, job_id) + reply = self._manager.post(self._createEmptyRequest(url), b"") + self._addCallback(reply, on_finished, CloudPrintResponse) + + ## We override _createEmptyRequest in order to add the user credentials. + # \param url: The URL to request + # \param content_type: The type of the body contents. + def _createEmptyRequest(self, path: str, content_type: Optional[str] = "application/json") -> QNetworkRequest: + request = QNetworkRequest(QUrl(path)) + if content_type: + request.setHeader(QNetworkRequest.ContentTypeHeader, content_type) + if self._account.isLoggedIn: + request.setRawHeader(b"Authorization", "Bearer {}".format(self._account.accessToken).encode()) + return request + + ## Parses the given JSON network reply into a status code and a dictionary, handling unexpected errors as well. + # \param reply: The reply from the server. + # \return A tuple with a status code and a dictionary. + @staticmethod + def _parseReply(reply: QNetworkReply) -> Tuple[int, Dict[str, Any]]: + status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) + try: + response = bytes(reply.readAll()).decode() + return status_code, json.loads(response) + except (UnicodeDecodeError, JSONDecodeError, ValueError) as err: + error = CloudError(code=type(err).__name__, title=str(err), http_code=str(status_code), + id=str(time()), http_status="500") + Logger.logException("e", "Could not parse the stardust response: %s", error) + return status_code, {"errors": [error.toDict()]} + + ## Parses the given models and calls the correct callback depending on the result. + # \param response: The response from the server, after being converted to a dict. + # \param on_finished: The callback in case the response is successful. + # \param model_class: The type of the model to convert the response to. It may either be a single record or a list. + def _parseModels(self, response: Dict[str, Any], + on_finished: Union[Callable[[CloudApiClientModel], Any], + Callable[[List[CloudApiClientModel]], Any]], + model_class: Type[CloudApiClientModel]) -> None: + if "data" in response: + data = response["data"] + if isinstance(data, list): + results = [model_class(**c) for c in data] # type: List[CloudApiClientModel] + on_finished_list = cast(Callable[[List[CloudApiClientModel]], Any], on_finished) + on_finished_list(results) + else: + result = model_class(**data) # type: CloudApiClientModel + on_finished_item = cast(Callable[[CloudApiClientModel], Any], on_finished) + on_finished_item(result) + elif "errors" in response: + self._on_error([CloudError(**error) for error in response["errors"]]) + else: + Logger.log("e", "Cannot find data or errors in the cloud response: %s", response) + + ## Creates a callback function so that it includes the parsing of the response into the correct model. + # The callback is added to the 'finished' signal of the reply. + # \param reply: The reply that should be listened to. + # \param on_finished: The callback in case the response is successful. Depending on the endpoint it will be either + # a list or a single item. + # \param model: The type of the model to convert the response to. + def _addCallback(self, + reply: QNetworkReply, + on_finished: Union[Callable[[CloudApiClientModel], Any], + Callable[[List[CloudApiClientModel]], Any]], + model: Type[CloudApiClientModel], + ) -> None: + def parse() -> None: + status_code, response = self._parseReply(reply) + self._anti_gc_callbacks.remove(parse) + return self._parseModels(response, on_finished, model) + + self._anti_gc_callbacks.append(parse) + reply.finished.connect(parse) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputController.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputController.py new file mode 100644 index 0000000000..bd56ef3185 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputController.py @@ -0,0 +1,22 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from cura.PrinterOutput.PrinterOutputController import PrinterOutputController + +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from .CloudOutputDevice import CloudOutputDevice + + +class CloudOutputController(PrinterOutputController): + def __init__(self, output_device: "CloudOutputDevice") -> None: + super().__init__(output_device) + + # The cloud connection only supports fetching the printer and queue status and adding a job to the queue. + # To let the UI know this we mark all features below as False. + self.can_pause = False + self.can_abort = False + self.can_pre_heat_bed = False + self.can_pre_heat_hotends = False + self.can_send_raw_gcode = False + self.can_control_manually = False + self.can_update_firmware = False diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py new file mode 100644 index 0000000000..33968beb6d --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py @@ -0,0 +1,424 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import os + +from time import time +from typing import Dict, List, Optional, Set, cast + +from PyQt5.QtCore import QObject, QUrl, pyqtProperty, pyqtSignal, pyqtSlot + +from UM import i18nCatalog +from UM.Backend.Backend import BackendState +from UM.FileHandler.FileHandler import FileHandler +from UM.Logger import Logger +from UM.Message import Message +from UM.Qt.Duration import Duration, DurationFormat +from UM.Scene.SceneNode import SceneNode +from cura.CuraApplication import CuraApplication +from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState, NetworkedPrinterOutputDevice +from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel +from cura.PrinterOutputDevice import ConnectionType + +from .CloudOutputController import CloudOutputController +from ..MeshFormatHandler import MeshFormatHandler +from ..UM3PrintJobOutputModel import UM3PrintJobOutputModel +from .CloudProgressMessage import CloudProgressMessage +from .CloudApiClient import CloudApiClient +from .Models.CloudClusterResponse import CloudClusterResponse +from .Models.CloudClusterStatus import CloudClusterStatus +from .Models.CloudPrintJobUploadRequest import CloudPrintJobUploadRequest +from .Models.CloudPrintResponse import CloudPrintResponse +from .Models.CloudPrintJobResponse import CloudPrintJobResponse +from .Models.CloudClusterPrinterStatus import CloudClusterPrinterStatus +from .Models.CloudClusterPrintJobStatus import CloudClusterPrintJobStatus +from .Utils import findChanges, formatDateCompleted, formatTimeCompleted + + +I18N_CATALOG = i18nCatalog("cura") + + +## The cloud output device is a network output device that works remotely but has limited functionality. +# Currently it only supports viewing the printer and print job status and adding a new job to the queue. +# As such, those methods have been implemented here. +# Note that this device represents a single remote cluster, not a list of multiple clusters. +class CloudOutputDevice(NetworkedPrinterOutputDevice): + + # The interval with which the remote clusters are checked + CHECK_CLUSTER_INTERVAL = 10.0 # seconds + + # Signal triggered when the print jobs in the queue were changed. + printJobsChanged = pyqtSignal() + + # Signal triggered when the selected printer in the UI should be changed. + activePrinterChanged = pyqtSignal() + + # Notify can only use signals that are defined by the class that they are in, not inherited ones. + # Therefore we create a private signal used to trigger the printersChanged signal. + _clusterPrintersChanged = pyqtSignal() + + ## Creates a new cloud output device + # \param api_client: The client that will run the API calls + # \param cluster: The device response received from the cloud API. + # \param parent: The optional parent of this output device. + def __init__(self, api_client: CloudApiClient, cluster: CloudClusterResponse, parent: QObject = None) -> None: + super().__init__(device_id = cluster.cluster_id, address = "", + connection_type = ConnectionType.CloudConnection, properties = {}, parent = parent) + self._api = api_client + self._cluster = cluster + + self._setInterfaceElements() + + self._account = api_client.account + + # We use the Cura Connect monitor tab to get most functionality right away. + self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), + "../../resources/qml/MonitorStage.qml") + + # Trigger the printersChanged signal when the private signal is triggered. + self.printersChanged.connect(self._clusterPrintersChanged) + + # We keep track of which printer is visible in the monitor page. + self._active_printer = None # type: Optional[PrinterOutputModel] + + # Properties to populate later on with received cloud data. + self._print_jobs = [] # type: List[UM3PrintJobOutputModel] + self._number_of_extruders = 2 # All networked printers are dual-extrusion Ultimaker machines. + + # We only allow a single upload at a time. + self._progress = CloudProgressMessage() + + # Keep server string of the last generated time to avoid updating models more than once for the same response + self._received_printers = None # type: Optional[List[CloudClusterPrinterStatus]] + self._received_print_jobs = None # type: Optional[List[CloudClusterPrintJobStatus]] + + # A set of the user's job IDs that have finished + self._finished_jobs = set() # type: Set[str] + + # Reference to the uploaded print job / mesh + self._tool_path = None # type: Optional[bytes] + self._uploaded_print_job = None # type: Optional[CloudPrintJobResponse] + + ## Connects this device. + def connect(self) -> None: + if self.isConnected(): + return + super().connect() + Logger.log("i", "Connected to cluster %s", self.key) + CuraApplication.getInstance().getBackend().backendStateChange.connect(self._onBackendStateChange) + + ## Disconnects the device + def disconnect(self) -> None: + super().disconnect() + Logger.log("i", "Disconnected from cluster %s", self.key) + CuraApplication.getInstance().getBackend().backendStateChange.disconnect(self._onBackendStateChange) + + ## Resets the print job that was uploaded to force a new upload, runs whenever the user re-slices. + def _onBackendStateChange(self, _: BackendState) -> None: + self._tool_path = None + self._uploaded_print_job = None + + ## Gets the cluster response from which this device was created. + @property + def clusterData(self) -> CloudClusterResponse: + return self._cluster + + ## Updates the cluster data from the cloud. + @clusterData.setter + def clusterData(self, value: CloudClusterResponse) -> None: + self._cluster = value + + ## Checks whether the given network key is found in the cloud's host name + def matchesNetworkKey(self, network_key: str) -> bool: + # A network key looks like "ultimakersystem-aabbccdd0011._ultimaker._tcp.local." + # the host name should then be "ultimakersystem-aabbccdd0011" + return network_key.startswith(self.clusterData.host_name) + + ## Set all the interface elements and texts for this output device. + def _setInterfaceElements(self) -> None: + self.setPriority(2) # Make sure we end up below the local networking and above 'save to file' + self.setName(self._id) + self.setShortDescription(I18N_CATALOG.i18nc("@action:button", "Print via Cloud")) + self.setDescription(I18N_CATALOG.i18nc("@properties:tooltip", "Print via Cloud")) + self.setConnectionText(I18N_CATALOG.i18nc("@info:status", "Connected via Cloud")) + + ## Called when Cura requests an output device to receive a (G-code) file. + def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, + file_handler: Optional[FileHandler] = None, **kwargs: str) -> None: + + # Show an error message if we're already sending a job. + if self._progress.visible: + message = Message( + text = I18N_CATALOG.i18nc("@info:status", "Sending new jobs (temporarily) blocked, still sending the previous print job."), + title = I18N_CATALOG.i18nc("@info:title", "Cloud error"), + lifetime = 10 + ) + message.show() + return + + if self._uploaded_print_job: + # The mesh didn't change, let's not upload it again + self._api.requestPrint(self.key, self._uploaded_print_job.job_id, self._onPrintUploadCompleted) + return + + # Indicate we have started sending a job. + self.writeStarted.emit(self) + + mesh_format = MeshFormatHandler(file_handler, self.firmwareVersion) + if not mesh_format.is_valid: + Logger.log("e", "Missing file or mesh writer!") + return self._onUploadError(I18N_CATALOG.i18nc("@info:status", "Could not export print job.")) + + mesh = mesh_format.getBytes(nodes) + + self._tool_path = mesh + request = CloudPrintJobUploadRequest( + job_name = file_name or mesh_format.file_extension, + file_size = len(mesh), + content_type = mesh_format.mime_type, + ) + self._api.requestUpload(request, self._onPrintJobCreated) + + ## Called when the network data should be updated. + def _update(self) -> None: + super()._update() + if self._last_request_time and time() - self._last_request_time < self.CHECK_CLUSTER_INTERVAL: + return # Avoid calling the cloud too often + + Logger.log("d", "Updating: %s - %s >= %s", time(), self._last_request_time, self.CHECK_CLUSTER_INTERVAL) + if self._account.isLoggedIn: + self.setAuthenticationState(AuthState.Authenticated) + self._last_request_time = time() + self._api.getClusterStatus(self.key, self._onStatusCallFinished) + else: + self.setAuthenticationState(AuthState.NotAuthenticated) + + ## Method called when HTTP request to status endpoint is finished. + # Contains both printers and print jobs statuses in a single response. + def _onStatusCallFinished(self, status: CloudClusterStatus) -> None: + # Update all data from the cluster. + self._last_response_time = time() + if self._received_printers != status.printers: + self._received_printers = status.printers + self._updatePrinters(status.printers) + + if status.print_jobs != self._received_print_jobs: + self._received_print_jobs = status.print_jobs + self._updatePrintJobs(status.print_jobs) + + ## Updates the local list of printers with the list received from the cloud. + # \param jobs: The printers received from the cloud. + def _updatePrinters(self, printers: List[CloudClusterPrinterStatus]) -> None: + previous = {p.key: p for p in self._printers} # type: Dict[str, PrinterOutputModel] + received = {p.uuid: p for p in printers} # type: Dict[str, CloudClusterPrinterStatus] + + removed_printers, added_printers, updated_printers = findChanges(previous, received) + + for removed_printer in removed_printers: + if self._active_printer == removed_printer: + self.setActivePrinter(None) + self._printers.remove(removed_printer) + + for added_printer in added_printers: + self._printers.append(added_printer.createOutputModel(CloudOutputController(self))) + + for model, printer in updated_printers: + printer.updateOutputModel(model) + + # Always have an active printer + if self._printers and not self._active_printer: + self.setActivePrinter(self._printers[0]) + + if added_printers or removed_printers: + self.printersChanged.emit() + + ## Updates the local list of print jobs with the list received from the cloud. + # \param jobs: The print jobs received from the cloud. + def _updatePrintJobs(self, jobs: List[CloudClusterPrintJobStatus]) -> None: + received = {j.uuid: j for j in jobs} # type: Dict[str, CloudClusterPrintJobStatus] + previous = {j.key: j for j in self._print_jobs} # type: Dict[str, UM3PrintJobOutputModel] + + removed_jobs, added_jobs, updated_jobs = findChanges(previous, received) + + for removed_job in removed_jobs: + if removed_job.assignedPrinter: + removed_job.assignedPrinter.updateActivePrintJob(None) + removed_job.stateChanged.disconnect(self._onPrintJobStateChanged) + self._print_jobs.remove(removed_job) + + for added_job in added_jobs: + self._addPrintJob(added_job) + + for model, job in updated_jobs: + job.updateOutputModel(model) + if job.printer_uuid: + self._updateAssignedPrinter(model, job.printer_uuid) + + # We only have to update when jobs are added or removed + # updated jobs push their changes via their output model + if added_jobs or removed_jobs: + self.printJobsChanged.emit() + + ## Registers a new print job received via the cloud API. + # \param job: The print job received. + def _addPrintJob(self, job: CloudClusterPrintJobStatus) -> None: + model = job.createOutputModel(CloudOutputController(self)) + model.stateChanged.connect(self._onPrintJobStateChanged) + if job.printer_uuid: + self._updateAssignedPrinter(model, job.printer_uuid) + self._print_jobs.append(model) + + ## Handles the event of a change in a print job state + def _onPrintJobStateChanged(self) -> None: + user_name = self._getUserName() + # TODO: confirm that notifications in Cura are still required + for job in self._print_jobs: + if job.state == "wait_cleanup" and job.key not in self._finished_jobs and job.owner == user_name: + self._finished_jobs.add(job.key) + Message( + title = I18N_CATALOG.i18nc("@info:status", "Print finished"), + text = (I18N_CATALOG.i18nc("@info:status", "Printer '{printer_name}' has finished printing '{job_name}'.").format( + printer_name = job.assignedPrinter.name, + job_name = job.name + ) if job.assignedPrinter else + I18N_CATALOG.i18nc("@info:status", "The print job '{job_name}' was finished.").format( + job_name = job.name + )), + ).show() + + ## Updates the printer assignment for the given print job model. + def _updateAssignedPrinter(self, model: UM3PrintJobOutputModel, printer_uuid: str) -> None: + printer = next((p for p in self._printers if printer_uuid == p.key), None) + if not printer: + Logger.log("w", "Missing printer %s for job %s in %s", model.assignedPrinter, model.key, + [p.key for p in self._printers]) + return + + printer.updateActivePrintJob(model) + model.updateAssignedPrinter(printer) + + ## Uploads the mesh when the print job was registered with the cloud API. + # \param job_response: The response received from the cloud API. + def _onPrintJobCreated(self, job_response: CloudPrintJobResponse) -> None: + self._progress.show() + self._uploaded_print_job = job_response + tool_path = cast(bytes, self._tool_path) + self._api.uploadToolPath(job_response, tool_path, self._onPrintJobUploaded, self._progress.update, self._onUploadError) + + ## Requests the print to be sent to the printer when we finished uploading the mesh. + def _onPrintJobUploaded(self) -> None: + self._progress.update(100) + print_job = cast(CloudPrintJobResponse, self._uploaded_print_job) + self._api.requestPrint(self.key, print_job.job_id, self._onPrintUploadCompleted) + + ## Displays the given message if uploading the mesh has failed + # \param message: The message to display. + def _onUploadError(self, message: str = None) -> None: + self._progress.hide() + self._uploaded_print_job = None + Message( + text = message or I18N_CATALOG.i18nc("@info:text", "Could not upload the data to the printer."), + title = I18N_CATALOG.i18nc("@info:title", "Cloud error"), + lifetime = 10 + ).show() + self.writeError.emit() + + ## Shows a message when the upload has succeeded + # \param response: The response from the cloud API. + def _onPrintUploadCompleted(self, response: CloudPrintResponse) -> None: + Logger.log("d", "The cluster will be printing this print job with the ID %s", response.cluster_job_id) + self._progress.hide() + Message( + text = I18N_CATALOG.i18nc("@info:status", "Print job was successfully sent to the printer."), + title = I18N_CATALOG.i18nc("@info:title", "Data Sent"), + lifetime = 5 + ).show() + self.writeFinished.emit() + + ## Gets the remote printers. + @pyqtProperty("QVariantList", notify=_clusterPrintersChanged) + def printers(self) -> List[PrinterOutputModel]: + return self._printers + + ## Get the active printer in the UI (monitor page). + @pyqtProperty(QObject, notify = activePrinterChanged) + def activePrinter(self) -> Optional[PrinterOutputModel]: + return self._active_printer + + ## Set the active printer in the UI (monitor page). + @pyqtSlot(QObject) + def setActivePrinter(self, printer: Optional[PrinterOutputModel] = None) -> None: + if printer != self._active_printer: + self._active_printer = printer + self.activePrinterChanged.emit() + + @pyqtProperty(int, notify = _clusterPrintersChanged) + def clusterSize(self) -> int: + return len(self._printers) + + ## Get remote print jobs. + @pyqtProperty("QVariantList", notify = printJobsChanged) + def printJobs(self) -> List[UM3PrintJobOutputModel]: + return self._print_jobs + + ## Get remote print jobs that are still in the print queue. + @pyqtProperty("QVariantList", notify = printJobsChanged) + def queuedPrintJobs(self) -> List[UM3PrintJobOutputModel]: + return [print_job for print_job in self._print_jobs + if print_job.state == "queued" or print_job.state == "error"] + + ## Get remote print jobs that are assigned to a printer. + @pyqtProperty("QVariantList", notify = printJobsChanged) + def activePrintJobs(self) -> List[UM3PrintJobOutputModel]: + return [print_job for print_job in self._print_jobs if + print_job.assignedPrinter is not None and print_job.state != "queued"] + + @pyqtSlot(int, result = str) + def formatDuration(self, seconds: int) -> str: + return Duration(seconds).getDisplayString(DurationFormat.Format.Short) + + @pyqtSlot(int, result = str) + def getTimeCompleted(self, time_remaining: int) -> str: + return formatTimeCompleted(time_remaining) + + @pyqtSlot(int, result = str) + def getDateCompleted(self, time_remaining: int) -> str: + return formatDateCompleted(time_remaining) + + ## TODO: The following methods are required by the monitor page QML, but are not actually available using cloud. + # TODO: We fake the methods here to not break the monitor page. + + @pyqtProperty(QUrl, notify = _clusterPrintersChanged) + def activeCameraUrl(self) -> "QUrl": + return QUrl() + + @pyqtSlot(QUrl) + def setActiveCameraUrl(self, camera_url: "QUrl") -> None: + pass + + @pyqtProperty(bool, notify = printJobsChanged) + def receivedPrintJobs(self) -> bool: + return bool(self._print_jobs) + + @pyqtSlot() + def openPrintJobControlPanel(self) -> None: + pass + + @pyqtSlot() + def openPrinterControlPanel(self) -> None: + pass + + @pyqtSlot(str) + def sendJobToTop(self, print_job_uuid: str) -> None: + pass + + @pyqtSlot(str) + def deleteJobFromQueue(self, print_job_uuid: str) -> None: + pass + + @pyqtSlot(str) + def forceSendJob(self, print_job_uuid: str) -> None: + pass + + @pyqtProperty("QVariantList", notify = _clusterPrintersChanged) + def connectedPrintersTypeCount(self) -> List[Dict[str, str]]: + return [] diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py new file mode 100644 index 0000000000..f9a0a59c81 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -0,0 +1,170 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import Dict, List + +from PyQt5.QtCore import QTimer + +from UM import i18nCatalog +from UM.Logger import Logger +from UM.Message import Message +from cura.API import Account +from cura.CuraApplication import CuraApplication +from cura.Settings.GlobalStack import GlobalStack +from .CloudApiClient import CloudApiClient +from .CloudOutputDevice import CloudOutputDevice +from .Models.CloudClusterResponse import CloudClusterResponse +from .Models.CloudError import CloudError +from .Utils import findChanges + + +## The cloud output device manager is responsible for using the Ultimaker Cloud APIs to manage remote clusters. +# Keeping all cloud related logic in this class instead of the UM3OutputDevicePlugin results in more readable code. +# +# API spec is available on https://api.ultimaker.com/docs/connect/spec/. +# +class CloudOutputDeviceManager: + META_CLUSTER_ID = "um_cloud_cluster_id" + + # The interval with which the remote clusters are checked + CHECK_CLUSTER_INTERVAL = 30.0 # seconds + + # The translation catalog for this device. + I18N_CATALOG = i18nCatalog("cura") + + def __init__(self) -> None: + # Persistent dict containing the remote clusters for the authenticated user. + self._remote_clusters = {} # type: Dict[str, CloudOutputDevice] + + application = CuraApplication.getInstance() + self._output_device_manager = application.getOutputDeviceManager() + + self._account = application.getCuraAPI().account # type: Account + self._api = CloudApiClient(self._account, self._onApiError) + + # Create a timer to update the remote cluster list + self._update_timer = QTimer() + self._update_timer.setInterval(int(self.CHECK_CLUSTER_INTERVAL * 1000)) + self._update_timer.setSingleShot(False) + + self._running = False + + # Called when the uses logs in or out + def _onLoginStateChanged(self, is_logged_in: bool) -> None: + Logger.log("d", "Log in state changed to %s", is_logged_in) + if is_logged_in: + if not self._update_timer.isActive(): + self._update_timer.start() + self._getRemoteClusters() + else: + if self._update_timer.isActive(): + self._update_timer.stop() + + # Notify that all clusters have disappeared + self._onGetRemoteClustersFinished([]) + + ## Gets all remote clusters from the API. + def _getRemoteClusters(self) -> None: + Logger.log("d", "Retrieving remote clusters") + self._api.getClusters(self._onGetRemoteClustersFinished) + + ## Callback for when the request for getting the clusters. is finished. + def _onGetRemoteClustersFinished(self, clusters: List[CloudClusterResponse]) -> None: + online_clusters = {c.cluster_id: c for c in clusters if c.is_online} # type: Dict[str, CloudClusterResponse] + + removed_devices, added_clusters, updates = findChanges(self._remote_clusters, online_clusters) + + Logger.log("d", "Parsed remote clusters to %s", [cluster.toDict() for cluster in online_clusters.values()]) + Logger.log("d", "Removed: %s, added: %s, updates: %s", len(removed_devices), len(added_clusters), len(updates)) + + # Remove output devices that are gone + for removed_cluster in removed_devices: + if removed_cluster.isConnected(): + removed_cluster.disconnect() + removed_cluster.close() + self._output_device_manager.removeOutputDevice(removed_cluster.key) + del self._remote_clusters[removed_cluster.key] + + # Add an output device for each new remote cluster. + # We only add when is_online as we don't want the option in the drop down if the cluster is not online. + for added_cluster in added_clusters: + device = CloudOutputDevice(self._api, added_cluster) + self._remote_clusters[added_cluster.cluster_id] = device + + for device, cluster in updates: + device.clusterData = cluster + + self._connectToActiveMachine() + + ## Callback for when the active machine was changed by the user or a new remote cluster was found. + def _connectToActiveMachine(self) -> None: + active_machine = CuraApplication.getInstance().getGlobalContainerStack() + if not active_machine: + return + + # Remove all output devices that we have registered. + # This is needed because when we switch machines we can only leave + # output devices that are meant for that machine. + for stored_cluster_id in self._remote_clusters: + self._output_device_manager.removeOutputDevice(stored_cluster_id) + + # Check if the stored cluster_id for the active machine is in our list of remote clusters. + stored_cluster_id = active_machine.getMetaDataEntry(self.META_CLUSTER_ID) + if stored_cluster_id in self._remote_clusters: + device = self._remote_clusters[stored_cluster_id] + self._connectToOutputDevice(device) + Logger.log("d", "Device connected by metadata cluster ID %s", stored_cluster_id) + else: + self._connectByNetworkKey(active_machine) + + ## Tries to match the local network key to the cloud cluster host name. + def _connectByNetworkKey(self, active_machine: GlobalStack) -> None: + # Check if the active printer has a local network connection and match this key to the remote cluster. + local_network_key = active_machine.getMetaDataEntry("um_network_key") + if not local_network_key: + return + + device = next((c for c in self._remote_clusters.values() if c.matchesNetworkKey(local_network_key)), None) + if not device: + return + + Logger.log("i", "Found cluster %s with network key %s", device, local_network_key) + active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key) + self._connectToOutputDevice(device) + + ## Connects to an output device and makes sure it is registered in the output device manager. + def _connectToOutputDevice(self, device: CloudOutputDevice) -> None: + device.connect() + self._output_device_manager.addOutputDevice(device) + + ## Handles an API error received from the cloud. + # \param errors: The errors received + def _onApiError(self, errors: List[CloudError]) -> None: + text = ". ".join(e.title for e in errors) # TODO: translate errors + message = Message( + text = text, + title = self.I18N_CATALOG.i18nc("@info:title", "Error"), + lifetime = 10 + ) + message.show() + + ## Starts running the cloud output device manager, thus periodically requesting cloud data. + def start(self): + if self._running: + return + application = CuraApplication.getInstance() + self._account.loginStateChanged.connect(self._onLoginStateChanged) + # When switching machines we check if we have to activate a remote cluster. + application.globalContainerStackChanged.connect(self._connectToActiveMachine) + self._update_timer.timeout.connect(self._getRemoteClusters) + self._onLoginStateChanged(is_logged_in = self._account.isLoggedIn) + + ## Stops running the cloud output device manager. + def stop(self): + if not self._running: + return + application = CuraApplication.getInstance() + self._account.loginStateChanged.disconnect(self._onLoginStateChanged) + # When switching machines we check if we have to activate a remote cluster. + application.globalContainerStackChanged.disconnect(self._connectToActiveMachine) + self._update_timer.timeout.disconnect(self._getRemoteClusters) + self._onLoginStateChanged(is_logged_in = False) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudProgressMessage.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudProgressMessage.py new file mode 100644 index 0000000000..d85f49c1a0 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudProgressMessage.py @@ -0,0 +1,32 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from UM import i18nCatalog +from UM.Message import Message + + +I18N_CATALOG = i18nCatalog("cura") + + +## Class responsible for showing a progress message while a mesh is being uploaded to the cloud. +class CloudProgressMessage(Message): + def __init__(self): + super().__init__( + text = I18N_CATALOG.i18nc("@info:status", "Sending data to remote cluster"), + title = I18N_CATALOG.i18nc("@info:status", "Sending data to remote cluster"), + progress = -1, + lifetime = 0, + dismissable = False, + use_inactivity_timer = False + ) + + ## Shows the progress message. + def show(self): + self.setProgress(0) + super().show() + + ## Updates the percentage of the uploaded. + # \param percentage: The percentage amount (0-100). + def update(self, percentage: int) -> None: + if not self._visible: + super().show() + self.setProgress(percentage) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/BaseCloudModel.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/BaseCloudModel.py new file mode 100644 index 0000000000..18a8cb5cba --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/BaseCloudModel.py @@ -0,0 +1,55 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from datetime import datetime, timezone +from typing import Dict, Union, TypeVar, Type, List, Any + +from ...Models import BaseModel + + +## Base class for the models used in the interface with the Ultimaker cloud APIs. +class BaseCloudModel(BaseModel): + ## Checks whether the two models are equal. + # \param other: The other model. + # \return True if they are equal, False if they are different. + def __eq__(self, other): + return type(self) == type(other) and self.toDict() == other.toDict() + + ## Checks whether the two models are different. + # \param other: The other model. + # \return True if they are different, False if they are the same. + def __ne__(self, other) -> bool: + return type(self) != type(other) or self.toDict() != other.toDict() + + ## Converts the model into a serializable dictionary + def toDict(self) -> Dict[str, Any]: + return self.__dict__ + + # Type variable used in the parse methods below, which should be a subclass of BaseModel. + T = TypeVar("T", bound=BaseModel) + + ## Parses a single model. + # \param model_class: The model class. + # \param values: The value of the model, which is usually a dictionary, but may also be already parsed. + # \return An instance of the model_class given. + @staticmethod + def parseModel(model_class: Type[T], values: Union[T, Dict[str, Any]]) -> T: + if isinstance(values, dict): + return model_class(**values) + return values + + ## Parses a list of models. + # \param model_class: The model class. + # \param values: The value of the list. Each value is usually a dictionary, but may also be already parsed. + # \return A list of instances of the model_class given. + @classmethod + def parseModels(cls, model_class: Type[T], values: List[Union[T, Dict[str, Any]]]) -> List[T]: + return [cls.parseModel(model_class, value) for value in values] + + ## Parses the given date string. + # \param date: The date to parse. + # \return The parsed date. + @staticmethod + def parseDate(date: Union[str, datetime]) -> datetime: + if isinstance(date, datetime): + return date + return datetime.strptime(date, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=timezone.utc) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterBuildPlate.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterBuildPlate.py new file mode 100644 index 0000000000..4386bbb435 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterBuildPlate.py @@ -0,0 +1,13 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from .BaseCloudModel import BaseCloudModel + + +## Class representing a cluster printer +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterBuildPlate(BaseCloudModel): + ## Create a new build plate + # \param type: The type of buildplate glass or aluminium + def __init__(self, type: str = "glass", **kwargs) -> None: + self.type = type + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintCoreConfiguration.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintCoreConfiguration.py new file mode 100644 index 0000000000..7454401d09 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintCoreConfiguration.py @@ -0,0 +1,52 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import Union, Dict, Optional, Any + +from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel +from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel +from .CloudClusterPrinterConfigurationMaterial import CloudClusterPrinterConfigurationMaterial +from .BaseCloudModel import BaseCloudModel + + +## Class representing a cloud cluster printer configuration +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterPrintCoreConfiguration(BaseCloudModel): + ## Creates a new cloud cluster printer configuration object + # \param extruder_index: The position of the extruder on the machine as list index. Numbered from left to right. + # \param material: The material of a configuration object in a cluster printer. May be in a dict or an object. + # \param nozzle_diameter: The diameter of the print core at this position in millimeters, e.g. '0.4'. + # \param print_core_id: The type of print core inserted at this position, e.g. 'AA 0.4'. + def __init__(self, extruder_index: int, + material: Union[None, Dict[str, Any], CloudClusterPrinterConfigurationMaterial], + print_core_id: Optional[str] = None, **kwargs) -> None: + self.extruder_index = extruder_index + self.material = self.parseModel(CloudClusterPrinterConfigurationMaterial, material) if material else None + self.print_core_id = print_core_id + super().__init__(**kwargs) + + ## Updates the given output model. + # \param model - The output model to update. + def updateOutputModel(self, model: ExtruderOutputModel) -> None: + if self.print_core_id is not None: + model.updateHotendID(self.print_core_id) + + if self.material: + active_material = model.activeMaterial + if active_material is None or active_material.guid != self.material.guid: + material = self.material.createOutputModel() + model.updateActiveMaterial(material) + else: + model.updateActiveMaterial(None) + + ## Creates a configuration model + def createConfigurationModel(self) -> ExtruderConfigurationModel: + model = ExtruderConfigurationModel(position = self.extruder_index) + self.updateConfigurationModel(model) + return model + + ## Creates a configuration model + def updateConfigurationModel(self, model: ExtruderConfigurationModel) -> ExtruderConfigurationModel: + model.setHotendID(self.print_core_id) + if self.material: + model.setMaterial(self.material.createOutputModel()) + return model diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConfigurationChange.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConfigurationChange.py new file mode 100644 index 0000000000..9ff4154666 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConfigurationChange.py @@ -0,0 +1,27 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import Optional + +from .BaseCloudModel import BaseCloudModel + + +## Model for the types of changes that are needed before a print job can start +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterPrintJobConfigurationChange(BaseCloudModel): + ## Creates a new print job constraint. + # \param type_of_change: The type of configuration change, one of: "material", "print_core_change" + # \param index: The hotend slot or extruder index to change + # \param target_id: Target material guid or hotend id + # \param origin_id: Original/current material guid or hotend id + # \param target_name: Target material name or hotend id + # \param origin_name: Original/current material name or hotend id + def __init__(self, type_of_change: str, target_id: str, origin_id: str, + index: Optional[int] = None, target_name: Optional[str] = None, origin_name: Optional[str] = None, + **kwargs) -> None: + self.type_of_change = type_of_change + self.index = index + self.target_id = target_id + self.origin_id = origin_id + self.target_name = target_name + self.origin_name = origin_name + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConstraint.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConstraint.py new file mode 100644 index 0000000000..8236ec06b9 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobConstraint.py @@ -0,0 +1,16 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import Optional + +from .BaseCloudModel import BaseCloudModel + + +## Class representing a cloud cluster print job constraint +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterPrintJobConstraints(BaseCloudModel): + ## Creates a new print job constraint. + # \param require_printer_name: Unique name of the printer that this job should be printed on. + # Should be one of the unique_name field values in the cluster, e.g. 'ultimakersystem-ccbdd30044ec' + def __init__(self, require_printer_name: Optional[str] = None, **kwargs) -> None: + self.require_printer_name = require_printer_name + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobImpediment.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobImpediment.py new file mode 100644 index 0000000000..12b67996c1 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobImpediment.py @@ -0,0 +1,15 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from .BaseCloudModel import BaseCloudModel + + +## Class representing the reasons that prevent this job from being printed on the associated printer +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterPrintJobImpediment(BaseCloudModel): + ## Creates a new print job constraint. + # \param translation_key: A string indicating a reason the print cannot be printed, such as 'does_not_fit_in_build_volume' + # \param severity: A number indicating the severity of the problem, with higher being more severe + def __init__(self, translation_key: str, severity: int, **kwargs) -> None: + self.translation_key = translation_key + self.severity = severity + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobStatus.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobStatus.py new file mode 100644 index 0000000000..45b7d838a5 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrintJobStatus.py @@ -0,0 +1,134 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import List, Optional, Union, Dict, Any + +from cura.PrinterOutput.ConfigurationModel import ConfigurationModel +from ...UM3PrintJobOutputModel import UM3PrintJobOutputModel +from ...ConfigurationChangeModel import ConfigurationChangeModel +from ..CloudOutputController import CloudOutputController +from .BaseCloudModel import BaseCloudModel +from .CloudClusterBuildPlate import CloudClusterBuildPlate +from .CloudClusterPrintJobConfigurationChange import CloudClusterPrintJobConfigurationChange +from .CloudClusterPrintJobImpediment import CloudClusterPrintJobImpediment +from .CloudClusterPrintCoreConfiguration import CloudClusterPrintCoreConfiguration +from .CloudClusterPrintJobConstraint import CloudClusterPrintJobConstraints + + +## Model for the status of a single print job in a cluster. +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterPrintJobStatus(BaseCloudModel): + ## Creates a new cloud print job status model. + # \param assigned_to: The name of the printer this job is assigned to while being queued. + # \param configuration: The required print core configurations of this print job. + # \param constraints: Print job constraints object. + # \param created_at: The timestamp when the job was created in Cura Connect. + # \param force: Allow this job to be printed despite of mismatching configurations. + # \param last_seen: The number of seconds since this job was checked. + # \param machine_variant: The machine type that this job should be printed on.Coincides with the machine_type field + # of the printer object. + # \param name: The name of the print job. Usually the name of the .gcode file. + # \param network_error_count: The number of errors encountered when requesting data for this print job. + # \param owner: The name of the user who added the print job to Cura Connect. + # \param printer_uuid: UUID of the printer that the job is currently printing on or assigned to. + # \param started: Whether the job has started printing or not. + # \param status: The status of the print job. + # \param time_elapsed: The remaining printing time in seconds. + # \param time_total: The total printing time in seconds. + # \param uuid: UUID of this print job. Should be used for identification purposes. + # \param deleted_at: The time when this print job was deleted. + # \param printed_on_uuid: UUID of the printer used to print this job. + # \param configuration_changes_required: List of configuration changes the printer this job is associated with + # needs to make in order to be able to print this job + # \param build_plate: The build plate (type) this job needs to be printed on. + # \param compatible_machine_families: Family names of machines suitable for this print job + # \param impediments_to_printing: A list of reasons that prevent this job from being printed on the associated + # printer + def __init__(self, created_at: str, force: bool, machine_variant: str, name: str, started: bool, status: str, + time_total: int, uuid: str, + configuration: List[Union[Dict[str, Any], CloudClusterPrintCoreConfiguration]], + constraints: List[Union[Dict[str, Any], CloudClusterPrintJobConstraints]], + last_seen: Optional[float] = None, network_error_count: Optional[int] = None, + owner: Optional[str] = None, printer_uuid: Optional[str] = None, time_elapsed: Optional[int] = None, + assigned_to: Optional[str] = None, deleted_at: Optional[str] = None, + printed_on_uuid: Optional[str] = None, + configuration_changes_required: List[ + Union[Dict[str, Any], CloudClusterPrintJobConfigurationChange]] = None, + build_plate: Union[Dict[str, Any], CloudClusterBuildPlate] = None, + compatible_machine_families: List[str] = None, + impediments_to_printing: List[Union[Dict[str, Any], CloudClusterPrintJobImpediment]] = None, + **kwargs) -> None: + self.assigned_to = assigned_to + self.configuration = self.parseModels(CloudClusterPrintCoreConfiguration, configuration) + self.constraints = self.parseModels(CloudClusterPrintJobConstraints, constraints) + self.created_at = created_at + self.force = force + self.last_seen = last_seen + self.machine_variant = machine_variant + self.name = name + self.network_error_count = network_error_count + self.owner = owner + self.printer_uuid = printer_uuid + self.started = started + self.status = status + self.time_elapsed = time_elapsed + self.time_total = time_total + self.uuid = uuid + self.deleted_at = deleted_at + self.printed_on_uuid = printed_on_uuid + + self.configuration_changes_required = self.parseModels(CloudClusterPrintJobConfigurationChange, + configuration_changes_required) \ + if configuration_changes_required else [] + self.build_plate = self.parseModel(CloudClusterBuildPlate, build_plate) if build_plate else None + self.compatible_machine_families = compatible_machine_families if compatible_machine_families else [] + self.impediments_to_printing = self.parseModels(CloudClusterPrintJobImpediment, impediments_to_printing) \ + if impediments_to_printing else [] + + super().__init__(**kwargs) + + ## Creates an UM3 print job output model based on this cloud cluster print job. + # \param printer: The output model of the printer + def createOutputModel(self, controller: CloudOutputController) -> UM3PrintJobOutputModel: + model = UM3PrintJobOutputModel(controller, self.uuid, self.name) + self.updateOutputModel(model) + + return model + + ## Creates a new configuration model + def _createConfigurationModel(self) -> ConfigurationModel: + extruders = [extruder.createConfigurationModel() for extruder in self.configuration or ()] + configuration = ConfigurationModel() + configuration.setExtruderConfigurations(extruders) + return configuration + + ## Updates an UM3 print job output model based on this cloud cluster print job. + # \param model: The model to update. + def updateOutputModel(self, model: UM3PrintJobOutputModel) -> None: + model.updateConfiguration(self._createConfigurationModel()) + model.updateTimeTotal(self.time_total) + model.updateTimeElapsed(self.time_elapsed) + model.updateOwner(self.owner) + model.updateState(self.status) + model.setCompatibleMachineFamilies(self.compatible_machine_families) + model.updateTimeTotal(self.time_total) + model.updateTimeElapsed(self.time_elapsed) + model.updateOwner(self.owner) + + status_set_by_impediment = False + for impediment in self.impediments_to_printing: + # TODO: impediment.severity is defined as int, this will not work, is there a translation? + if impediment.severity == "UNFIXABLE": + status_set_by_impediment = True + model.updateState("error") + break + + if not status_set_by_impediment: + model.updateState(self.status) + + model.updateConfigurationChanges( + [ConfigurationChangeModel( + type_of_change = change.type_of_change, + index = change.index if change.index else 0, + target_name = change.target_name if change.target_name else "", + origin_name = change.origin_name if change.origin_name else "") + for change in self.configuration_changes_required]) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfigurationMaterial.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfigurationMaterial.py new file mode 100644 index 0000000000..652cbdabda --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterConfigurationMaterial.py @@ -0,0 +1,55 @@ +from typing import Optional + +from UM.Logger import Logger +from cura.CuraApplication import CuraApplication +from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel +from .BaseCloudModel import BaseCloudModel + + +## Class representing a cloud cluster printer configuration +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterPrinterConfigurationMaterial(BaseCloudModel): + ## Creates a new material configuration model. + # \param brand: The brand of material in this print core, e.g. 'Ultimaker'. + # \param color: The color of material in this print core, e.g. 'Blue'. + # \param guid: he GUID of the material in this print core, e.g. '506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9'. + # \param material: The type of material in this print core, e.g. 'PLA'. + def __init__(self, brand: Optional[str] = None, color: Optional[str] = None, guid: Optional[str] = None, + material: Optional[str] = None, **kwargs) -> None: + self.guid = guid + self.brand = brand + self.color = color + self.material = material + super().__init__(**kwargs) + + ## Creates a material output model based on this cloud printer material. + def createOutputModel(self) -> MaterialOutputModel: + material_manager = CuraApplication.getInstance().getMaterialManager() + material_group_list = material_manager.getMaterialGroupListByGUID(self.guid) or [] + + # Sort the material groups by "is_read_only = True" first, and then the name alphabetically. + read_only_material_group_list = list(filter(lambda x: x.is_read_only, material_group_list)) + non_read_only_material_group_list = list(filter(lambda x: not x.is_read_only, material_group_list)) + material_group = None + if read_only_material_group_list: + read_only_material_group_list = sorted(read_only_material_group_list, key = lambda x: x.name) + material_group = read_only_material_group_list[0] + elif non_read_only_material_group_list: + non_read_only_material_group_list = sorted(non_read_only_material_group_list, key = lambda x: x.name) + material_group = non_read_only_material_group_list[0] + + if material_group: + container = material_group.root_material_node.getContainer() + color = container.getMetaDataEntry("color_code") + brand = container.getMetaDataEntry("brand") + material_type = container.getMetaDataEntry("material") + name = container.getName() + else: + Logger.log("w", "Unable to find material with guid {guid}. Using data as provided by cluster" + .format(guid = self.guid)) + color = self.color + brand = self.brand + material_type = self.material + name = "Empty" if self.material == "empty" else "Unknown" + + return MaterialOutputModel(guid = self.guid, type = material_type, brand = brand, color = color, name = name) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterStatus.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterStatus.py new file mode 100644 index 0000000000..a8165ff69c --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterPrinterStatus.py @@ -0,0 +1,72 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import List, Union, Dict, Optional, Any + +from cura.PrinterOutput.PrinterOutputController import PrinterOutputController +from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel +from .CloudClusterBuildPlate import CloudClusterBuildPlate +from .CloudClusterPrintCoreConfiguration import CloudClusterPrintCoreConfiguration +from .BaseCloudModel import BaseCloudModel + + +## Class representing a cluster printer +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterPrinterStatus(BaseCloudModel): + ## Creates a new cluster printer status + # \param enabled: A printer can be disabled if it should not receive new jobs. By default every printer is enabled. + # \param firmware_version: Firmware version installed on the printer. Can differ for each printer in a cluster. + # \param friendly_name: Human readable name of the printer. Can be used for identification purposes. + # \param ip_address: The IP address of the printer in the local network. + # \param machine_variant: The type of printer. Can be 'Ultimaker 3' or 'Ultimaker 3ext'. + # \param status: The status of the printer. + # \param unique_name: The unique name of the printer in the network. + # \param uuid: The unique ID of the printer, also known as GUID. + # \param configuration: The active print core configurations of this printer. + # \param reserved_by: A printer can be claimed by a specific print job. + # \param maintenance_required: Indicates if maintenance is necessary + # \param firmware_update_status: Whether the printer's firmware is up-to-date, value is one of: "up_to_date", + # "pending_update", "update_available", "update_in_progress", "update_failed", "update_impossible" + # \param latest_available_firmware: The version of the latest firmware that is available + # \param build_plate: The build plate that is on the printer + def __init__(self, enabled: bool, firmware_version: str, friendly_name: str, ip_address: str, machine_variant: str, + status: str, unique_name: str, uuid: str, + configuration: List[Union[Dict[str, Any], CloudClusterPrintCoreConfiguration]], + reserved_by: Optional[str] = None, maintenance_required: Optional[bool] = None, + firmware_update_status: Optional[str] = None, latest_available_firmware: Optional[str] = None, + build_plate: Union[Dict[str, Any], CloudClusterBuildPlate] = None, **kwargs) -> None: + + self.configuration = self.parseModels(CloudClusterPrintCoreConfiguration, configuration) + self.enabled = enabled + self.firmware_version = firmware_version + self.friendly_name = friendly_name + self.ip_address = ip_address + self.machine_variant = machine_variant + self.status = status + self.unique_name = unique_name + self.uuid = uuid + self.reserved_by = reserved_by + self.maintenance_required = maintenance_required + self.firmware_update_status = firmware_update_status + self.latest_available_firmware = latest_available_firmware + self.build_plate = self.parseModel(CloudClusterBuildPlate, build_plate) if build_plate else None + super().__init__(**kwargs) + + ## Creates a new output model. + # \param controller - The controller of the model. + def createOutputModel(self, controller: PrinterOutputController) -> PrinterOutputModel: + model = PrinterOutputModel(controller, len(self.configuration), firmware_version = self.firmware_version) + self.updateOutputModel(model) + return model + + ## Updates the given output model. + # \param model - The output model to update. + def updateOutputModel(self, model: PrinterOutputModel) -> None: + model.updateKey(self.uuid) + model.updateName(self.friendly_name) + model.updateType(self.machine_variant) + model.updateState(self.status if self.enabled else "disabled") + + for configuration, extruder_output, extruder_config in \ + zip(self.configuration, model.extruders, model.printerConfiguration.extruderConfigurations): + configuration.updateOutputModel(extruder_output) + configuration.updateConfigurationModel(extruder_config) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterResponse.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterResponse.py new file mode 100644 index 0000000000..9c0853e7c9 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterResponse.py @@ -0,0 +1,32 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import Optional + +from .BaseCloudModel import BaseCloudModel + + +## Class representing a cloud connected cluster. +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterResponse(BaseCloudModel): + ## Creates a new cluster response object. + # \param cluster_id: The secret unique ID, e.g. 'kBEeZWEifXbrXviO8mRYLx45P8k5lHVGs43XKvRniPg='. + # \param host_guid: The unique identifier of the print cluster host, e.g. 'e90ae0ac-1257-4403-91ee-a44c9b7e8050'. + # \param host_name: The name of the printer as configured during the Wi-Fi setup. Used as identifier for end users. + # \param is_online: Whether this cluster is currently connected to the cloud. + # \param status: The status of the cluster authentication (active or inactive). + # \param host_version: The firmware version of the cluster host. This is where the Stardust client is running on. + def __init__(self, cluster_id: str, host_guid: str, host_name: str, is_online: bool, status: str, + host_version: Optional[str] = None, **kwargs) -> None: + self.cluster_id = cluster_id + self.host_guid = host_guid + self.host_name = host_name + self.status = status + self.is_online = is_online + self.host_version = host_version + super().__init__(**kwargs) + + # Validates the model, raising an exception if the model is invalid. + def validate(self) -> None: + super().validate() + if not self.cluster_id: + raise ValueError("cluster_id is required on CloudCluster") diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterStatus.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterStatus.py new file mode 100644 index 0000000000..b0250c2ebb --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudClusterStatus.py @@ -0,0 +1,26 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from datetime import datetime +from typing import List, Dict, Union, Any + +from .CloudClusterPrinterStatus import CloudClusterPrinterStatus +from .CloudClusterPrintJobStatus import CloudClusterPrintJobStatus +from .BaseCloudModel import BaseCloudModel + + +# Model that represents the status of the cluster for the cloud +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudClusterStatus(BaseCloudModel): + ## Creates a new cluster status model object. + # \param printers: The latest status of each printer in the cluster. + # \param print_jobs: The latest status of each print job in the cluster. + # \param generated_time: The datetime when the object was generated on the server-side. + def __init__(self, + printers: List[Union[CloudClusterPrinterStatus, Dict[str, Any]]], + print_jobs: List[Union[CloudClusterPrintJobStatus, Dict[str, Any]]], + generated_time: Union[str, datetime], + **kwargs) -> None: + self.generated_time = self.parseDate(generated_time) + self.printers = self.parseModels(CloudClusterPrinterStatus, printers) + self.print_jobs = self.parseModels(CloudClusterPrintJobStatus, print_jobs) + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudError.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudError.py new file mode 100644 index 0000000000..b53361022e --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudError.py @@ -0,0 +1,28 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import Dict, Optional, Any + +from .BaseCloudModel import BaseCloudModel + + +## Class representing errors generated by the cloud servers, according to the JSON-API standard. +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudError(BaseCloudModel): + ## Creates a new error object. + # \param id: Unique identifier for this particular occurrence of the problem. + # \param title: A short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence + # of the problem, except for purposes of localization. + # \param code: An application-specific error code, expressed as a string value. + # \param detail: A human-readable explanation specific to this occurrence of the problem. Like title, this field's + # value can be localized. + # \param http_status: The HTTP status code applicable to this problem, converted to string. + # \param meta: Non-standard meta-information about the error, depending on the error code. + def __init__(self, id: str, code: str, title: str, http_status: str, detail: Optional[str] = None, + meta: Optional[Dict[str, Any]] = None, **kwargs) -> None: + self.id = id + self.code = code + self.http_status = http_status + self.title = title + self.detail = detail + self.meta = meta + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintJobResponse.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintJobResponse.py new file mode 100644 index 0000000000..79196ee38c --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintJobResponse.py @@ -0,0 +1,33 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import Optional + +from .BaseCloudModel import BaseCloudModel + + +# Model that represents the response received from the cloud after requesting to upload a print job +# Spec: https://api-staging.ultimaker.com/cura/v1/spec +class CloudPrintJobResponse(BaseCloudModel): + ## Creates a new print job response model. + # \param job_id: The job unique ID, e.g. 'kBEeZWEifXbrXviO8mRYLx45P8k5lHVGs43XKvRniPg='. + # \param status: The status of the print job. + # \param status_description: Contains more details about the status, e.g. the cause of failures. + # \param download_url: A signed URL to download the resulting status. Only available when the job is finished. + # \param job_name: The name of the print job. + # \param slicing_details: Model for slice information. + # \param upload_url: The one-time use URL where the toolpath must be uploaded to (only if status is uploading). + # \param content_type: The content type of the print job (e.g. text/plain or application/gzip) + # \param generated_time: The datetime when the object was generated on the server-side. + def __init__(self, job_id: str, status: str, download_url: Optional[str] = None, job_name: Optional[str] = None, + upload_url: Optional[str] = None, content_type: Optional[str] = None, + status_description: Optional[str] = None, slicing_details: Optional[dict] = None, **kwargs) -> None: + self.job_id = job_id + self.status = status + self.download_url = download_url + self.job_name = job_name + self.upload_url = upload_url + self.content_type = content_type + self.status_description = status_description + # TODO: Implement slicing details + self.slicing_details = slicing_details + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintJobUploadRequest.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintJobUploadRequest.py new file mode 100644 index 0000000000..e59c571558 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintJobUploadRequest.py @@ -0,0 +1,17 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from .BaseCloudModel import BaseCloudModel + + +# Model that represents the request to upload a print job to the cloud +# Spec: https://api-staging.ultimaker.com/cura/v1/spec +class CloudPrintJobUploadRequest(BaseCloudModel): + ## Creates a new print job upload request. + # \param job_name: The name of the print job. + # \param file_size: The size of the file in bytes. + # \param content_type: The content type of the print job (e.g. text/plain or application/gzip) + def __init__(self, job_name: str, file_size: int, content_type: str, **kwargs) -> None: + self.job_name = job_name + self.file_size = file_size + self.content_type = content_type + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintResponse.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintResponse.py new file mode 100644 index 0000000000..919d1b3c3a --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/CloudPrintResponse.py @@ -0,0 +1,23 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from datetime import datetime +from typing import Optional, Union + +from .BaseCloudModel import BaseCloudModel + + +# Model that represents the responses received from the cloud after requesting a job to be printed. +# Spec: https://api-staging.ultimaker.com/connect/v1/spec +class CloudPrintResponse(BaseCloudModel): + ## Creates a new print response object. + # \param job_id: The unique ID of a print job inside of the cluster. This ID is generated by Cura Connect. + # \param status: The status of the print request (queued or failed). + # \param generated_time: The datetime when the object was generated on the server-side. + # \param cluster_job_id: The unique ID of a print job inside of the cluster. This ID is generated by Cura Connect. + def __init__(self, job_id: str, status: str, generated_time: Union[str, datetime], + cluster_job_id: Optional[str] = None, **kwargs) -> None: + self.job_id = job_id + self.status = status + self.cluster_job_id = cluster_job_id + self.generated_time = self.parseDate(generated_time) + super().__init__(**kwargs) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Models/__init__.py b/plugins/UM3NetworkPrinting/src/Cloud/Models/__init__.py new file mode 100644 index 0000000000..f3f6970c54 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Models/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. diff --git a/plugins/UM3NetworkPrinting/src/Cloud/ToolPathUploader.py b/plugins/UM3NetworkPrinting/src/Cloud/ToolPathUploader.py new file mode 100644 index 0000000000..176b7e6ab7 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/ToolPathUploader.py @@ -0,0 +1,148 @@ +# Copyright (c) 2018 Ultimaker B.V. +# !/usr/bin/env python +# -*- coding: utf-8 -*- +from PyQt5.QtCore import QUrl +from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply, QNetworkAccessManager +from typing import Optional, Callable, Any, Tuple, cast + +from UM.Logger import Logger +from .Models.CloudPrintJobResponse import CloudPrintJobResponse + + +## Class responsible for uploading meshes to the cloud in separate requests. +class ToolPathUploader: + + # The maximum amount of times to retry if the server returns one of the RETRY_HTTP_CODES + MAX_RETRIES = 10 + + # The HTTP codes that should trigger a retry. + RETRY_HTTP_CODES = {500, 502, 503, 504} + + # The amount of bytes to send per request + BYTES_PER_REQUEST = 256 * 1024 + + ## Creates a mesh upload object. + # \param manager: The network access manager that will handle the HTTP requests. + # \param print_job: The print job response that was returned by the cloud after registering the upload. + # \param data: The mesh bytes to be uploaded. + # \param on_finished: The method to be called when done. + # \param on_progress: The method to be called when the progress changes (receives a percentage 0-100). + # \param on_error: The method to be called when an error occurs. + def __init__(self, manager: QNetworkAccessManager, print_job: CloudPrintJobResponse, data: bytes, + on_finished: Callable[[], Any], on_progress: Callable[[int], Any], on_error: Callable[[], Any] + ) -> None: + self._manager = manager + self._print_job = print_job + self._data = data + + self._on_finished = on_finished + self._on_progress = on_progress + self._on_error = on_error + + self._sent_bytes = 0 + self._retries = 0 + self._finished = False + self._reply = None # type: Optional[QNetworkReply] + + ## Returns the print job for which this object was created. + @property + def printJob(self): + return self._print_job + + ## Creates a network request to the print job upload URL, adding the needed content range header. + def _createRequest(self) -> QNetworkRequest: + request = QNetworkRequest(QUrl(self._print_job.upload_url)) + request.setHeader(QNetworkRequest.ContentTypeHeader, self._print_job.content_type) + + first_byte, last_byte = self._chunkRange() + content_range = "bytes {}-{}/{}".format(first_byte, last_byte - 1, len(self._data)) + request.setRawHeader(b"Content-Range", content_range.encode()) + Logger.log("i", "Uploading %s to %s", content_range, self._print_job.upload_url) + + return request + + ## Determines the bytes that should be uploaded next. + # \return: A tuple with the first and the last byte to upload. + def _chunkRange(self) -> Tuple[int, int]: + last_byte = min(len(self._data), self._sent_bytes + self.BYTES_PER_REQUEST) + return self._sent_bytes, last_byte + + ## Starts uploading the mesh. + def start(self) -> None: + if self._finished: + # reset state. + self._sent_bytes = 0 + self._retries = 0 + self._finished = False + self._uploadChunk() + + ## Stops uploading the mesh, marking it as finished. + def stop(self): + Logger.log("i", "Stopped uploading") + self._finished = True + + ## Uploads a chunk of the mesh to the cloud. + def _uploadChunk(self) -> None: + if self._finished: + raise ValueError("The upload is already finished") + + first_byte, last_byte = self._chunkRange() + request = self._createRequest() + + # now send the reply and subscribe to the results + self._reply = self._manager.put(request, self._data[first_byte:last_byte]) + self._reply.finished.connect(self._finishedCallback) + self._reply.uploadProgress.connect(self._progressCallback) + self._reply.error.connect(self._errorCallback) + + ## Handles an update to the upload progress + # \param bytes_sent: The amount of bytes sent in the current request. + # \param bytes_total: The amount of bytes to send in the current request. + def _progressCallback(self, bytes_sent: int, bytes_total: int) -> None: + Logger.log("i", "Progress callback %s / %s", bytes_sent, bytes_total) + if bytes_total: + total_sent = self._sent_bytes + bytes_sent + self._on_progress(int(total_sent / len(self._data) * 100)) + + ## Handles an error uploading. + def _errorCallback(self) -> None: + reply = cast(QNetworkReply, self._reply) + body = bytes(reply.readAll()).decode() + Logger.log("e", "Received error while uploading: %s", body) + self.stop() + self._on_error() + + ## Checks whether a chunk of data was uploaded successfully, starting the next chunk if needed. + def _finishedCallback(self) -> None: + reply = cast(QNetworkReply, self._reply) + Logger.log("i", "Finished callback %s %s", + reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url().toString()) + + status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) # type: int + + # check if we should retry the last chunk + if self._retries < self.MAX_RETRIES and status_code in self.RETRY_HTTP_CODES: + self._retries += 1 + Logger.log("i", "Retrying %s/%s request %s", self._retries, self.MAX_RETRIES, reply.url().toString()) + self._uploadChunk() + return + + # Http codes that are not to be retried are assumed to be errors. + if status_code > 308: + self._errorCallback() + return + + Logger.log("d", "status_code: %s, Headers: %s, body: %s", status_code, + [bytes(header).decode() for header in reply.rawHeaderList()], bytes(reply.readAll()).decode()) + self._chunkUploaded() + + ## Handles a chunk of data being uploaded, starting the next chunk if needed. + def _chunkUploaded(self) -> None: + # We got a successful response. Let's start the next chunk or report the upload is finished. + first_byte, last_byte = self._chunkRange() + self._sent_bytes += last_byte - first_byte + if self._sent_bytes >= len(self._data): + self.stop() + self._on_finished() + else: + self._uploadChunk() diff --git a/plugins/UM3NetworkPrinting/src/Cloud/Utils.py b/plugins/UM3NetworkPrinting/src/Cloud/Utils.py new file mode 100644 index 0000000000..5136e0e7db --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Cloud/Utils.py @@ -0,0 +1,54 @@ +from datetime import datetime, timedelta +from typing import TypeVar, Dict, Tuple, List + +from UM import i18nCatalog + +T = TypeVar("T") +U = TypeVar("U") + + +## Splits the given dictionaries into three lists (in a tuple): +# - `removed`: Items that were in the first argument but removed in the second one. +# - `added`: Items that were not in the first argument but were included in the second one. +# - `updated`: Items that were in both dictionaries. Both values are given in a tuple. +# \param previous: The previous items +# \param received: The received items +# \return: The tuple (removed, added, updated) as explained above. +def findChanges(previous: Dict[str, T], received: Dict[str, U]) -> Tuple[List[T], List[U], List[Tuple[T, U]]]: + previous_ids = set(previous) + received_ids = set(received) + + removed_ids = previous_ids.difference(received_ids) + new_ids = received_ids.difference(previous_ids) + updated_ids = received_ids.intersection(previous_ids) + + removed = [previous[removed_id] for removed_id in removed_ids] + added = [received[new_id] for new_id in new_ids] + updated = [(previous[updated_id], received[updated_id]) for updated_id in updated_ids] + + return removed, added, updated + + +def formatTimeCompleted(seconds_remaining: int) -> str: + completed = datetime.now() + timedelta(seconds=seconds_remaining) + return "{hour:02d}:{minute:02d}".format(hour = completed.hour, minute = completed.minute) + + +def formatDateCompleted(seconds_remaining: int) -> str: + now = datetime.now() + completed = now + timedelta(seconds=seconds_remaining) + days = (completed.date() - now.date()).days + i18n = i18nCatalog("cura") + + # If finishing date is more than 7 days out, using "Mon Dec 3 at HH:MM" format + if days >= 7: + return completed.strftime("%a %b ") + "{day}".format(day = completed.day) + # If finishing date is within the next week, use "Monday at HH:MM" format + elif days >= 2: + return completed.strftime("%a") + # If finishing tomorrow, use "tomorrow at HH:MM" format + elif days >= 1: + return i18n.i18nc("@info:status", "tomorrow") + # If finishing today, use "today at HH:MM" format + else: + return i18n.i18nc("@info:status", "today") diff --git a/plugins/UM3NetworkPrinting/src/Cloud/__init__.py b/plugins/UM3NetworkPrinting/src/Cloud/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py index 8314b0f089..b48f9380e1 100644 --- a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py @@ -1,45 +1,41 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Any, cast, Optional, Set, Tuple, Union +from typing import Any, cast, Tuple, Union, Optional, Dict, List +from time import time + +import io # To create the correct buffers for sending data to the printer. +import json +import os from UM.FileHandler.FileHandler import FileHandler -from UM.FileHandler.FileWriter import FileWriter # To choose based on the output file mode (text vs. binary). from UM.FileHandler.WriteFileJob import WriteFileJob # To call the file writer asynchronously. from UM.Logger import Logger from UM.Settings.ContainerRegistry import ContainerRegistry from UM.i18n import i18nCatalog from UM.Message import Message -from UM.Qt.Duration import Duration, DurationFormat -from UM.OutputDevice import OutputDeviceError # To show that something went wrong when writing. from UM.Scene.SceneNode import SceneNode # For typing. -from UM.Version import Version # To check against firmware versions for support. from cura.CuraApplication import CuraApplication from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel -from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState +from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState, NetworkedPrinterOutputDevice from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel +from cura.PrinterOutputDevice import ConnectionType +from .Cloud.Utils import formatTimeCompleted, formatDateCompleted from .ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController -from .SendMaterialJob import SendMaterialJob from .ConfigurationChangeModel import ConfigurationChangeModel +from .MeshFormatHandler import MeshFormatHandler +from .SendMaterialJob import SendMaterialJob from .UM3PrintJobOutputModel import UM3PrintJobOutputModel from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply from PyQt5.QtGui import QDesktopServices, QImage from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QObject -from time import time -from datetime import datetime -from typing import Optional, Dict, List - -import io # To create the correct buffers for sending data to the printer. -import json -import os - i18n_catalog = i18nCatalog("cura") @@ -49,26 +45,27 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): activeCameraUrlChanged = pyqtSignal() receivedPrintJobsChanged = pyqtSignal() - # This is a bit of a hack, as the notify can only use signals that are defined by the class that they are in. - # Inheritance doesn't seem to work. Tying them together does work, but i'm open for better suggestions. - clusterPrintersChanged = pyqtSignal() + # Notify can only use signals that are defined by the class that they are in, not inherited ones. + # Therefore we create a private signal used to trigger the printersChanged signal. + _clusterPrintersChanged = pyqtSignal() def __init__(self, device_id, address, properties, parent = None) -> None: - super().__init__(device_id = device_id, address = address, properties=properties, parent = parent) + super().__init__(device_id = device_id, address = address, properties=properties, connection_type = ConnectionType.NetworkConnection, parent = parent) self._api_prefix = "/cluster-api/v1/" self._number_of_extruders = 2 - self._dummy_lambdas = ("", {}, io.BytesIO()) #type: Tuple[str, Dict, Union[io.StringIO, io.BytesIO]] + self._dummy_lambdas = ( + "", {}, io.BytesIO() + ) # type: Tuple[Optional[str], Dict[str, Union[str, int, bool]], Union[io.StringIO, io.BytesIO]] self._print_jobs = [] # type: List[UM3PrintJobOutputModel] self._received_print_jobs = False # type: bool - self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterMonitorItem.qml") - self._control_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/ClusterControlItem.qml") + self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/MonitorStage.qml") - # See comments about this hack with the clusterPrintersChanged signal - self.printersChanged.connect(self.clusterPrintersChanged) + # Trigger the printersChanged signal when the private signal is triggered + self.printersChanged.connect(self._clusterPrintersChanged) self._accepts_commands = True # type: bool @@ -101,53 +98,19 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._active_camera_url = QUrl() # type: QUrl - def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, file_handler: Optional[FileHandler] = None, **kwargs: str) -> None: + def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, + file_handler: Optional[FileHandler] = None, **kwargs: str) -> None: self.writeStarted.emit(self) self.sendMaterialProfiles() - # Formats supported by this application (file types that we can actually write). - if file_handler: - file_formats = file_handler.getSupportedFileTypesWrite() - else: - file_formats = CuraApplication.getInstance().getMeshFileHandler().getSupportedFileTypesWrite() - - global_stack = CuraApplication.getInstance().getGlobalContainerStack() - # Create a list from the supported file formats string. - if not global_stack: - Logger.log("e", "Missing global stack!") - return - - machine_file_formats = global_stack.getMetaDataEntry("file_formats").split(";") - machine_file_formats = [file_type.strip() for file_type in machine_file_formats] - # Exception for UM3 firmware version >=4.4: UFP is now supported and should be the preferred file format. - if "application/x-ufp" not in machine_file_formats and Version(self.firmwareVersion) >= Version("4.4"): - machine_file_formats = ["application/x-ufp"] + machine_file_formats - - # Take the intersection between file_formats and machine_file_formats. - format_by_mimetype = {format["mime_type"]: format for format in file_formats} - file_formats = [format_by_mimetype[mimetype] for mimetype in machine_file_formats] #Keep them ordered according to the preference in machine_file_formats. - - if len(file_formats) == 0: - Logger.log("e", "There are no file formats available to write with!") - raise OutputDeviceError.WriteRequestFailedError(i18n_catalog.i18nc("@info:status", "There are no file formats available to write with!")) - preferred_format = file_formats[0] - - # Just take the first file format available. - if file_handler is not None: - writer = file_handler.getWriterByMimeType(cast(str, preferred_format["mime_type"])) - else: - writer = CuraApplication.getInstance().getMeshFileHandler().getWriterByMimeType(cast(str, preferred_format["mime_type"])) - - if not writer: - Logger.log("e", "Unexpected error when trying to get the FileWriter") - return + mesh_format = MeshFormatHandler(file_handler, self.firmwareVersion) # This function pauses with the yield, waiting on instructions on which printer it needs to print with. - if not writer: + if not mesh_format.is_valid: Logger.log("e", "Missing file or mesh writer!") return - self._sending_job = self._sendPrintJob(writer, preferred_format, nodes) + self._sending_job = self._sendPrintJob(mesh_format, nodes) if self._sending_job is not None: self._sending_job.send(None) # Start the generator. @@ -187,11 +150,8 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): # greenlet in order to optionally wait for selectPrinter() to select a # printer. # The greenlet yields exactly three times: First time None, - # \param writer The file writer to use to create the data. - # \param preferred_format A dictionary containing some information about - # what format to write to. This is necessary to create the correct buffer - # types and file extension and such. - def _sendPrintJob(self, writer: FileWriter, preferred_format: Dict, nodes: List[SceneNode]): + # \param mesh_format Object responsible for choosing the right kind of format to write with. + def _sendPrintJob(self, mesh_format: MeshFormatHandler, nodes: List[SceneNode]): Logger.log("i", "Sending print job to printer.") if self._sending_gcode: self._error_message = Message( @@ -205,35 +165,37 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._sending_gcode = True - target_printer = yield #Potentially wait on the user to select a target printer. + # Potentially wait on the user to select a target printer. + target_printer = yield # type: Optional[str] # Using buffering greatly reduces the write time for many lines of gcode - stream = io.BytesIO() # type: Union[io.BytesIO, io.StringIO]# Binary mode. - if preferred_format["mode"] == FileWriter.OutputMode.TextMode: - stream = io.StringIO() + stream = mesh_format.createStream() - job = WriteFileJob(writer, stream, nodes, preferred_format["mode"]) + job = WriteFileJob(mesh_format.writer, stream, nodes, mesh_format.file_mode) - self._write_job_progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0, dismissable = False, progress = -1, - title = i18n_catalog.i18nc("@info:title", "Sending Data"), use_inactivity_timer = False) + self._write_job_progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), + lifetime = 0, dismissable = False, progress = -1, + title = i18n_catalog.i18nc("@info:title", "Sending Data"), + use_inactivity_timer = False) self._write_job_progress_message.show() - self._dummy_lambdas = (target_printer, preferred_format, stream) - job.finished.connect(self._sendPrintJobWaitOnWriteJobFinished) - - job.start() - - yield True # Return that we had success! - yield # To prevent having to catch the StopIteration exception. + if mesh_format.preferred_format is not None: + self._dummy_lambdas = (target_printer, mesh_format.preferred_format, stream) + job.finished.connect(self._sendPrintJobWaitOnWriteJobFinished) + job.start() + yield True # Return that we had success! + yield # To prevent having to catch the StopIteration exception. def _sendPrintJobWaitOnWriteJobFinished(self, job: WriteFileJob) -> None: if self._write_job_progress_message: self._write_job_progress_message.hide() - self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0, dismissable = False, progress = -1, + self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), lifetime = 0, + dismissable = False, progress = -1, title = i18n_catalog.i18nc("@info:title", "Sending Data")) - self._progress_message.addAction("Abort", i18n_catalog.i18nc("@action:button", "Cancel"), icon = None, description = "") + self._progress_message.addAction("Abort", i18n_catalog.i18nc("@action:button", "Cancel"), icon = None, + description = "") self._progress_message.actionTriggered.connect(self._progressMessageActionTriggered) self._progress_message.show() parts = [] @@ -257,7 +219,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): parts.append(self._createFormPart("name=\"file\"; filename=\"%s\"" % file_name, output)) - self._latest_reply_handler = self.postFormWithParts("print_jobs/", parts, on_finished = self._onPostPrintJobFinished, on_progress = self._onUploadPrintJobProgress) + self._latest_reply_handler = self.postFormWithParts("print_jobs/", parts, + on_finished = self._onPostPrintJobFinished, + on_progress = self._onUploadPrintJobProgress) @pyqtProperty(QObject, notify = activePrinterChanged) def activePrinter(self) -> Optional[PrinterOutputModel]: @@ -291,7 +255,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): # Treat upload progress as response. Uploading can take more than 10 seconds, so if we don't, we can get # timeout responses if this happens. self._last_response_time = time() - if self._progress_message and new_progress > self._progress_message.getProgress(): + if self._progress_message is not None and new_progress > self._progress_message.getProgress(): self._progress_message.show() # Ensure that the message is visible. self._progress_message.setProgress(bytes_sent / bytes_total * 100) @@ -357,7 +321,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): def activePrintJobs(self) -> List[UM3PrintJobOutputModel]: return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None and print_job.state != "queued"] - @pyqtProperty("QVariantList", notify = clusterPrintersChanged) + @pyqtProperty("QVariantList", notify = _clusterPrintersChanged) def connectedPrintersTypeCount(self) -> List[Dict[str, str]]: printer_count = {} # type: Dict[str, int] for printer in self._printers: @@ -370,25 +334,17 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): result.append({"machine_type": machine_type, "count": str(printer_count[machine_type])}) return result - @pyqtProperty("QVariantList", notify=clusterPrintersChanged) + @pyqtProperty("QVariantList", notify=_clusterPrintersChanged) def printers(self): return self._printers - @pyqtSlot(int, result = str) - def formatDuration(self, seconds: int) -> str: - return Duration(seconds).getDisplayString(DurationFormat.Format.Short) - @pyqtSlot(int, result = str) def getTimeCompleted(self, time_remaining: int) -> str: - current_time = time() - datetime_completed = datetime.fromtimestamp(current_time + time_remaining) - return "{hour:02d}:{minute:02d}".format(hour=datetime_completed.hour, minute=datetime_completed.minute) + return formatTimeCompleted(time_remaining) @pyqtSlot(int, result = str) def getDateCompleted(self, time_remaining: int) -> str: - current_time = time() - datetime_completed = datetime.fromtimestamp(current_time + time_remaining) - return (datetime_completed.strftime("%a %b ") + "{day}".format(day=datetime_completed.day)).upper() + return formatDateCompleted(time_remaining) @pyqtSlot(str) def sendJobToTop(self, print_job_uuid: str) -> None: @@ -592,7 +548,25 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): def _createMaterialOutputModel(self, material_data: Dict[str, Any]) -> "MaterialOutputModel": material_manager = CuraApplication.getInstance().getMaterialManager() - material_group_list = material_manager.getMaterialGroupListByGUID(material_data["guid"]) + material_group_list = None + + # Avoid crashing if there is no "guid" field in the metadata + material_guid = material_data.get("guid") + if material_guid: + material_group_list = material_manager.getMaterialGroupListByGUID(material_guid) + + # This can happen if the connected machine has no material in one or more extruders (if GUID is empty), or the + # material is unknown to Cura, so we should return an "empty" or "unknown" material model. + if material_group_list is None: + material_name = i18n_catalog.i18nc("@label:material", "Empty") if len(material_data.get("guid", "")) == 0 \ + else i18n_catalog.i18nc("@label:material", "Unknown") + + return MaterialOutputModel(guid = material_data.get("guid", ""), + type = material_data.get("material", ""), + color = material_data.get("color", ""), + brand = material_data.get("brand", ""), + name = material_data.get("name", material_name) + ) # Sort the material groups by "is_read_only = True" first, and then the name alphabetically. read_only_material_group_list = list(filter(lambda x: x.is_read_only, material_group_list)) @@ -618,9 +592,10 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): color = material_data["color"] brand = material_data["brand"] material_type = material_data["material"] - name = "Empty" if material_data["material"] == "empty" else "Unknown" - return MaterialOutputModel(guid=material_data["guid"], type=material_type, - brand=brand, color=color, name=name) + name = i18n_catalog.i18nc("@label:material", "Empty") if material_data["material"] == "empty" \ + else i18n_catalog.i18nc("@label:material", "Unknown") + return MaterialOutputModel(guid = material_data["guid"], type = material_type, + brand = brand, color = color, name = name) def _updatePrinter(self, printer: PrinterOutputModel, data: Dict[str, Any]) -> None: # For some unknown reason the cluster wants UUID for everything, except for sending a job directly to a printer. diff --git a/plugins/UM3NetworkPrinting/src/ClusterUM3PrinterOutputController.py b/plugins/UM3NetworkPrinting/src/ClusterUM3PrinterOutputController.py index fcced0b883..fc6798386a 100644 --- a/plugins/UM3NetworkPrinting/src/ClusterUM3PrinterOutputController.py +++ b/plugins/UM3NetworkPrinting/src/ClusterUM3PrinterOutputController.py @@ -18,4 +18,3 @@ class ClusterUM3PrinterOutputController(PrinterOutputController): def setJobState(self, job: "PrintJobOutputModel", state: str): data = "{\"action\": \"%s\"}" % state self._output_device.put("print_jobs/%s/action" % job.key, data, on_finished=None) - diff --git a/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py b/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py index be83e04585..b688ee9d7d 100644 --- a/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py +++ b/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py @@ -3,7 +3,7 @@ import os.path import time -from typing import cast, Optional +from typing import Optional, TYPE_CHECKING from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject @@ -16,6 +16,9 @@ from cura.MachineAction import MachineAction from .UM3OutputDevicePlugin import UM3OutputDevicePlugin +if TYPE_CHECKING: + from cura.PrinterOutputDevice import PrinterOutputDevice + catalog = i18nCatalog("cura") @@ -116,22 +119,37 @@ class DiscoverUM3Action(MachineAction): # Ensure that the connection states are refreshed. self._network_plugin.reCheckConnections() - @pyqtSlot(str) - def setKey(self, key: str) -> None: - Logger.log("d", "Attempting to set the network key of the active machine to %s", key) + # Associates the currently active machine with the given printer device. The network connection information will be + # stored into the metadata of the currently active machine. + @pyqtSlot(QObject) + def associateActiveMachineWithPrinterDevice(self, printer_device: Optional["PrinterOutputDevice"]) -> None: + if not printer_device: + return + + Logger.log("d", "Attempting to set the network key of the active machine to %s", printer_device.key) + global_container_stack = CuraApplication.getInstance().getGlobalContainerStack() - if global_container_stack: - meta_data = global_container_stack.getMetaData() - if "um_network_key" in meta_data: - previous_network_key= meta_data["um_network_key"] - global_container_stack.setMetaDataEntry("um_network_key", key) - # Delete old authentication data. - Logger.log("d", "Removing old authentication id %s for device %s", global_container_stack.getMetaDataEntry("network_authentication_id", None), key) - global_container_stack.removeMetaDataEntry("network_authentication_id") - global_container_stack.removeMetaDataEntry("network_authentication_key") - CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "um_network_key", value = previous_network_key, new_value = key) - else: - global_container_stack.setMetaDataEntry("um_network_key", key) + if not global_container_stack: + return + + meta_data = global_container_stack.getMetaData() + if "um_network_key" in meta_data: + previous_network_key = meta_data["um_network_key"] + global_container_stack.setMetaDataEntry("um_network_key", printer_device.key) + # Delete old authentication data. + Logger.log("d", "Removing old authentication id %s for device %s", + global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key) + global_container_stack.removeMetaDataEntry("network_authentication_id") + global_container_stack.removeMetaDataEntry("network_authentication_key") + CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "um_network_key", value = previous_network_key, new_value = printer_device.key) + + if "connection_type" in meta_data: + previous_connection_type = meta_data["connection_type"] + global_container_stack.setMetaDataEntry("connection_type", printer_device.connectionType.value) + CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "connection_type", value = previous_connection_type, new_value = printer_device.connectionType.value) + else: + global_container_stack.setMetaDataEntry("um_network_key", printer_device.key) + global_container_stack.setMetaDataEntry("connection_type", printer_device.connectionType.value) if self._network_plugin: # Ensure that the connection states are refreshed. @@ -182,4 +200,3 @@ class DiscoverUM3Action(MachineAction): # Create extra components CuraApplication.getInstance().addAdditionalComponent("monitorButtons", self.__additional_components_view.findChild(QObject, "networkPrinterConnectButton")) - CuraApplication.getInstance().addAdditionalComponent("machinesDetailPane", self.__additional_components_view.findChild(QObject, "networkPrinterConnectionInfo")) diff --git a/plugins/UM3NetworkPrinting/src/LegacyUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/LegacyUM3OutputDevice.py index 18af22e72f..3ce0460d6b 100644 --- a/plugins/UM3NetworkPrinting/src/LegacyUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/LegacyUM3OutputDevice.py @@ -7,6 +7,7 @@ from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutp from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel +from cura.PrinterOutputDevice import ConnectionType from cura.Settings.ContainerManager import ContainerManager from cura.Settings.ExtruderManager import ExtruderManager @@ -43,7 +44,7 @@ i18n_catalog = i18nCatalog("cura") # 5. As a final step, we verify the authentication, as this forces the QT manager to setup the authenticator. class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice): def __init__(self, device_id, address: str, properties, parent = None) -> None: - super().__init__(device_id = device_id, address = address, properties = properties, parent = parent) + super().__init__(device_id = device_id, address = address, properties = properties, connection_type = ConnectionType.NetworkConnection, parent = parent) self._api_prefix = "/api/v1/" self._number_of_extruders = 2 diff --git a/plugins/UM3NetworkPrinting/src/MeshFormatHandler.py b/plugins/UM3NetworkPrinting/src/MeshFormatHandler.py new file mode 100644 index 0000000000..c3cd82a86d --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/MeshFormatHandler.py @@ -0,0 +1,115 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import io +from typing import Optional, Dict, Union, List, cast + +from UM.FileHandler.FileHandler import FileHandler +from UM.FileHandler.FileWriter import FileWriter +from UM.Logger import Logger +from UM.OutputDevice import OutputDeviceError # To show that something went wrong when writing. +from UM.Scene.SceneNode import SceneNode +from UM.Version import Version # To check against firmware versions for support. +from UM.i18n import i18nCatalog +from cura.CuraApplication import CuraApplication + + +I18N_CATALOG = i18nCatalog("cura") + + +## This class is responsible for choosing the formats used by the connected clusters. +class MeshFormatHandler: + + def __init__(self, file_handler: Optional[FileHandler], firmware_version: str) -> None: + self._file_handler = file_handler or CuraApplication.getInstance().getMeshFileHandler() + self._preferred_format = self._getPreferredFormat(firmware_version) + self._writer = self._getWriter(self.mime_type) if self._preferred_format else None + + @property + def is_valid(self) -> bool: + return bool(self._writer) + + ## Chooses the preferred file format. + # \return A dict with the file format details, with the following keys: + # {id: str, extension: str, description: str, mime_type: str, mode: int, hide_in_file_dialog: bool} + @property + def preferred_format(self) -> Optional[Dict[str, Union[str, int, bool]]]: + return self._preferred_format + + ## Gets the file writer for the given file handler and mime type. + # \return A file writer. + @property + def writer(self) -> Optional[FileWriter]: + return self._writer + + @property + def mime_type(self) -> str: + return cast(str, self._preferred_format["mime_type"]) + + ## Gets the file mode (FileWriter.OutputMode.TextMode or FileWriter.OutputMode.BinaryMode) + @property + def file_mode(self) -> int: + return cast(int, self._preferred_format["mode"]) + + ## Gets the file extension + @property + def file_extension(self) -> str: + return cast(str, self._preferred_format["extension"]) + + ## Creates the right kind of stream based on the preferred format. + def createStream(self) -> Union[io.BytesIO, io.StringIO]: + if self.file_mode == FileWriter.OutputMode.TextMode: + return io.StringIO() + else: + return io.BytesIO() + + ## Writes the mesh and returns its value. + def getBytes(self, nodes: List[SceneNode]) -> bytes: + if self.writer is None: + raise ValueError("There is no writer for the mesh format handler.") + stream = self.createStream() + self.writer.write(stream, nodes) + value = stream.getvalue() + if isinstance(value, str): + value = value.encode() + return value + + ## Chooses the preferred file format for the given file handler. + # \param firmware_version: The version of the firmware. + # \return A dict with the file format details. + def _getPreferredFormat(self, firmware_version: str) -> Dict[str, Union[str, int, bool]]: + # Formats supported by this application (file types that we can actually write). + application = CuraApplication.getInstance() + + file_formats = self._file_handler.getSupportedFileTypesWrite() + + global_stack = application.getGlobalContainerStack() + # Create a list from the supported file formats string. + if not global_stack: + Logger.log("e", "Missing global stack!") + return {} + + machine_file_formats = global_stack.getMetaDataEntry("file_formats").split(";") + machine_file_formats = [file_type.strip() for file_type in machine_file_formats] + # Exception for UM3 firmware version >=4.4: UFP is now supported and should be the preferred file format. + if "application/x-ufp" not in machine_file_formats and Version(firmware_version) >= Version("4.4"): + machine_file_formats = ["application/x-ufp"] + machine_file_formats + + # Take the intersection between file_formats and machine_file_formats. + format_by_mimetype = {f["mime_type"]: f for f in file_formats} + + # Keep them ordered according to the preference in machine_file_formats. + file_formats = [format_by_mimetype[mimetype] for mimetype in machine_file_formats] + + if len(file_formats) == 0: + Logger.log("e", "There are no file formats available to write with!") + raise OutputDeviceError.WriteRequestFailedError( + I18N_CATALOG.i18nc("@info:status", "There are no file formats available to write with!") + ) + return file_formats[0] + + ## Gets the file writer for the given file handler and mime type. + # \param mime_type: The mine type. + # \return A file writer. + def _getWriter(self, mime_type: str) -> Optional[FileWriter]: + # Just take the first file format available. + return self._file_handler.getWriterByMimeType(mime_type) diff --git a/plugins/UM3NetworkPrinting/src/Models.py b/plugins/UM3NetworkPrinting/src/Models.py new file mode 100644 index 0000000000..c5b9b16665 --- /dev/null +++ b/plugins/UM3NetworkPrinting/src/Models.py @@ -0,0 +1,46 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + + +## Base model that maps kwargs to instance attributes. +class BaseModel: + def __init__(self, **kwargs) -> None: + self.__dict__.update(kwargs) + self.validate() + + # Validates the model, raising an exception if the model is invalid. + def validate(self) -> None: + pass + + +## Class representing a material that was fetched from the cluster API. +class ClusterMaterial(BaseModel): + def __init__(self, guid: str, version: int, **kwargs) -> None: + self.guid = guid # type: str + self.version = version # type: int + super().__init__(**kwargs) + + def validate(self) -> None: + if not self.guid: + raise ValueError("guid is required on ClusterMaterial") + if not self.version: + raise ValueError("version is required on ClusterMaterial") + + +## Class representing a local material that was fetched from the container registry. +class LocalMaterial(BaseModel): + def __init__(self, GUID: str, id: str, version: int, **kwargs) -> None: + self.GUID = GUID # type: str + self.id = id # type: str + self.version = version # type: int + super().__init__(**kwargs) + + # + def validate(self) -> None: + super().validate() + if not self.GUID: + raise ValueError("guid is required on LocalMaterial") + if not self.version: + raise ValueError("version is required on LocalMaterial") + if not self.id: + raise ValueError("id is required on LocalMaterial") diff --git a/plugins/UM3NetworkPrinting/src/SendMaterialJob.py b/plugins/UM3NetworkPrinting/src/SendMaterialJob.py index 8491e79c29..8cdd647a25 100644 --- a/plugins/UM3NetworkPrinting/src/SendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/src/SendMaterialJob.py @@ -1,99 +1,197 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import json +import os +from typing import Dict, TYPE_CHECKING, Set, Optional -import json #To understand the list of materials from the printer reply. -import os #To walk over material files. -import os.path #To filter on material files. -from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest #To listen to the reply from the printer. -from typing import Any, Dict, Set, TYPE_CHECKING -import urllib.parse #For getting material IDs from their file names. +from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest -from UM.Job import Job #The interface we're implementing. +from UM.Application import Application +from UM.Job import Job from UM.Logger import Logger -from UM.MimeTypeDatabase import MimeTypeDatabase #To strip the extensions of the material profile files. -from UM.Resources import Resources -from UM.Settings.ContainerRegistry import ContainerRegistry #To find the GUIDs of materials. -from cura.CuraApplication import CuraApplication #For the resource types. +# Absolute imports don't work in plugins +from .Models import ClusterMaterial, LocalMaterial if TYPE_CHECKING: from .ClusterUM3OutputDevice import ClusterUM3OutputDevice + ## Asynchronous job to send material profiles to the printer. # # This way it won't freeze up the interface while sending those materials. class SendMaterialJob(Job): + def __init__(self, device: "ClusterUM3OutputDevice") -> None: super().__init__() - self.device = device #type: ClusterUM3OutputDevice + self.device = device # type: ClusterUM3OutputDevice + ## Send the request to the printer and register a callback def run(self) -> None: - self.device.get("materials/", on_finished = self.sendMissingMaterials) + self.device.get("materials/", on_finished = self._onGetRemoteMaterials) - def sendMissingMaterials(self, reply: QNetworkReply) -> None: - if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: #Got an error from the HTTP request. - Logger.log("e", "Couldn't request current material storage on printer. Not syncing materials.") + ## Process the materials reply from the printer. + # + # \param reply The reply from the printer, a json file. + def _onGetRemoteMaterials(self, reply: QNetworkReply) -> None: + # Got an error from the HTTP request. If we did not receive a 200 something happened. + if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: + Logger.log("e", "Error fetching materials from printer: %s", reply.errorString()) return - remote_materials_list = reply.readAll().data().decode("utf-8") + # Collect materials from the printer's reply and send the missing ones if needed. + remote_materials_by_guid = self._parseReply(reply) + if remote_materials_by_guid: + self._sendMissingMaterials(remote_materials_by_guid) + + ## Determine which materials should be updated and send them to the printer. + # + # \param remote_materials_by_guid The remote materials by GUID. + def _sendMissingMaterials(self, remote_materials_by_guid: Dict[str, ClusterMaterial]) -> None: + # Collect local materials + local_materials_by_guid = self._getLocalMaterials() + if len(local_materials_by_guid) == 0: + Logger.log("d", "There are no local materials to synchronize with the printer.") + return + + # Find out what materials are new or updated and must be sent to the printer + material_ids_to_send = self._determineMaterialsToSend(local_materials_by_guid, remote_materials_by_guid) + if len(material_ids_to_send) == 0: + Logger.log("d", "There are no remote materials to update.") + return + + # Send materials to the printer + self._sendMaterials(material_ids_to_send) + + ## From the local and remote materials, determine which ones should be synchronized. + # + # Makes a Set of id's containing only the id's of the materials that are not on the printer yet or the ones that + # are newer in Cura. + # + # \param local_materials The local materials by GUID. + # \param remote_materials The remote materials by GUID. + @staticmethod + def _determineMaterialsToSend(local_materials: Dict[str, LocalMaterial], + remote_materials: Dict[str, ClusterMaterial]) -> Set[str]: + return { + material.id + for guid, material in local_materials.items() + if guid not in remote_materials or material.version > remote_materials[guid].version + } + + ## Send the materials to the printer. + # + # The given materials will be loaded from disk en sent to to printer. + # The given id's will be matched with filenames of the locally stored materials. + # + # \param materials_to_send A set with id's of materials that must be sent. + def _sendMaterials(self, materials_to_send: Set[str]) -> None: + container_registry = Application.getInstance().getContainerRegistry() + material_manager = Application.getInstance().getMaterialManager() + material_group_dict = material_manager.getAllMaterialGroups() + + for root_material_id in material_group_dict: + if root_material_id not in materials_to_send: + # If the material does not have to be sent we skip it. + continue + + file_path = container_registry.getContainerFilePathById(root_material_id) + if not file_path: + Logger.log("w", "Cannot get file path for material container [%s]", root_material_id) + continue + + file_name = os.path.basename(file_path) + self._sendMaterialFile(file_path, file_name, root_material_id) + + ## Send a single material file to the printer. + # + # Also add the material signature file if that is available. + # + # \param file_path The path of the material file. + # \param file_name The name of the material file. + # \param material_id The ID of the material in the file. + def _sendMaterialFile(self, file_path: str, file_name: str, material_id: str) -> None: + parts = [] + + # Add the material file. + with open(file_path, "rb") as f: + parts.append(self.device.createFormPart("name=\"file\"; filename=\"{file_name}\"" + .format(file_name = file_name), f.read())) + + # Add the material signature file if needed. + signature_file_path = "{}.sig".format(file_path) + if os.path.exists(signature_file_path): + signature_file_name = os.path.basename(signature_file_path) + with open(signature_file_path, "rb") as f: + parts.append(self.device.createFormPart("name=\"signature_file\"; filename=\"{file_name}\"" + .format(file_name = signature_file_name), f.read())) + + Logger.log("d", "Syncing material {material_id} with cluster.".format(material_id = material_id)) + self.device.postFormWithParts(target = "materials/", parts = parts, on_finished = self.sendingFinished) + + ## Check a reply from an upload to the printer and log an error when the call failed + @staticmethod + def sendingFinished(reply: QNetworkReply) -> None: + if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: + Logger.log("e", "Received error code from printer when syncing material: {code}, {text}".format( + code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), + text = reply.errorString() + )) + + ## Parse the reply from the printer + # + # Parses the reply to a "/materials" request to the printer + # + # \return a dictionary of ClusterMaterial objects by GUID + # \throw KeyError Raised when on of the materials does not include a valid guid + @classmethod + def _parseReply(cls, reply: QNetworkReply) -> Optional[Dict[str, ClusterMaterial]]: try: - remote_materials_list = json.loads(remote_materials_list) + remote_materials = json.loads(reply.readAll().data().decode("utf-8")) + return {material["guid"]: ClusterMaterial(**material) for material in remote_materials} + except UnicodeDecodeError: + Logger.log("e", "Request material storage on printer: I didn't understand the printer's answer.") except json.JSONDecodeError: Logger.log("e", "Request material storage on printer: I didn't understand the printer's answer.") - return - try: - remote_materials_by_guid = {material["guid"]: material for material in remote_materials_list} #Index by GUID. - except KeyError: - Logger.log("e", "Request material storage on printer: Printer's answer was missing GUIDs.") - return + except ValueError: + Logger.log("e", "Request material storage on printer: Printer's answer had an incorrect value.") + except TypeError: + Logger.log("e", "Request material storage on printer: Printer's answer was missing a required value.") + return None - container_registry = ContainerRegistry.getInstance() - local_materials_list = filter(lambda material: ("GUID" in material and "version" in material and "id" in material), container_registry.findContainersMetadata(type = "material")) - local_materials_by_guid = {material["GUID"]: material for material in local_materials_list if material["id"] == material["base_file"]} - for material in local_materials_list: #For each GUID get the material with the highest version number. - try: - if int(material["version"]) > local_materials_by_guid[material["GUID"]]["version"]: - local_materials_by_guid[material["GUID"]] = material - except ValueError: - Logger.log("e", "Material {material_id} has invalid version number {number}.".format(material_id = material["id"], number = material["version"])) - continue + ## Retrieves a list of local materials + # + # Only the new newest version of the local materials is returned + # + # \return a dictionary of LocalMaterial objects by GUID + def _getLocalMaterials(self) -> Dict[str, LocalMaterial]: + result = {} # type: Dict[str, LocalMaterial] + material_manager = Application.getInstance().getMaterialManager() + + material_group_dict = material_manager.getAllMaterialGroups() + + # Find the latest version of all material containers in the registry. + for root_material_id, material_group in material_group_dict.items(): + material_metadata = material_group.root_material_node.getMetadata() - materials_to_send = set() #type: Set[Dict[str, Any]] - for guid, material in local_materials_by_guid.items(): - if guid not in remote_materials_by_guid: - materials_to_send.add(material["id"]) - continue try: - if int(material["version"]) > remote_materials_by_guid[guid]["version"]: - materials_to_send.add(material["id"]) - continue + # material version must be an int + material_metadata["version"] = int(material_metadata["version"]) + + # Create a new local material + local_material = LocalMaterial(**material_metadata) + local_material.id = root_material_id + + if local_material.GUID not in result or \ + local_material.GUID not in result or \ + local_material.version > result[local_material.GUID].version: + result[local_material.GUID] = local_material + except KeyError: - Logger.log("e", "Current material storage on printer was an invalid reply (missing version).") - return + Logger.logException("w", "Local material {} has missing values.".format(material_metadata["id"])) + except ValueError: + Logger.logException("w", "Local material {} has invalid values.".format(material_metadata["id"])) + except TypeError: + Logger.logException("w", "Local material {} has invalid values.".format(material_metadata["id"])) - for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.MaterialInstanceContainer): - try: - mime_type = MimeTypeDatabase.getMimeTypeForFile(file_path) - except MimeTypeDatabase.MimeTypeNotFoundError: - continue #Not the sort of file we'd like to send then. - _, file_name = os.path.split(file_path) - material_id = urllib.parse.unquote_plus(mime_type.stripExtension(file_name)) - if material_id not in materials_to_send: - continue - - parts = [] - with open(file_path, "rb") as f: - parts.append(self.device._createFormPart("name=\"file\"; filename=\"{file_name}\"".format(file_name = file_name), f.read())) - signature_file_path = file_path + ".sig" - if os.path.exists(signature_file_path): - _, signature_file_name = os.path.split(signature_file_path) - with open(signature_file_path, "rb") as f: - parts.append(self.device._createFormPart("name=\"signature_file\"; filename=\"{file_name}\"".format(file_name = signature_file_name), f.read())) - - Logger.log("d", "Syncing material {material_id} with cluster.".format(material_id = material_id)) - self.device.postFormWithParts(target = "materials/", parts = parts, on_finished = self.sendingFinished) - - def sendingFinished(self, reply: QNetworkReply): - if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: - Logger.log("e", "Received error code from printer when syncing material: {code}".format(code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute))) - Logger.log("e", reply.readAll().data().decode("utf-8")) \ No newline at end of file + return result diff --git a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py index 9c070f2de2..4a510903dd 100644 --- a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py @@ -1,23 +1,22 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. - -from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin -from UM.Logger import Logger -from UM.Application import Application -from UM.Signal import Signal, signalemitter -from UM.Version import Version - -from . import ClusterUM3OutputDevice, LegacyUM3OutputDevice - -from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager -from PyQt5.QtCore import QUrl - -from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo +import json from queue import Queue from threading import Event, Thread from time import time -import json +from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo +from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager +from PyQt5.QtCore import QUrl + +from UM.Application import Application +from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin +from UM.Logger import Logger +from UM.Signal import Signal, signalemitter +from UM.Version import Version + +from . import ClusterUM3OutputDevice, LegacyUM3OutputDevice +from .Cloud.CloudOutputDeviceManager import CloudOutputDeviceManager ## This plugin handles the connection detection & creation of output device objects for the UM3 printer. @@ -31,9 +30,13 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): def __init__(self): super().__init__() + self._zero_conf = None self._zero_conf_browser = None + # Create a cloud output device manager that abstracts all cloud connection logic away. + self._cloud_output_device_manager = CloudOutputDeviceManager() + # Because the model needs to be created in the same thread as the QMLEngine, we use a signal. self.addDeviceSignal.connect(self._onAddDevice) self.removeDeviceSignal.connect(self._onRemoveDevice) @@ -83,6 +86,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): ## Start looking for devices on network. def start(self): self.startDiscovery() + self._cloud_output_device_manager.start() def startDiscovery(self): self.stop() @@ -114,6 +118,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): if key == um_network_key: if not self._discovered_devices[key].isConnected(): Logger.log("d", "Attempting to connect with [%s]" % key) + active_machine.setMetaDataEntry("connection_type", self._discovered_devices[key].connectionType.value) self._discovered_devices[key].connect() self._discovered_devices[key].connectionStateChanged.connect(self._onDeviceConnectionStateChanged) else: @@ -139,6 +144,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): if self._zero_conf is not None: Logger.log("d", "zeroconf close...") self._zero_conf.close() + self._cloud_output_device_manager.stop() def removeManualDevice(self, key, address = None): if key in self._discovered_devices: @@ -283,6 +289,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): global_container_stack = Application.getInstance().getGlobalContainerStack() if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"): + global_container_stack.setMetaDataEntry("connection_type", device.connectionType.value) device.connect() device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged) @@ -325,13 +332,12 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): ## Handler for zeroConf detection. # Return True or False indicating if the process succeeded. - # Note that this function can take over 3 seconds to complete. Be carefull calling it from the main thread. + # Note that this function can take over 3 seconds to complete. Be careful + # calling it from the main thread. def _onServiceChanged(self, zero_conf, service_type, name, state_change): if state_change == ServiceStateChange.Added: - Logger.log("d", "Bonjour service added: %s" % name) - # First try getting info from zero-conf cache - info = ServiceInfo(service_type, name, properties={}) + info = ServiceInfo(service_type, name, properties = {}) for record in zero_conf.cache.entries_with_name(name.lower()): info.update_record(zero_conf, time(), record) @@ -342,7 +348,6 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): # Request more data if info is not complete if not info.address: - Logger.log("d", "Trying to get address of %s", name) info = zero_conf.get_service_info(service_type, name) if info: @@ -362,4 +367,4 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): Logger.log("d", "Bonjour service removed: %s" % name) self.removeDeviceSignal.emit(str(name)) - return True \ No newline at end of file + return True diff --git a/plugins/UM3NetworkPrinting/src/UM3PrintJobOutputModel.py b/plugins/UM3NetworkPrinting/src/UM3PrintJobOutputModel.py index 2ac3e6ba4f..4f44ca4af8 100644 --- a/plugins/UM3NetworkPrinting/src/UM3PrintJobOutputModel.py +++ b/plugins/UM3NetworkPrinting/src/UM3PrintJobOutputModel.py @@ -1,13 +1,12 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, pyqtSlot -from typing import Optional, TYPE_CHECKING, List -from PyQt5.QtCore import QUrl -from PyQt5.QtGui import QImage +from typing import List + +from PyQt5.QtCore import pyqtProperty, pyqtSignal from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel - +from cura.PrinterOutput.PrinterOutputController import PrinterOutputController from .ConfigurationChangeModel import ConfigurationChangeModel diff --git a/plugins/UM3NetworkPrinting/src/__init__.py b/plugins/UM3NetworkPrinting/src/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/__init__.py b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/__init__.py new file mode 100644 index 0000000000..777afc92c2 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import json +import os + + +def readFixture(fixture_name: str) -> bytes: + with open("{}/{}.json".format(os.path.dirname(__file__), fixture_name), "rb") as f: + return f.read() + +def parseFixture(fixture_name: str) -> dict: + return json.loads(readFixture(fixture_name).decode()) diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/getClusterStatusResponse.json b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/getClusterStatusResponse.json new file mode 100644 index 0000000000..4f9f47fc75 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/getClusterStatusResponse.json @@ -0,0 +1,95 @@ +{ + "data": { + "generated_time": "2018-12-10T08:23:55.110Z", + "printers": [ + { + "configuration": [ + { + "extruder_index": 0, + "material": { + "material": "empty" + }, + "print_core_id": "AA 0.4" + }, + { + "extruder_index": 1, + "material": { + "material": "empty" + }, + "print_core_id": "AA 0.4" + } + ], + "enabled": true, + "firmware_version": "5.1.2.20180807", + "friendly_name": "Master-Luke", + "ip_address": "10.183.1.140", + "machine_variant": "Ultimaker 3", + "status": "maintenance", + "unique_name": "ultimakersystem-ccbdd30044ec", + "uuid": "b3a47ea3-1eeb-4323-9626-6f9c3c888f9e" + }, + { + "configuration": [ + { + "extruder_index": 0, + "material": { + "brand": "Generic", + "color": "Generic", + "guid": "506c9f0d-e3aa-4bd4-b2d2-23e2425b1aa9", + "material": "PLA" + }, + "print_core_id": "AA 0.4" + }, + { + "extruder_index": 1, + "material": { + "brand": "Ultimaker", + "color": "Red", + "guid": "9cfe5bf1-bdc5-4beb-871a-52c70777842d", + "material": "PLA" + }, + "print_core_id": "AA 0.4" + } + ], + "enabled": true, + "firmware_version": "4.3.3.20180529", + "friendly_name": "UM-Marijn", + "ip_address": "10.183.1.166", + "machine_variant": "Ultimaker 3", + "status": "idle", + "unique_name": "ultimakersystem-ccbdd30058ab", + "uuid": "6e62c40a-4601-4b0e-9fec-c7c02c59c30a" + } + ], + "print_jobs": [ + { + "assigned_to": "6e62c40a-4601-4b0e-9fec-c7c02c59c30a", + "configuration": [ + { + "extruder_index": 0, + "material": { + "brand": "Ultimaker", + "color": "Black", + "guid": "3ee70a86-77d8-4b87-8005-e4a1bc57d2ce", + "material": "PLA" + }, + "print_core_id": "AA 0.4" + } + ], + "constraints": {}, + "created_at": "2018-12-10T08:28:04.108Z", + "force": false, + "last_seen": 500165.109491861, + "machine_variant": "Ultimaker 3", + "name": "UM3_dragon", + "network_error_count": 0, + "owner": "Daniel Testing", + "started": false, + "status": "queued", + "time_elapsed": 0, + "time_total": 14145, + "uuid": "d1c8bd52-5e9f-486a-8c25-a123cc8c7702" + } + ] + } +} diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/getClusters.json b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/getClusters.json new file mode 100644 index 0000000000..5200e3b971 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/getClusters.json @@ -0,0 +1,17 @@ +{ + "data": [{ + "cluster_id": "RIZ6cZbWA_Ua7RZVJhrdVfVpf0z-MqaSHQE4v8aRTtYq", + "host_guid": "e90ae0ac-1257-4403-91ee-a44c9b7e8050", + "host_name": "ultimakersystem-ccbdd30044ec", + "host_version": "5.0.0.20170101", + "is_online": true, + "status": "active" + }, { + "cluster_id": "NWKV6vJP_LdYsXgXqAcaNCR0YcLJwar1ugh0ikEZsZs8", + "host_guid": "e0ace90a-91ee-1257-4403-e8050a44c9b7", + "host_name": "ultimakersystem-30044ecccbdd", + "host_version": "5.1.2.20180807", + "is_online": true, + "status": "active" + }] +} diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/postJobPrintResponse.json b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/postJobPrintResponse.json new file mode 100644 index 0000000000..caedcd8732 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/postJobPrintResponse.json @@ -0,0 +1,8 @@ +{ + "data": { + "cluster_job_id": "9a59d8e9-91d3-4ff6-b4cb-9db91c4094dd", + "job_id": "ABCDefGHIjKlMNOpQrSTUvYxWZ0-1234567890abcDE=", + "status": "queued", + "generated_time": "2018-12-10T08:23:55.110Z" + } +} diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/putJobUploadResponse.json b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/putJobUploadResponse.json new file mode 100644 index 0000000000..1304f3a9f6 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/Fixtures/putJobUploadResponse.json @@ -0,0 +1,9 @@ +{ + "data": { + "content_type": "text/plain", + "job_id": "ABCDefGHIjKlMNOpQrSTUvYxWZ0-1234567890abcDE=", + "job_name": "Ultimaker Robot v3.0", + "status": "uploading", + "upload_url": "https://api.ultimaker.com/print-job-upload" + } +} diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/Models/__init__.py b/plugins/UM3NetworkPrinting/tests/Cloud/Models/__init__.py new file mode 100644 index 0000000000..f3f6970c54 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/Models/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/NetworkManagerMock.py b/plugins/UM3NetworkPrinting/tests/Cloud/NetworkManagerMock.py new file mode 100644 index 0000000000..e504509d67 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/NetworkManagerMock.py @@ -0,0 +1,105 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import json +from typing import Dict, Tuple, Union, Optional, Any +from unittest.mock import MagicMock + +from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest + +from UM.Logger import Logger +from UM.Signal import Signal + + +class FakeSignal: + def __init__(self): + self._callbacks = [] + + def connect(self, callback): + self._callbacks.append(callback) + + def disconnect(self, callback): + self._callbacks.remove(callback) + + def emit(self, *args, **kwargs): + for callback in self._callbacks: + callback(*args, **kwargs) + + +## This class can be used to mock the QNetworkManager class and test the code using it. +# After patching the QNetworkManager class, requests are prepared before they can be executed. +# Any requests not prepared beforehand will cause KeyErrors. +class NetworkManagerMock: + + # An enumeration of the supported operations and their code for the network access manager. + _OPERATIONS = { + "GET": QNetworkAccessManager.GetOperation, + "POST": QNetworkAccessManager.PostOperation, + "PUT": QNetworkAccessManager.PutOperation, + "DELETE": QNetworkAccessManager.DeleteOperation, + "HEAD": QNetworkAccessManager.HeadOperation, + } # type: Dict[str, int] + + ## Initializes the network manager mock. + def __init__(self) -> None: + # A dict with the prepared replies, using the format {(http_method, url): reply} + self.replies = {} # type: Dict[Tuple[str, str], MagicMock] + self.request_bodies = {} # type: Dict[Tuple[str, str], bytes] + + # Signals used in the network manager. + self.finished = Signal() + self.authenticationRequired = Signal() + + ## Mock implementation of the get, post, put, delete and head methods from the network manager. + # Since the methods are very simple and the same it didn't make sense to repeat the code. + # \param method: The method being called. + # \return The mocked function, if the method name is known. Defaults to the standard getattr function. + def __getattr__(self, method: str) -> Any: + ## This mock implementation will simply return the reply from the prepared ones. + # it raises a KeyError if requests are done without being prepared. + def doRequest(request: QNetworkRequest, body: Optional[bytes] = None, *_): + key = method.upper(), request.url().toString() + if body: + self.request_bodies[key] = body + return self.replies[key] + + operation = self._OPERATIONS.get(method.upper()) + if operation: + return doRequest + + # the attribute is not one of the implemented methods, default to the standard implementation. + return getattr(super(), method) + + ## Prepares a server reply for the given parameters. + # \param method: The HTTP method. + # \param url: The URL being requested. + # \param status_code: The HTTP status code for the response. + # \param response: The response body from the server (generally json-encoded). + def prepareReply(self, method: str, url: str, status_code: int, response: Union[bytes, dict]) -> None: + reply_mock = MagicMock() + reply_mock.url().toString.return_value = url + reply_mock.operation.return_value = self._OPERATIONS[method] + reply_mock.attribute.return_value = status_code + reply_mock.finished = FakeSignal() + reply_mock.isFinished.return_value = False + reply_mock.readAll.return_value = response if isinstance(response, bytes) else json.dumps(response).encode() + self.replies[method, url] = reply_mock + Logger.log("i", "Prepared mock {}-response to {} {}", status_code, method, url) + + ## Gets the request that was sent to the network manager for the given method and URL. + # \param method: The HTTP method. + # \param url: The URL. + def getRequestBody(self, method: str, url: str) -> Optional[bytes]: + return self.request_bodies.get((method.upper(), url)) + + ## Emits the signal that the reply is ready to all prepared replies. + def flushReplies(self) -> None: + for key, reply in self.replies.items(): + Logger.log("i", "Flushing reply to {} {}", *key) + reply.isFinished.return_value = True + reply.finished.emit() + self.finished.emit(reply) + self.reset() + + ## Deletes all prepared replies + def reset(self) -> None: + self.replies.clear() diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudApiClient.py b/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudApiClient.py new file mode 100644 index 0000000000..0be1d82141 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudApiClient.py @@ -0,0 +1,117 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from typing import List +from unittest import TestCase +from unittest.mock import patch, MagicMock + +from cura.UltimakerCloudAuthentication import CuraCloudAPIRoot +from ...src.Cloud.CloudApiClient import CloudApiClient +from ...src.Cloud.Models.CloudClusterResponse import CloudClusterResponse +from ...src.Cloud.Models.CloudClusterStatus import CloudClusterStatus +from ...src.Cloud.Models.CloudPrintJobResponse import CloudPrintJobResponse +from ...src.Cloud.Models.CloudPrintJobUploadRequest import CloudPrintJobUploadRequest +from ...src.Cloud.Models.CloudError import CloudError +from .Fixtures import readFixture, parseFixture +from .NetworkManagerMock import NetworkManagerMock + + +class TestCloudApiClient(TestCase): + maxDiff = None + + def _errorHandler(self, errors: List[CloudError]): + raise Exception("Received unexpected error: {}".format(errors)) + + def setUp(self): + super().setUp() + self.account = MagicMock() + self.account.isLoggedIn.return_value = True + + self.network = NetworkManagerMock() + with patch("plugins.UM3NetworkPrinting.src.Cloud.CloudApiClient.QNetworkAccessManager", return_value = self.network): + self.api = CloudApiClient(self.account, self._errorHandler) + + def test_getClusters(self): + result = [] + + response = readFixture("getClusters") + data = parseFixture("getClusters")["data"] + + self.network.prepareReply("GET", CuraCloudAPIRoot + "/connect/v1/clusters", 200, response) + # The callback is a function that adds the result of the call to getClusters to the result list + self.api.getClusters(lambda clusters: result.extend(clusters)) + + self.network.flushReplies() + + self.assertEqual([CloudClusterResponse(**data[0]), CloudClusterResponse(**data[1])], result) + + def test_getClusterStatus(self): + result = [] + + response = readFixture("getClusterStatusResponse") + data = parseFixture("getClusterStatusResponse")["data"] + + url = CuraCloudAPIRoot + "/connect/v1/clusters/R0YcLJwar1ugh0ikEZsZs8NWKV6vJP_LdYsXgXqAcaNC/status" + self.network.prepareReply("GET", url, 200, response) + self.api.getClusterStatus("R0YcLJwar1ugh0ikEZsZs8NWKV6vJP_LdYsXgXqAcaNC", lambda s: result.append(s)) + + self.network.flushReplies() + + self.assertEqual([CloudClusterStatus(**data)], result) + + def test_requestUpload(self): + + results = [] + + response = readFixture("putJobUploadResponse") + + self.network.prepareReply("PUT", CuraCloudAPIRoot + "/cura/v1/jobs/upload", 200, response) + request = CloudPrintJobUploadRequest(job_name = "job name", file_size = 143234, content_type = "text/plain") + self.api.requestUpload(request, lambda r: results.append(r)) + self.network.flushReplies() + + self.assertEqual(["text/plain"], [r.content_type for r in results]) + self.assertEqual(["uploading"], [r.status for r in results]) + + def test_uploadToolPath(self): + + results = [] + progress = MagicMock() + + data = parseFixture("putJobUploadResponse")["data"] + upload_response = CloudPrintJobResponse(**data) + + # Network client doesn't look into the reply + self.network.prepareReply("PUT", upload_response.upload_url, 200, b'{}') + + mesh = ("1234" * 100000).encode() + self.api.uploadToolPath(upload_response, mesh, lambda: results.append("sent"), progress.advance, progress.error) + + for _ in range(10): + self.network.flushReplies() + self.network.prepareReply("PUT", upload_response.upload_url, 200, b'{}') + + self.assertEqual(["sent"], results) + + def test_requestPrint(self): + + results = [] + + response = readFixture("postJobPrintResponse") + + cluster_id = "NWKV6vJP_LdYsXgXqAcaNCR0YcLJwar1ugh0ikEZsZs8" + cluster_job_id = "9a59d8e9-91d3-4ff6-b4cb-9db91c4094dd" + job_id = "ABCDefGHIjKlMNOpQrSTUvYxWZ0-1234567890abcDE=" + + self.network.prepareReply("POST", + CuraCloudAPIRoot + "/connect/v1/clusters/{}/print/{}" + .format(cluster_id, job_id), + 200, response) + + self.api.requestPrint(cluster_id, job_id, lambda r: results.append(r)) + + self.network.flushReplies() + + self.assertEqual([job_id], [r.job_id for r in results]) + self.assertEqual([cluster_job_id], [r.cluster_job_id for r in results]) + self.assertEqual(["queued"], [r.status for r in results]) diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudOutputDevice.py b/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudOutputDevice.py new file mode 100644 index 0000000000..191b92bdd5 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudOutputDevice.py @@ -0,0 +1,145 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import json +from unittest import TestCase +from unittest.mock import patch, MagicMock + +from UM.Scene.SceneNode import SceneNode +from cura.UltimakerCloudAuthentication import CuraCloudAPIRoot +from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel +from ...src.Cloud.CloudApiClient import CloudApiClient +from ...src.Cloud.CloudOutputDevice import CloudOutputDevice +from ...src.Cloud.Models.CloudClusterResponse import CloudClusterResponse +from .Fixtures import readFixture, parseFixture +from .NetworkManagerMock import NetworkManagerMock + + +class TestCloudOutputDevice(TestCase): + maxDiff = None + + CLUSTER_ID = "RIZ6cZbWA_Ua7RZVJhrdVfVpf0z-MqaSHQE4v8aRTtYq" + JOB_ID = "ABCDefGHIjKlMNOpQrSTUvYxWZ0-1234567890abcDE=" + HOST_NAME = "ultimakersystem-ccbdd30044ec" + HOST_GUID = "e90ae0ac-1257-4403-91ee-a44c9b7e8050" + + STATUS_URL = "{}/connect/v1/clusters/{}/status".format(CuraCloudAPIRoot, CLUSTER_ID) + PRINT_URL = "{}/connect/v1/clusters/{}/print/{}".format(CuraCloudAPIRoot, CLUSTER_ID, JOB_ID) + REQUEST_UPLOAD_URL = "{}/cura/v1/jobs/upload".format(CuraCloudAPIRoot) + + def setUp(self): + super().setUp() + self.app = MagicMock() + + self.patches = [patch("UM.Qt.QtApplication.QtApplication.getInstance", return_value=self.app), + patch("UM.Application.Application.getInstance", return_value=self.app)] + for patched_method in self.patches: + patched_method.start() + + self.cluster = CloudClusterResponse(self.CLUSTER_ID, self.HOST_GUID, self.HOST_NAME, is_online=True, + status="active") + + self.network = NetworkManagerMock() + self.account = MagicMock(isLoggedIn=True, accessToken="TestAccessToken") + self.onError = MagicMock() + with patch("plugins.UM3NetworkPrinting.src.Cloud.CloudApiClient.QNetworkAccessManager", + return_value = self.network): + self._api = CloudApiClient(self.account, self.onError) + + self.device = CloudOutputDevice(self._api, self.cluster) + self.cluster_status = parseFixture("getClusterStatusResponse") + self.network.prepareReply("GET", self.STATUS_URL, 200, readFixture("getClusterStatusResponse")) + + def tearDown(self): + super().tearDown() + self.network.flushReplies() + for patched_method in self.patches: + patched_method.stop() + + def test_status(self): + self.device._update() + self.network.flushReplies() + + self.assertEqual([PrinterOutputModel, PrinterOutputModel], [type(printer) for printer in self.device.printers]) + + controller_fields = { + "_output_device": self.device, + "can_abort": False, + "can_control_manually": False, + "can_pause": False, + "can_pre_heat_bed": False, + "can_pre_heat_hotends": False, + "can_send_raw_gcode": False, + "can_update_firmware": False, + } + + self.assertEqual({printer["uuid"] for printer in self.cluster_status["data"]["printers"]}, + {printer.key for printer in self.device.printers}) + self.assertEqual([controller_fields, controller_fields], + [printer.getController().__dict__ for printer in self.device.printers]) + + self.assertEqual(["UM3PrintJobOutputModel"], [type(printer).__name__ for printer in self.device.printJobs]) + self.assertEqual({job["uuid"] for job in self.cluster_status["data"]["print_jobs"]}, + {job.key for job in self.device.printJobs}) + self.assertEqual({job["owner"] for job in self.cluster_status["data"]["print_jobs"]}, + {job.owner for job in self.device.printJobs}) + self.assertEqual({job["name"] for job in self.cluster_status["data"]["print_jobs"]}, + {job.name for job in self.device.printJobs}) + + def test_remove_print_job(self): + self.device._update() + self.network.flushReplies() + self.assertEqual(1, len(self.device.printJobs)) + + self.cluster_status["data"]["print_jobs"].clear() + self.network.prepareReply("GET", self.STATUS_URL, 200, self.cluster_status) + + self.device._last_request_time = None + self.device._update() + self.network.flushReplies() + self.assertEqual([], self.device.printJobs) + + def test_remove_printers(self): + self.device._update() + self.network.flushReplies() + self.assertEqual(2, len(self.device.printers)) + + self.cluster_status["data"]["printers"].clear() + self.network.prepareReply("GET", self.STATUS_URL, 200, self.cluster_status) + + self.device._last_request_time = None + self.device._update() + self.network.flushReplies() + self.assertEqual([], self.device.printers) + + def test_print_to_cloud(self): + active_machine_mock = self.app.getGlobalContainerStack.return_value + active_machine_mock.getMetaDataEntry.side_effect = {"file_formats": "application/gzip"}.get + + request_upload_response = parseFixture("putJobUploadResponse") + request_print_response = parseFixture("postJobPrintResponse") + self.network.prepareReply("PUT", self.REQUEST_UPLOAD_URL, 201, request_upload_response) + self.network.prepareReply("PUT", request_upload_response["data"]["upload_url"], 201, b"{}") + self.network.prepareReply("POST", self.PRINT_URL, 200, request_print_response) + + file_handler = MagicMock() + file_handler.getSupportedFileTypesWrite.return_value = [{ + "extension": "gcode.gz", + "mime_type": "application/gzip", + "mode": 2, + }] + file_handler.getWriterByMimeType.return_value.write.side_effect = \ + lambda stream, nodes: stream.write(str(nodes).encode()) + + scene_nodes = [SceneNode()] + expected_mesh = str(scene_nodes).encode() + self.device.requestWrite(scene_nodes, file_handler=file_handler, file_name="FileName") + + self.network.flushReplies() + self.assertEqual( + {"data": {"content_type": "application/gzip", "file_size": len(expected_mesh), "job_name": "FileName"}}, + json.loads(self.network.getRequestBody("PUT", self.REQUEST_UPLOAD_URL).decode()) + ) + self.assertEqual(expected_mesh, + self.network.getRequestBody("PUT", request_upload_response["data"]["upload_url"])) + + self.assertIsNone(self.network.getRequestBody("POST", self.PRINT_URL)) diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudOutputDeviceManager.py new file mode 100644 index 0000000000..c5006f35a1 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/TestCloudOutputDeviceManager.py @@ -0,0 +1,124 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +from unittest import TestCase +from unittest.mock import patch, MagicMock + +from UM.OutputDevice.OutputDeviceManager import OutputDeviceManager +from cura.UltimakerCloudAuthentication import CuraCloudAPIRoot +from ...src.Cloud.CloudOutputDeviceManager import CloudOutputDeviceManager +from .Fixtures import parseFixture, readFixture +from .NetworkManagerMock import NetworkManagerMock, FakeSignal + + +class TestCloudOutputDeviceManager(TestCase): + maxDiff = None + + URL = CuraCloudAPIRoot + "/connect/v1/clusters" + + def setUp(self): + super().setUp() + self.app = MagicMock() + self.device_manager = OutputDeviceManager() + self.app.getOutputDeviceManager.return_value = self.device_manager + + self.patches = [patch("UM.Qt.QtApplication.QtApplication.getInstance", return_value=self.app), + patch("UM.Application.Application.getInstance", return_value=self.app)] + for patched_method in self.patches: + patched_method.start() + + self.network = NetworkManagerMock() + self.timer = MagicMock(timeout = FakeSignal()) + with patch("plugins.UM3NetworkPrinting.src.Cloud.CloudApiClient.QNetworkAccessManager", + return_value = self.network), \ + patch("plugins.UM3NetworkPrinting.src.Cloud.CloudOutputDeviceManager.QTimer", + return_value = self.timer): + self.manager = CloudOutputDeviceManager() + self.clusters_response = parseFixture("getClusters") + self.network.prepareReply("GET", self.URL, 200, readFixture("getClusters")) + + def tearDown(self): + try: + self._beforeTearDown() + + self.network.flushReplies() + self.manager.stop() + for patched_method in self.patches: + patched_method.stop() + finally: + super().tearDown() + + ## Before tear down method we check whether the state of the output device manager is what we expect based on the + # mocked API response. + def _beforeTearDown(self): + # let the network send replies + self.network.flushReplies() + # get the created devices + devices = self.device_manager.getOutputDevices() + # TODO: Check active device + + response_clusters = self.clusters_response.get("data", []) + manager_clusters = sorted([device.clusterData.toDict() for device in self.manager._remote_clusters.values()], + key=lambda cluster: cluster['cluster_id'], reverse=True) + self.assertEqual(response_clusters, manager_clusters) + + ## Runs the initial request to retrieve the clusters. + def _loadData(self): + self.manager.start() + self.network.flushReplies() + + def test_device_is_created(self): + # just create the cluster, it is checked at tearDown + self._loadData() + + def test_device_is_updated(self): + self._loadData() + + # update the cluster from member variable, which is checked at tearDown + self.clusters_response["data"][0]["host_name"] = "New host name" + self.network.prepareReply("GET", self.URL, 200, self.clusters_response) + + self.manager._update_timer.timeout.emit() + + def test_device_is_removed(self): + self._loadData() + + # delete the cluster from member variable, which is checked at tearDown + del self.clusters_response["data"][1] + self.network.prepareReply("GET", self.URL, 200, self.clusters_response) + + self.manager._update_timer.timeout.emit() + + def test_device_connects_by_cluster_id(self): + active_machine_mock = self.app.getGlobalContainerStack.return_value + cluster1, cluster2 = self.clusters_response["data"] + cluster_id = cluster1["cluster_id"] + active_machine_mock.getMetaDataEntry.side_effect = {"um_cloud_cluster_id": cluster_id}.get + + self._loadData() + + self.assertTrue(self.device_manager.getOutputDevice(cluster1["cluster_id"]).isConnected()) + self.assertIsNone(self.device_manager.getOutputDevice(cluster2["cluster_id"])) + self.assertEquals([], active_machine_mock.setMetaDataEntry.mock_calls) + + def test_device_connects_by_network_key(self): + active_machine_mock = self.app.getGlobalContainerStack.return_value + + cluster1, cluster2 = self.clusters_response["data"] + network_key = cluster2["host_name"] + ".ultimaker.local" + active_machine_mock.getMetaDataEntry.side_effect = {"um_network_key": network_key}.get + + self._loadData() + + self.assertIsNone(self.device_manager.getOutputDevice(cluster1["cluster_id"])) + self.assertTrue(self.device_manager.getOutputDevice(cluster2["cluster_id"]).isConnected()) + + active_machine_mock.setMetaDataEntry.assert_called_with("um_cloud_cluster_id", cluster2["cluster_id"]) + + @patch("plugins.UM3NetworkPrinting.src.Cloud.CloudOutputDeviceManager.Message") + def test_api_error(self, message_mock): + self.clusters_response = { + "errors": [{"id": "notFound", "title": "Not found!", "http_status": "404", "code": "notFound"}] + } + self.network.prepareReply("GET", self.URL, 200, self.clusters_response) + self._loadData() + message_mock.return_value.show.assert_called_once_with() diff --git a/plugins/UM3NetworkPrinting/tests/Cloud/__init__.py b/plugins/UM3NetworkPrinting/tests/Cloud/__init__.py new file mode 100644 index 0000000000..f3f6970c54 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/Cloud/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. diff --git a/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py new file mode 100644 index 0000000000..6eac892af6 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py @@ -0,0 +1,245 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. +import copy +import io +import json +from unittest import TestCase, mock +from unittest.mock import patch, call, MagicMock + +from PyQt5.QtCore import QByteArray + +from UM.Application import Application + +from cura.Machines.MaterialGroup import MaterialGroup +from cura.Machines.MaterialNode import MaterialNode + +from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob + +_FILES_MAP = {"generic_pla_white": "/materials/generic_pla_white.xml.fdm_material", + "generic_pla_black": "/materials/generic_pla_black.xml.fdm_material", + } + + +@patch("builtins.open", lambda _, __: io.StringIO("")) +class TestSendMaterialJob(TestCase): + # version 1 + _LOCAL_MATERIAL_WHITE = {"type": "material", "status": "unknown", "id": "generic_pla_white", + "base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA", + "brand": "Generic", "material": "PLA", "color_name": "White", + "GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "1", "color_code": "#ffffff", + "description": "Test PLA White", "adhesion_info": "Use glue.", "approximate_diameter": "3", + "properties": {"density": "1.00", "diameter": "2.85", "weight": "750"}, + "definition": "fdmprinter", "compatible": True} + + # version 2 + _LOCAL_MATERIAL_WHITE_NEWER = {"type": "material", "status": "unknown", "id": "generic_pla_white", + "base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA", + "brand": "Generic", "material": "PLA", "color_name": "White", + "GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "2", + "color_code": "#ffffff", + "description": "Test PLA White", "adhesion_info": "Use glue.", + "approximate_diameter": "3", + "properties": {"density": "1.00", "diameter": "2.85", "weight": "750"}, + "definition": "fdmprinter", "compatible": True} + + # invalid version: "one" + _LOCAL_MATERIAL_WHITE_INVALID_VERSION = {"type": "material", "status": "unknown", "id": "generic_pla_white", + "base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA", + "brand": "Generic", "material": "PLA", "color_name": "White", + "GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "one", + "color_code": "#ffffff", + "description": "Test PLA White", "adhesion_info": "Use glue.", + "approximate_diameter": "3", + "properties": {"density": "1.00", "diameter": "2.85", "weight": "750"}, + "definition": "fdmprinter", "compatible": True} + + _LOCAL_MATERIAL_WHITE_ALL_RESULT = {"generic_pla_white": MaterialGroup("generic_pla_white", + MaterialNode(_LOCAL_MATERIAL_WHITE))} + + _LOCAL_MATERIAL_WHITE_NEWER_ALL_RESULT = {"generic_pla_white": MaterialGroup("generic_pla_white", + MaterialNode(_LOCAL_MATERIAL_WHITE_NEWER))} + + _LOCAL_MATERIAL_WHITE_INVALID_VERSION_ALL_RESULT = {"generic_pla_white": MaterialGroup("generic_pla_white", + MaterialNode(_LOCAL_MATERIAL_WHITE_INVALID_VERSION))} + + _LOCAL_MATERIAL_BLACK = {"type": "material", "status": "unknown", "id": "generic_pla_black", + "base_file": "generic_pla_black", "setting_version": "5", "name": "Yellow CPE", + "brand": "Ultimaker", "material": "CPE", "color_name": "Black", + "GUID": "5fbb362a-41f9-4818-bb43-15ea6df34aa4", "version": "1", "color_code": "#000000", + "description": "Test PLA Black", "adhesion_info": "Use glue.", "approximate_diameter": "3", + "properties": {"density": "1.01", "diameter": "2.85", "weight": "750"}, + "definition": "fdmprinter", "compatible": True} + + _LOCAL_MATERIAL_BLACK_ALL_RESULT = {"generic_pla_black": MaterialGroup("generic_pla_black", + MaterialNode(_LOCAL_MATERIAL_BLACK))} + + _REMOTE_MATERIAL_WHITE = { + "guid": "badb0ee7-87c8-4f3f-9398-938587b67dce", + "material": "PLA", + "brand": "Generic", + "version": 1, + "color": "White", + "density": 1.00 + } + + _REMOTE_MATERIAL_BLACK = { + "guid": "5fbb362a-41f9-4818-bb43-15ea6df34aa4", + "material": "PLA", + "brand": "Generic", + "version": 2, + "color": "Black", + "density": 1.00 + } + + def test_run(self): + device_mock = MagicMock() + job = SendMaterialJob(device_mock) + job.run() + + # We expect the materials endpoint to be called when the job runs. + device_mock.get.assert_called_with("materials/", on_finished = job._onGetRemoteMaterials) + + def test__onGetRemoteMaterials_withFailedRequest(self): + reply_mock = MagicMock() + device_mock = MagicMock() + reply_mock.attribute.return_value = 404 + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + # We expect the device not to be called for any follow up. + self.assertEqual(0, device_mock.createFormPart.call_count) + + def test__onGetRemoteMaterials_withWrongEncoding(self): + reply_mock = MagicMock() + device_mock = MagicMock() + reply_mock.attribute.return_value = 200 + reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("cp500")) + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + # Given that the parsing fails we do no expect the device to be called for any follow up. + self.assertEqual(0, device_mock.createFormPart.call_count) + + def test__onGetRemoteMaterials_withBadJsonAnswer(self): + reply_mock = MagicMock() + device_mock = MagicMock() + reply_mock.attribute.return_value = 200 + reply_mock.readAll.return_value = QByteArray(b"Six sick hicks nick six slick bricks with picks and sticks.") + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + # Given that the parsing fails we do no expect the device to be called for any follow up. + self.assertEqual(0, device_mock.createFormPart.call_count) + + def test__onGetRemoteMaterials_withMissingGuidInRemoteMaterial(self): + reply_mock = MagicMock() + device_mock = MagicMock() + reply_mock.attribute.return_value = 200 + remote_material_without_guid = self._REMOTE_MATERIAL_WHITE.copy() + del remote_material_without_guid["guid"] + reply_mock.readAll.return_value = QByteArray(json.dumps([remote_material_without_guid]).encode("ascii")) + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + # Given that parsing fails we do not expect the device to be called for any follow up. + self.assertEqual(0, device_mock.createFormPart.call_count) + + @patch("cura.Machines.MaterialManager.MaterialManager") + @patch("cura.Settings.CuraContainerRegistry") + @patch("UM.Application") + def test__onGetRemoteMaterials_withInvalidVersionInLocalMaterial(self, application_mock, container_registry_mock, + material_manager_mock): + reply_mock = MagicMock() + device_mock = MagicMock() + application_mock.getContainerRegistry.return_value = container_registry_mock + application_mock.getMaterialManager.return_value = material_manager_mock + + reply_mock.attribute.return_value = 200 + reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii")) + + material_manager_mock.getAllMaterialGroups.return_value = self._LOCAL_MATERIAL_WHITE_INVALID_VERSION_ALL_RESULT.copy() + + with mock.patch.object(Application, "getInstance", new = lambda: application_mock): + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + self.assertEqual(0, device_mock.createFormPart.call_count) + + @patch("UM.Application.Application.getInstance") + def test__onGetRemoteMaterials_withNoUpdate(self, application_mock): + reply_mock = MagicMock() + device_mock = MagicMock() + container_registry_mock = application_mock.getContainerRegistry.return_value + material_manager_mock = application_mock.getMaterialManager.return_value + + device_mock.createFormPart.return_value = "_xXx_" + + material_manager_mock.getAllMaterialGroups.return_value = self._LOCAL_MATERIAL_WHITE_ALL_RESULT.copy() + + reply_mock.attribute.return_value = 200 + reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii")) + + with mock.patch.object(Application, "getInstance", new = lambda: application_mock): + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + self.assertEqual(0, device_mock.createFormPart.call_count) + self.assertEqual(0, device_mock.postFormWithParts.call_count) + + @patch("UM.Application.Application.getInstance") + def test__onGetRemoteMaterials_withUpdatedMaterial(self, get_instance_mock): + reply_mock = MagicMock() + device_mock = MagicMock() + application_mock = get_instance_mock.return_value + container_registry_mock = application_mock.getContainerRegistry.return_value + material_manager_mock = application_mock.getMaterialManager.return_value + + container_registry_mock.getContainerFilePathById = lambda x: _FILES_MAP.get(x) + + device_mock.createFormPart.return_value = "_xXx_" + + material_manager_mock.getAllMaterialGroups.return_value = self._LOCAL_MATERIAL_WHITE_NEWER_ALL_RESULT.copy() + + reply_mock.attribute.return_value = 200 + reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii")) + + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + self.assertEqual(1, device_mock.createFormPart.call_count) + self.assertEqual(1, device_mock.postFormWithParts.call_count) + self.assertEquals( + [call.createFormPart("name=\"file\"; filename=\"generic_pla_white.xml.fdm_material\"", ""), + call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)], + device_mock.method_calls) + + @patch("UM.Application.Application.getInstance") + def test__onGetRemoteMaterials_withNewMaterial(self, application_mock): + reply_mock = MagicMock() + device_mock = MagicMock() + container_registry_mock = application_mock.getContainerRegistry.return_value + material_manager_mock = application_mock.getMaterialManager.return_value + + container_registry_mock.getContainerFilePathById = lambda x: _FILES_MAP.get(x) + + device_mock.createFormPart.return_value = "_xXx_" + + all_results = self._LOCAL_MATERIAL_WHITE_ALL_RESULT.copy() + for key, value in self._LOCAL_MATERIAL_BLACK_ALL_RESULT.items(): + all_results[key] = value + material_manager_mock.getAllMaterialGroups.return_value = all_results + + reply_mock.attribute.return_value = 200 + reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_BLACK]).encode("ascii")) + + with mock.patch.object(Application, "getInstance", new = lambda: application_mock): + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) + + self.assertEqual(1, device_mock.createFormPart.call_count) + self.assertEqual(1, device_mock.postFormWithParts.call_count) + self.assertEquals( + [call.createFormPart("name=\"file\"; filename=\"generic_pla_white.xml.fdm_material\"", ""), + call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)], + device_mock.method_calls) diff --git a/plugins/UM3NetworkPrinting/tests/__init__.py b/plugins/UM3NetworkPrinting/tests/__init__.py new file mode 100644 index 0000000000..f3f6970c54 --- /dev/null +++ b/plugins/UM3NetworkPrinting/tests/__init__.py @@ -0,0 +1,2 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. diff --git a/plugins/USBPrinting/AutoDetectBaudJob.py b/plugins/USBPrinting/AutoDetectBaudJob.py index 8b37c4b29d..2fa0af1795 100644 --- a/plugins/USBPrinting/AutoDetectBaudJob.py +++ b/plugins/USBPrinting/AutoDetectBaudJob.py @@ -4,6 +4,7 @@ from UM.Job import Job from UM.Logger import Logger +from .avr_isp import ispBase from .avr_isp.stk500v2 import Stk500v2 from time import time, sleep @@ -14,12 +15,12 @@ from serial import Serial, SerialException # It tries a pre-set list of baud rates. All these baud rates are validated by requesting the temperature a few times # and checking if the results make sense. If getResult() is not None, it was able to find a correct baud rate. class AutoDetectBaudJob(Job): - def __init__(self, serial_port): + def __init__(self, serial_port: int) -> None: super().__init__() self._serial_port = serial_port - self._all_baud_rates = [115200, 250000, 230400, 57600, 38400, 19200, 9600] + self._all_baud_rates = [115200, 250000, 500000, 230400, 57600, 38400, 19200, 9600] - def run(self): + def run(self) -> None: Logger.log("d", "Auto detect baud rate started.") wait_response_timeouts = [3, 15, 30] wait_bootloader_times = [1.5, 5, 15] @@ -32,7 +33,7 @@ class AutoDetectBaudJob(Job): try: programmer.connect(self._serial_port) serial = programmer.leaveISP() - except: + except ispBase.IspError: programmer.close() for retry in range(tries): @@ -58,7 +59,7 @@ class AutoDetectBaudJob(Job): # We already have a serial connection, just change the baud rate. try: serial.baudrate = baud_rate - except: + except ValueError: continue sleep(wait_bootloader) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number successful_responses = 0 @@ -81,5 +82,5 @@ class AutoDetectBaudJob(Job): return serial.write(b"M105\n") - sleep(15) # Give the printer some time to init and try again. + sleep(15) # Give the printer some time to init and try again. self.setResult(None) # Unable to detect the correct baudrate. diff --git a/plugins/USBPrinting/MonitorItem.qml b/plugins/USBPrinting/MonitorItem.qml new file mode 100644 index 0000000000..c86353f814 --- /dev/null +++ b/plugins/USBPrinting/MonitorItem.qml @@ -0,0 +1,48 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.10 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura +Component +{ + Item + { + Rectangle + { + color: UM.Theme.getColor("main_background") + + anchors.right: parent.right + width: parent.width * 0.3 + anchors.top: parent.top + anchors.bottom: parent.bottom + + Cura.PrintMonitor + { + anchors.fill: parent + } + + Rectangle + { + id: footerSeparator + width: parent.width + height: UM.Theme.getSize("wide_lining").height + color: UM.Theme.getColor("wide_lining") + anchors.bottom: monitorButton.top + anchors.bottomMargin: UM.Theme.getSize("thick_margin").height + } + + // MonitorButton is actually the bottom footer panel. + Cura.MonitorButton + { + id: monitorButton + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + } + } + } +} \ No newline at end of file diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index e1c39ff8fa..89903b06f4 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -1,12 +1,13 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import os from UM.Logger import Logger from UM.i18n import i18nCatalog from UM.Qt.Duration import DurationFormat from cura.CuraApplication import CuraApplication -from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState +from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState, ConnectionType from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.GenericOutputController import GenericOutputController @@ -28,7 +29,7 @@ catalog = i18nCatalog("cura") class USBPrinterOutputDevice(PrinterOutputDevice): def __init__(self, serial_port: str, baud_rate: Optional[int] = None) -> None: - super().__init__(serial_port) + super().__init__(serial_port, connection_type = ConnectionType.UsbConnection) self.setName(catalog.i18nc("@item:inmenu", "USB printing")) self.setShortDescription(catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print via USB")) self.setDescription(catalog.i18nc("@info:tooltip", "Print via USB")) @@ -48,7 +49,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._baud_rate = baud_rate - self._all_baud_rates = [115200, 250000, 230400, 57600, 38400, 19200, 9600] + self._all_baud_rates = [115200, 250000, 500000, 230400, 57600, 38400, 19200, 9600] # Instead of using a timer, we really need the update to be as a thread, as reading from serial can block. self._update_thread = Thread(target = self._update, daemon = True) @@ -64,7 +65,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._accepts_commands = True self._paused = False - self._printer_busy = False # when printer is preheating and waiting (M190/M109), or when waiting for action on the printer + self._printer_busy = False # When printer is preheating and waiting (M190/M109), or when waiting for action on the printer self.setConnectionText(catalog.i18nc("@info:status", "Connected via USB")) @@ -77,6 +78,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._firmware_name_requested = False self._firmware_updater = AvrFirmwareUpdater(self) + self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "MonitorItem.qml") + CuraApplication.getInstance().getOnExitCallbackManager().addCallback(self._checkActivePrintingUponAppExit) # This is a callback function that checks if there is any printing in progress via USB when the application tries @@ -176,7 +179,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): return CuraApplication.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerStackChanged) self._onGlobalContainerStackChanged() - self.setConnectionState(ConnectionState.connected) + self.setConnectionState(ConnectionState.Connected) self._update_thread.start() def _onGlobalContainerStackChanged(self): @@ -205,7 +208,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._sendCommand(command) def _sendCommand(self, command: Union[str, bytes]): - if self._serial is None or self._connection_state != ConnectionState.connected: + if self._serial is None or self._connection_state != ConnectionState.Connected: return new_command = cast(bytes, command) if type(command) is bytes else cast(str, command).encode() # type: bytes @@ -219,7 +222,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._command_received.set() def _update(self): - while self._connection_state == ConnectionState.connected and self._serial is not None: + while self._connection_state == ConnectionState.Connected and self._serial is not None: try: line = self._serial.readline() except: diff --git a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py index bd207d9d96..d4c0d1828e 100644 --- a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py +++ b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py @@ -66,7 +66,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin): return changed_device = self._usb_output_devices[serial_port] - if changed_device.connectionState == ConnectionState.connected: + if changed_device.connectionState == ConnectionState.Connected: self.getOutputDeviceManager().addOutputDevice(changed_device) else: self.getOutputDeviceManager().removeOutputDevice(serial_port) diff --git a/plugins/USBPrinting/plugin.json b/plugins/USBPrinting/plugin.json index 3484c8a48a..45971d858b 100644 --- a/plugins/USBPrinting/plugin.json +++ b/plugins/USBPrinting/plugin.json @@ -1,8 +1,8 @@ { "name": "USB printing", "author": "Ultimaker B.V.", - "version": "1.0.0", - "api": 5, + "version": "1.0.2", + "api": "6.0", "description": "Accepts G-Code and sends them to a printer. Plugin can also update firmware.", "i18n-catalog": "cura" } diff --git a/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml b/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml index 4a1d42e248..2a01cfaa40 100644 --- a/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml +++ b/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml @@ -19,7 +19,7 @@ Cura.MachineAction property bool heatupBedStarted: false property bool printerConnected: Cura.MachineManager.printerConnected - UM.I18nCatalog { id: catalog; name:"cura"} + UM.I18nCatalog { id: catalog; name: "cura"} Label { id: pageTitle diff --git a/plugins/UltimakerMachineActions/plugin.json b/plugins/UltimakerMachineActions/plugin.json index b60c7df88e..3e3e0af9b0 100644 --- a/plugins/UltimakerMachineActions/plugin.json +++ b/plugins/UltimakerMachineActions/plugin.json @@ -1,8 +1,8 @@ { "name": "Ultimaker machine actions", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc.).", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/UserAgreement/UserAgreement.qml b/plugins/UserAgreement/UserAgreement.qml index 4ee03f4ad5..2e5893fc41 100644 --- a/plugins/UserAgreement/UserAgreement.qml +++ b/plugins/UserAgreement/UserAgreement.qml @@ -36,7 +36,7 @@ UM.Dialog width: parent.width anchors.bottomMargin: UM.Theme.getSize("default_margin").height - UM.I18nCatalog { id: catalog; name:"cura" } + UM.I18nCatalog { id: catalog; name: "cura" } Button { diff --git a/plugins/UserAgreement/plugin.json b/plugins/UserAgreement/plugin.json index 50a2aa0441..b172d1f9a2 100644 --- a/plugins/UserAgreement/plugin.json +++ b/plugins/UserAgreement/plugin.json @@ -1,8 +1,8 @@ { "name": "UserAgreement", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Ask the user once if he/she agrees with our license.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/MachineInstance.py b/plugins/VersionUpgrade/VersionUpgrade21to22/MachineInstance.py index 37b6989add..ff5c33517d 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/MachineInstance.py +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/MachineInstance.py @@ -1,14 +1,16 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -import UM.VersionUpgrade #To indicate that a file is of incorrect format. -import UM.VersionUpgradeManager #To schedule more files to be upgraded. -from UM.Resources import Resources #To get the config storage path. - import configparser #To read config files. import io #To write config files to strings as if they were files. import os.path #To get the path to write new user profiles to. +from typing import Dict, List, Optional, Set, Tuple import urllib #To serialise the user container file name properly. +import urllib.parse + +import UM.VersionUpgrade #To indicate that a file is of incorrect format. +import UM.VersionUpgradeManager #To schedule more files to be upgraded. +from UM.Resources import Resources #To get the config storage path. ## Creates a new machine instance instance by parsing a serialised machine # instance in version 1 of the file format. @@ -18,7 +20,7 @@ import urllib #To serialise the user container file name properly. # extension. # \return A machine instance instance, or None if the file format is # incorrect. -def importFrom(serialised, filename): +def importFrom(serialised: str, filename: str) -> Optional["MachineInstance"]: try: return MachineInstance(serialised, filename) except (configparser.Error, UM.VersionUpgrade.FormatException, UM.VersionUpgrade.InvalidVersionException): @@ -32,7 +34,7 @@ class MachineInstance: # \param serialised A string with the contents of a machine instance file, # without extension. # \param filename The supposed file name of this machine instance. - def __init__(self, serialised, filename): + def __init__(self, serialised: str, filename: str) -> None: self._filename = filename config = configparser.ConfigParser(interpolation = None) @@ -53,11 +55,11 @@ class MachineInstance: self._type_name = config.get("general", "type") self._variant_name = config.get("general", "variant", fallback = "empty_variant") self._name = config.get("general", "name", fallback = "") - self._key = config.get("general", "key", fallback = None) + self._key = config.get("general", "key", fallback = "") self._active_profile_name = config.get("general", "active_profile", fallback = "empty_quality") self._active_material_name = config.get("general", "material", fallback = "empty_material") - self._machine_setting_overrides = {} + self._machine_setting_overrides = {} # type: Dict[str, str] for key, value in config["machine_settings"].items(): self._machine_setting_overrides[key] = value @@ -67,7 +69,7 @@ class MachineInstance: # # \return A tuple containing the new filename and a serialised form of # this machine instance, serialised in version 2 of the file format. - def export(self): + def export(self) -> Tuple[List[str], List[str]]: config = configparser.ConfigParser(interpolation = None) # Build a config file in the form of version 2. config.add_section("general") @@ -108,7 +110,7 @@ class MachineInstance: version_upgrade_manager = UM.VersionUpgradeManager.VersionUpgradeManager.getInstance() user_version_to_paths_dict = version_upgrade_manager.getStoragePaths("user") - paths_set = set() + paths_set = set() # type: Set[str] for paths in user_version_to_paths_dict.values(): paths_set |= paths diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/Preferences.py b/plugins/VersionUpgrade/VersionUpgrade21to22/Preferences.py index 842499da86..953837b863 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/Preferences.py +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/Preferences.py @@ -1,8 +1,9 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import configparser #To read config files. import io #To output config files to string. +from typing import List, Optional, Tuple import UM.VersionUpgrade #To indicate that a file is of the wrong format. @@ -14,7 +15,7 @@ import UM.VersionUpgrade #To indicate that a file is of the wrong format. # extension. # \return A representation of those preferences, or None if the file format is # incorrect. -def importFrom(serialised, filename): +def importFrom(serialised: str, filename: str) -> Optional["Preferences"]: try: return Preferences(serialised, filename) except (configparser.Error, UM.VersionUpgrade.FormatException, UM.VersionUpgrade.InvalidVersionException): @@ -28,7 +29,7 @@ class Preferences: # \param serialised A serialised version 2 preferences file. # \param filename The supposed filename of the preferences file, without # extension. - def __init__(self, serialised, filename): + def __init__(self, serialised: str, filename: str) -> None: self._filename = filename self._config = configparser.ConfigParser(interpolation = None) @@ -50,7 +51,7 @@ class Preferences: # # \return A tuple containing the new filename and a serialised version of # a preferences file in version 3. - def export(self): + def export(self) -> Tuple[List[str], List[str]]: #Reset the cura/categories_expanded property since it works differently now. if self._config.has_section("cura") and self._config.has_option("cura", "categories_expanded"): self._config.remove_option("cura", "categories_expanded") @@ -58,11 +59,11 @@ class Preferences: #Translate the setting names in the visible settings. if self._config.has_section("machines") and self._config.has_option("machines", "setting_visibility"): visible_settings = self._config.get("machines", "setting_visibility") - visible_settings = visible_settings.split(",") + visible_settings_list = visible_settings.split(",") import VersionUpgrade21to22 #Import here to prevent a circular dependency. - visible_settings = [VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateSettingName(setting_name) - for setting_name in visible_settings] - visible_settings = ",".join(visible_settings) + visible_settings_list = [VersionUpgrade21to22.VersionUpgrade21to22.VersionUpgrade21to22.translateSettingName(setting_name) + for setting_name in visible_settings_list] + visible_settings = ",".join(visible_settings_list) self._config.set("machines", "setting_visibility", value = visible_settings) #Translate the active_instance key. diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/Profile.py b/plugins/VersionUpgrade/VersionUpgrade21to22/Profile.py index 161edcb67c..af9635d384 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/Profile.py +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/Profile.py @@ -1,10 +1,9 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import configparser #To read config files. import io #To write config files to strings as if they were files. -from typing import Dict -from typing import List +from typing import Dict, List, Optional, Tuple import UM.VersionUpgrade from UM.Logger import Logger @@ -15,7 +14,7 @@ from UM.Logger import Logger # \param serialised The serialised form of a profile in version 1. # \param filename The supposed filename of the profile, without extension. # \return A profile instance, or None if the file format is incorrect. -def importFrom(serialised, filename): +def importFrom(serialised: str, filename: str) -> Optional["Profile"]: try: return Profile(serialised, filename) except (configparser.Error, UM.VersionUpgrade.FormatException, UM.VersionUpgrade.InvalidVersionException): @@ -77,11 +76,11 @@ class Profile: # # \return A tuple containing the new filename and a serialised form of # this profile, serialised in version 2 of the file format. - def export(self): + def export(self) -> Optional[Tuple[List[str], List[str]]]: import VersionUpgrade21to22 # Import here to prevent circular dependencies. if self._name == "Current settings": - return None, None #Can't upgrade these, because the new current profile needs to specify the definition ID and the old file only had the machine instance, not the definition. + return None #Can't upgrade these, because the new current profile needs to specify the definition ID and the old file only had the machine instance, not the definition. config = configparser.ConfigParser(interpolation = None) diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py b/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py index d8036491bf..536385b19d 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/VersionUpgrade21to22.py @@ -1,7 +1,8 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import configparser #To get version numbers from config files. +from typing import Dict, Iterable, List, Optional, Set, Tuple from UM.VersionUpgrade import VersionUpgrade # Superclass of the plugin. @@ -30,7 +31,7 @@ _machines_with_machine_quality = { "materials": { "generic_abs", "generic_cpe", "generic_pla", "generic_pva", "generic_cpe_plus", "generic_nylon", "generic_pc", "generic_tpu" }, "variants": { "0.25 mm", "0.4 mm", "0.6 mm", "0.8 mm" } } -} +} # type: Dict[str, Dict[str, Set[str]]] ## How to translate material names from the old version to the new. _material_translations = { @@ -41,7 +42,7 @@ _material_translations = { "Nylon": "generic_nylon", "PC": "generic_pc", "TPU": "generic_tpu", -} +} # type: Dict[str, str] ## How to translate material names for in the profile names. _material_translations_profiles = { @@ -52,17 +53,17 @@ _material_translations_profiles = { "Nylon": "nylon", "PC": "pc", "TPU": "tpu", -} +} # type: Dict[str, str] ## How to translate printer names from the old version to the new. _printer_translations = { "ultimaker2plus": "ultimaker2_plus" -} +} # type: Dict[str, str] _printer_translations_profiles = { "ultimaker2plus": "um2p", #Does NOT get included in PLA profiles! "ultimaker2_extended_plus": "um2ep" #Has no profiles for CPE+, Nylon, PC and TPU! -} +} # type: Dict[str, str] ## How to translate profile names from the old version to the new. # @@ -116,13 +117,13 @@ _profile_translations = { "tpu_0.25_high": "um2p_tpu_0.25_high", "tpu_0.4_normal": "um2p_tpu_0.4_normal", "tpu_0.6_fast": "um2p_tpu_0.6_fast" -} +} # type: Dict[str, str] ## Settings that are no longer in the new version. _removed_settings = { "fill_perimeter_gaps", "support_area_smoothing" -} +} # type: Set[str] ## How to translate setting names from the old version to the new. _setting_name_translations = { @@ -142,7 +143,7 @@ _setting_name_translations = { "support_roof_line_distance": "support_interface_line_distance", "support_roof_line_width": "support_interface_line_width", "support_roof_pattern": "support_interface_pattern" -} +} # type: Dict[str, str] ## Custom profiles become quality_changes. This dictates which quality to base # the quality_changes profile on. @@ -190,7 +191,7 @@ _quality_fallbacks = { #No TPU. } } -} +} # type: Dict[str, Dict[str, Dict[str, str]]] ## How to translate variants of specific machines from the old version to the # new. @@ -207,7 +208,7 @@ _variant_translations = { "0.6 mm": "ultimaker2_extended_plus_0.6", "0.8 mm": "ultimaker2_extended_plus_0.8" } -} +} # type: Dict[str, Dict[str, str]] ## How to translate variant names for in the profile names. _variant_translations_profiles = { @@ -215,7 +216,7 @@ _variant_translations_profiles = { "0.4 mm": "0.4", "0.6 mm": "0.6", "0.8 mm": "0.8" -} +} # type: Dict[str, str] ## Cura 2.2's material profiles use a different naming scheme for variants. # @@ -233,7 +234,7 @@ _variant_translations_materials = { "0.6 mm": "ultimaker2_plus_0.6_mm", "0.8 mm": "ultimaker2_plus_0.8_mm" } -} +} # type: Dict[str, Dict[str, str]] ## Converts configuration from Cura 2.1's file formats to Cura 2.2's. # @@ -245,12 +246,12 @@ class VersionUpgrade21to22(VersionUpgrade): # number is stored in general/version, so get the data from that key. # # \param serialised The contents of a config file. - # \return \type{int} The version number of that config file. - def getCfgVersion(self, serialised): + # \return The version number of that config file. + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version ## Gets the fallback quality to use for a specific machine-variant-material @@ -263,7 +264,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \param variant The variant ID of the user's configuration in 2.2. # \param material The material ID of the user's configuration in 2.2. @staticmethod - def getQualityFallback(machine, variant, material): + def getQualityFallback(machine: str, variant: str, material: str) -> str: if machine not in _quality_fallbacks: return "normal" if variant not in _quality_fallbacks[machine]: @@ -277,14 +278,14 @@ class VersionUpgrade21to22(VersionUpgrade): # This is required to test if profiles should be converted to a quality # profile or a quality-changes profile. @staticmethod - def builtInProfiles(): + def builtInProfiles() -> Iterable[str]: return _profile_translations.keys() ## Gets a set of the machines which now have per-material quality profiles. # # \return A set of machine identifiers. @staticmethod - def machinesWithMachineQuality(): + def machinesWithMachineQuality() -> Dict[str, Dict[str, Set[str]]]: return _machines_with_machine_quality ## Converts machine instances from format version 1 to version 2. @@ -295,10 +296,10 @@ class VersionUpgrade21to22(VersionUpgrade): # \return A tuple containing the new filename and the serialised machine # instance in version 2, or None if the input was not of the correct # format. - def upgradeMachineInstance(self, serialised, filename): + def upgradeMachineInstance(self, serialised: str, filename: str) -> Optional[Tuple[List[str], List[str]]]: machine_instance = MachineInstance.importFrom(serialised, filename) if not machine_instance: #Invalid file format. - return filename, None + return None return machine_instance.export() ## Converts preferences from format version 2 to version 3. @@ -309,10 +310,10 @@ class VersionUpgrade21to22(VersionUpgrade): # \return A tuple containing the new filename and the serialised # preferences in version 3, or None if the input was not of the correct # format. - def upgradePreferences(self, serialised, filename): + def upgradePreferences(self, serialised: str, filename: str) -> Optional[Tuple[List[str], List[str]]]: preferences = Preferences.importFrom(serialised, filename) if not preferences: #Invalid file format. - return filename, None + return None return preferences.export() ## Converts profiles from format version 1 to version 2. @@ -322,10 +323,10 @@ class VersionUpgrade21to22(VersionUpgrade): # extension. # \return A tuple containing the new filename and the serialised profile # in version 2, or None if the input was not of the correct format. - def upgradeProfile(self, serialised, filename): + def upgradeProfile(self, serialised: str, filename: str) -> Optional[Tuple[List[str], List[str]]]: profile = Profile.importFrom(serialised, filename) if not profile: # Invalid file format. - return filename, None + return None return profile.export() ## Translates a material name for the change from Cura 2.1 to 2.2. @@ -333,7 +334,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \param material A material name in Cura 2.1. # \return The name of the corresponding material in Cura 2.2. @staticmethod - def translateMaterial(material): + def translateMaterial(material: str) -> str: if material in _material_translations: return _material_translations[material] return material @@ -345,7 +346,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \return The name of the corresponding material in the quality profiles # in Cura 2.2. @staticmethod - def translateMaterialForProfiles(material): + def translateMaterialForProfiles(material: str) -> str: if material in _material_translations_profiles: return _material_translations_profiles[material] return material @@ -356,7 +357,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \param printer A printer name in Cura 2.1. # \return The name of the corresponding printer in Cura 2.2. @staticmethod - def translatePrinter(printer): + def translatePrinter(printer: str) -> str: if printer in _printer_translations: return _printer_translations[printer] return printer #Doesn't need to be translated. @@ -367,7 +368,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \param printer A printer name in 2.1. # \return The name of the corresponding printer in Cura 2.2. @staticmethod - def translatePrinterForProfile(printer): + def translatePrinterForProfile(printer: str) -> str: if printer in _printer_translations_profiles: return _printer_translations_profiles[printer] return printer @@ -378,7 +379,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \param profile A profile name in the old version. # \return The corresponding profile name in the new version. @staticmethod - def translateProfile(profile): + def translateProfile(profile: str) -> str: if profile in _profile_translations: return _profile_translations[profile] return profile #Doesn't need to be translated. @@ -392,7 +393,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \param settings A dictionary of settings (as key-value pairs) to update. # \return The same dictionary. @staticmethod - def translateSettings(settings): + def translateSettings(settings: Dict[str, str]) -> Dict[str, str]: new_settings = {} for key, value in settings.items(): if key in _removed_settings: @@ -414,7 +415,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \param setting The name of a setting in Cura 2.1. # \return The name of the corresponding setting in Cura 2.2. @staticmethod - def translateSettingName(setting): + def translateSettingName(setting: str) -> str: if setting in _setting_name_translations: return _setting_name_translations[setting] return setting #Doesn't need to be translated. @@ -426,7 +427,7 @@ class VersionUpgrade21to22(VersionUpgrade): # 2.2's naming. # \return The name of the corresponding variant in Cura 2.2. @staticmethod - def translateVariant(variant, machine): + def translateVariant(variant: str, machine: str) -> str: if machine in _variant_translations and variant in _variant_translations[machine]: return _variant_translations[machine][variant] return variant @@ -440,7 +441,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \return The name of the corresponding variant for in material profiles # in Cura 2.2. @staticmethod - def translateVariantForMaterials(variant, machine): + def translateVariantForMaterials(variant: str, machine: str) -> str: if machine in _variant_translations_materials and variant in _variant_translations_materials[machine]: return _variant_translations_materials[machine][variant] return variant @@ -452,7 +453,7 @@ class VersionUpgrade21to22(VersionUpgrade): # \return The name of the corresponding variant for in quality profiles in # Cura 2.2. @staticmethod - def translateVariantForProfiles(variant): + def translateVariantForProfiles(variant: str) -> str: if variant in _variant_translations_profiles: return _variant_translations_profiles[variant] return variant \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/__init__.py b/plugins/VersionUpgrade/VersionUpgrade21to22/__init__.py index 609781ebfe..67530b9d45 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/__init__.py @@ -1,11 +1,16 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade21to22 +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade21to22.VersionUpgrade21to22() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -33,5 +38,5 @@ def getMetaData(): } } -def register(app): +def register(app: "Application") -> Dict[str, Any]: return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json b/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json index 463fcdc941..cad94c2eb5 100644 --- a/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json @@ -1,8 +1,8 @@ { "name": "Version Upgrade 2.1 to 2.2", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 2.1 to Cura 2.2.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py b/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py index a56f1f807b..ded892d137 100644 --- a/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py +++ b/plugins/VersionUpgrade/VersionUpgrade22to24/VersionUpgrade.py @@ -1,18 +1,18 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import configparser #To get version numbers from config files. +import io import os import os.path -import io +from typing import Dict, List, Optional, Tuple from UM.Resources import Resources from UM.VersionUpgrade import VersionUpgrade # Superclass of the plugin. import UM.VersionUpgrade class VersionUpgrade22to24(VersionUpgrade): - - def upgradeMachineInstance(self, serialised, filename): + def upgradeMachineInstance(self, serialised: str, filename: str) -> Optional[Tuple[List[str], List[str]]]: # All of this is needed to upgrade custom variant machines from old Cura to 2.4 where # `definition_changes` instance container has been introduced. Variant files which # look like the the handy work of the old machine settings plugin are converted directly @@ -22,11 +22,11 @@ class VersionUpgrade22to24(VersionUpgrade): config.read_string(serialised) # Read the input string as config file. if config.get("metadata", "type") == "definition_changes": # This is not a container stack, don't upgrade it here - return + return None config.set("general", "version", "3") - container_list = [] + container_list = [] # type: List[str] if config.has_section("containers"): for index, container_id in config.items("containers"): container_list.append(container_id) @@ -37,14 +37,14 @@ class VersionUpgrade22to24(VersionUpgrade): user_variants = self.__getUserVariants() name_path_dict = {} for variant in user_variants: - name_path_dict[variant.get("name")] = variant.get("path") + name_path_dict[variant["name"]] = variant["path"] user_variant_names = set(container_list).intersection(name_path_dict.keys()) if len(user_variant_names): # One of the user defined variants appears in the list of containers in the stack. for variant_name in user_variant_names: # really there should just be one variant to convert. - config_name = self.__convertVariant(name_path_dict.get(variant_name)) + config_name = self.__convertVariant(name_path_dict[variant_name]) # Change the name of variant and insert empty_variant into the stack. new_container_list = [] @@ -64,14 +64,14 @@ class VersionUpgrade22to24(VersionUpgrade): config.remove_option("general", "containers") - for index in range(len(container_list)): - config.set("containers", str(index), container_list[index]) + for idx in range(len(container_list)): + config.set("containers", str(idx), container_list[idx]) output = io.StringIO() config.write(output) return [filename], [output.getvalue()] - def __convertVariant(self, variant_path): + def __convertVariant(self, variant_path: str) -> str: # Copy the variant to the machine_instances/*_settings.inst.cfg variant_config = configparser.ConfigParser(interpolation = None) with open(variant_path, "r", encoding = "utf-8") as fhandle: @@ -99,7 +99,7 @@ class VersionUpgrade22to24(VersionUpgrade): return config_name - def __getUserVariants(self): + def __getUserVariants(self) -> List[Dict[str, str]]: resource_path = Resources.getDataStoragePath() variants_dir = os.path.join(resource_path, "variants") @@ -113,7 +113,7 @@ class VersionUpgrade22to24(VersionUpgrade): result.append( { "path": entry.path, "name": config.get("general", "name") } ) return result - def upgradeExtruderTrain(self, serialised, filename): + def upgradeExtruderTrain(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: config = configparser.ConfigParser(interpolation = None) config.read_string(serialised) # Read the input string as config file. config.set("general", "version", "3") # Just bump the version number. That is all we need for now. @@ -122,7 +122,7 @@ class VersionUpgrade22to24(VersionUpgrade): config.write(output) return [filename], [output.getvalue()] - def upgradePreferences(self, serialised, filename): + def upgradePreferences(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: config = configparser.ConfigParser(interpolation = None) config.read_string(serialised) @@ -142,7 +142,7 @@ class VersionUpgrade22to24(VersionUpgrade): config.write(output) return [filename], [output.getvalue()] - def upgradeQuality(self, serialised, filename): + def upgradeQuality(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: config = configparser.ConfigParser(interpolation = None) config.read_string(serialised) # Read the input string as config file. config.set("metadata", "type", "quality_changes") # Update metadata/type to quality_changes @@ -152,9 +152,9 @@ class VersionUpgrade22to24(VersionUpgrade): config.write(output) return [filename], [output.getvalue()] - def getCfgVersion(self, serialised): + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py b/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py index 278b660ec1..fe79333544 100644 --- a/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade22to24/__init__.py @@ -1,11 +1,16 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade.VersionUpgrade22to24() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -26,5 +31,5 @@ def getMetaData(): } } -def register(app): +def register(app: "Application"): return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json b/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json index e7a0b1c559..7da1e7a56d 100644 --- a/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json @@ -1,8 +1,8 @@ { "name": "Version Upgrade 2.2 to 2.4", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 2.2 to Cura 2.4.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade25to26/VersionUpgrade25to26.py b/plugins/VersionUpgrade/VersionUpgrade25to26/VersionUpgrade25to26.py index 6643edb765..6dbcfebc46 100644 --- a/plugins/VersionUpgrade/VersionUpgrade25to26/VersionUpgrade25to26.py +++ b/plugins/VersionUpgrade/VersionUpgrade25to26/VersionUpgrade25to26.py @@ -4,6 +4,7 @@ import configparser #To parse the files we need to upgrade and write the new files. import io #To serialise configparser output to a string. import os +from typing import Dict, List, Set, Tuple from urllib.parse import quote_plus from UM.Resources import Resources @@ -12,19 +13,18 @@ from UM.VersionUpgrade import VersionUpgrade _removed_settings = { #Settings that were removed in 2.5. "start_layers_at_same_position", "sub_div_rad_mult" -} +} # type: Set[str] _split_settings = { #These settings should be copied to all settings it was split into. "support_interface_line_distance": {"support_roof_line_distance", "support_bottom_line_distance"} -} +} # type: Dict[str, Set[str]] ## A collection of functions that convert the configuration of the user in Cura # 2.5 to a configuration for Cura 2.6. # # All of these methods are essentially stateless. class VersionUpgrade25to26(VersionUpgrade): - - def __init__(self): + def __init__(self) -> None: super().__init__() self._current_fdm_printer_count = 2 @@ -39,18 +39,18 @@ class VersionUpgrade25to26(VersionUpgrade): # \raises ValueError The format of the version number in the file is # incorrect. # \raises KeyError The format of the file is incorrect. - def getCfgVersion(self, serialised): + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version ## Upgrades the preferences file from version 2.5 to 2.6. # # \param serialised The serialised form of a preferences file. # \param filename The name of the file to upgrade. - def upgradePreferences(self, serialised, filename): + def upgradePreferences(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) @@ -86,7 +86,7 @@ class VersionUpgrade25to26(VersionUpgrade): # # \param serialised The serialised form of a quality profile. # \param filename The name of the file to upgrade. - def upgradeInstanceContainer(self, serialised, filename): + def upgradeInstanceContainer(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) @@ -116,7 +116,7 @@ class VersionUpgrade25to26(VersionUpgrade): # # \param serialised The serialised form of a quality profile. # \param filename The name of the file to upgrade. - def upgradeMachineStack(self, serialised, filename): + def upgradeMachineStack(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) @@ -149,7 +149,7 @@ class VersionUpgrade25to26(VersionUpgrade): return [filename], [output.getvalue()] ## Acquires the next unique extruder stack index number for the Custom FDM Printer. - def _acquireNextUniqueCustomFdmPrinterExtruderStackIdIndex(self): + def _acquireNextUniqueCustomFdmPrinterExtruderStackIdIndex(self) -> int: extruder_stack_dir = os.path.join(Resources.getDataStoragePath(), "extruders") file_name_list = os.listdir(extruder_stack_dir) file_name_list = [os.path.basename(file_name) for file_name in file_name_list] @@ -169,7 +169,7 @@ class VersionUpgrade25to26(VersionUpgrade): return self._current_fdm_printer_count - def _checkCustomFdmPrinterHasExtruderStack(self, machine_id): + def _checkCustomFdmPrinterHasExtruderStack(self, machine_id: str) -> bool: # go through all extruders and make sure that this custom FDM printer has extruder stacks. extruder_stack_dir = os.path.join(Resources.getDataStoragePath(), "extruders") has_extruders = False @@ -197,7 +197,7 @@ class VersionUpgrade25to26(VersionUpgrade): return has_extruders - def _createCustomFdmPrinterExtruderStack(self, machine_id: str, position: int, quality_id: str, material_id: str): + def _createCustomFdmPrinterExtruderStack(self, machine_id: str, position: int, quality_id: str, material_id: str) -> None: stack_id = "custom_extruder_%s" % (position + 1) if self._current_fdm_printer_count > 1: stack_id += " #%s" % self._current_fdm_printer_count @@ -256,7 +256,7 @@ class VersionUpgrade25to26(VersionUpgrade): ## Creates a definition changes container which doesn't contain anything for the Custom FDM Printers. # The container ID will be automatically generated according to the given stack name. - def _getCustomFdmPrinterDefinitionChanges(self, stack_id: str): + def _getCustomFdmPrinterDefinitionChanges(self, stack_id: str) -> configparser.ConfigParser: # In 2.5, there is no definition_changes container for the Custom FDM printer, so it should be safe to use the # default name unless some one names the printer as something like "Custom FDM Printer_settings". definition_changes_id = stack_id + "_settings" @@ -277,7 +277,7 @@ class VersionUpgrade25to26(VersionUpgrade): ## Creates a user settings container which doesn't contain anything for the Custom FDM Printers. # The container ID will be automatically generated according to the given stack name. - def _getCustomFdmPrinterUserSettings(self, stack_id: str): + def _getCustomFdmPrinterUserSettings(self, stack_id: str) -> configparser.ConfigParser: # For the extruder stacks created in the upgrade, also create user_settings containers so the user changes # will be saved. user_settings_id = stack_id + "_user" diff --git a/plugins/VersionUpgrade/VersionUpgrade25to26/__init__.py b/plugins/VersionUpgrade/VersionUpgrade25to26/__init__.py index 67aa73233f..c74b3218b6 100644 --- a/plugins/VersionUpgrade/VersionUpgrade25to26/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade25to26/__init__.py @@ -1,11 +1,16 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade25to26 +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade25to26.VersionUpgrade25to26() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -41,5 +46,5 @@ def getMetaData(): } } -def register(app): +def register(app: "Application") -> Dict[str, Any]: return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json b/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json index 3029539887..e1f0a47685 100644 --- a/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json @@ -1,8 +1,8 @@ { "name": "Version Upgrade 2.5 to 2.6", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 2.5 to Cura 2.6.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade26to27/VersionUpgrade26to27.py b/plugins/VersionUpgrade/VersionUpgrade26to27/VersionUpgrade26to27.py index dfa436e5bd..39e3dea4ed 100644 --- a/plugins/VersionUpgrade/VersionUpgrade26to27/VersionUpgrade26to27.py +++ b/plugins/VersionUpgrade/VersionUpgrade26to27/VersionUpgrade26to27.py @@ -3,6 +3,7 @@ import configparser #To parse the files we need to upgrade and write the new files. import io #To serialise configparser output to a string. +from typing import Dict, List, Tuple from UM.VersionUpgrade import VersionUpgrade @@ -61,7 +62,7 @@ _renamed_quality_profiles = { "um3_bb0.8_TPU_Not_Supported_Quality": "um3_bb0.8_TPU_Fast_print", "um3_bb0.8_TPU_Not_Supported_Superdraft_Quality": "um3_bb0.8_TPU_Superdraft_Print", -} +} # type: Dict[str, str] ## A collection of functions that convert the configuration of the user in Cura # 2.6 to a configuration for Cura 2.7. @@ -79,19 +80,19 @@ class VersionUpgrade26to27(VersionUpgrade): # \raises ValueError The format of the version number in the file is # incorrect. # \raises KeyError The format of the file is incorrect. - def getCfgVersion(self, serialised): + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version ## Upgrades a preferences file from version 2.6 to 2.7. # # \param serialised The serialised form of a preferences file. # \param filename The name of the file to upgrade. - def upgradePreferences(self, serialised, filename): - parser = configparser.ConfigParser(interpolation=None) + def upgradePreferences(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) # Update version numbers @@ -117,8 +118,8 @@ class VersionUpgrade26to27(VersionUpgrade): # # \param serialised The serialised form of a container file. # \param filename The name of the file to upgrade. - def upgradeOtherContainer(self, serialised, filename): - parser = configparser.ConfigParser(interpolation=None) + def upgradeOtherContainer(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) # Update version numbers @@ -139,7 +140,7 @@ class VersionUpgrade26to27(VersionUpgrade): # # \param serialised The serialised form of a container stack. # \param filename The name of the file to upgrade. - def upgradeStack(self, serialised, filename): + def upgradeStack(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) diff --git a/plugins/VersionUpgrade/VersionUpgrade26to27/__init__.py b/plugins/VersionUpgrade/VersionUpgrade26to27/__init__.py index 0e26ca8bbf..1952c9ceff 100644 --- a/plugins/VersionUpgrade/VersionUpgrade26to27/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade26to27/__init__.py @@ -1,11 +1,16 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade26to27 +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade26to27.VersionUpgrade26to27() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -59,5 +64,5 @@ def getMetaData(): } } -def register(app): +def register(app: "Application") -> Dict[str, Any]: return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json b/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json index 225da67235..6cdbd64cbb 100644 --- a/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json @@ -1,8 +1,8 @@ { "name": "Version Upgrade 2.6 to 2.7", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 2.6 to Cura 2.7.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade27to30/VersionUpgrade27to30.py b/plugins/VersionUpgrade/VersionUpgrade27to30/VersionUpgrade27to30.py index 5a141f1558..b594c3c6c4 100644 --- a/plugins/VersionUpgrade/VersionUpgrade27to30/VersionUpgrade27to30.py +++ b/plugins/VersionUpgrade/VersionUpgrade27to30/VersionUpgrade27to30.py @@ -1,9 +1,10 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import configparser #To parse preference files. import io #To serialise the preference files afterwards. import os +from typing import Dict, List, Tuple import urllib.parse import re @@ -11,7 +12,7 @@ from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this. _renamed_themes = { "cura": "cura-light" -} +} # type: Dict[str, str] _renamed_i18n = { "7s": "en_7S", "de": "de_DE", @@ -28,7 +29,7 @@ _renamed_i18n = { "ptbr": "pt_BR", "ru": "ru_RU", "tr": "tr_TR" -} +} # type: Dict[str, str] class VersionUpgrade27to30(VersionUpgrade): @@ -43,19 +44,19 @@ class VersionUpgrade27to30(VersionUpgrade): # \raises ValueError The format of the version number in the file is # incorrect. # \raises KeyError The format of the file is incorrect. - def getCfgVersion(self, serialised): + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version ## Upgrades a preferences file from version 2.7 to 3.0. # # \param serialised The serialised form of a preferences file. # \param filename The name of the file to upgrade. - def upgradePreferences(self, serialised, filename): - parser = configparser.ConfigParser(interpolation=None) + def upgradePreferences(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) # Update version numbers @@ -100,8 +101,8 @@ class VersionUpgrade27to30(VersionUpgrade): # # \param serialised The serialised form of the container file. # \param filename The name of the file to upgrade. - def upgradeQualityChangesContainer(self, serialised, filename): - parser = configparser.ConfigParser(interpolation=None) + def upgradeQualityChangesContainer(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) # Update the skin pre-shrink settings: @@ -156,8 +157,8 @@ class VersionUpgrade27to30(VersionUpgrade): # # \param serialised The serialised form of the container file. # \param filename The name of the file to upgrade. - def upgradeOtherContainer(self, serialised, filename): - parser = configparser.ConfigParser(interpolation=None) + def upgradeOtherContainer(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) # Update the skin pre-shrink settings: @@ -185,7 +186,7 @@ class VersionUpgrade27to30(VersionUpgrade): # # \param serialised The serialised form of a container stack. # \param filename The name of the file to upgrade. - def upgradeStack(self, serialised, filename): + def upgradeStack(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation=None) parser.read_string(serialised) diff --git a/plugins/VersionUpgrade/VersionUpgrade27to30/__init__.py b/plugins/VersionUpgrade/VersionUpgrade27to30/__init__.py index 4da7257b1c..bddc71a1e0 100644 --- a/plugins/VersionUpgrade/VersionUpgrade27to30/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade27to30/__init__.py @@ -1,11 +1,16 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade27to30 +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade27to30.VersionUpgrade27to30() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -51,5 +56,5 @@ def getMetaData(): } } -def register(app): +def register(app: "Application") -> Dict[str, Any]: return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json b/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json index 9a139851ec..885d741a8c 100644 --- a/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json @@ -1,8 +1,8 @@ { "name": "Version Upgrade 2.7 to 3.0", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 2.7 to Cura 3.0.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py b/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py index 399eb18b5d..f0b2e939b9 100644 --- a/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py +++ b/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py @@ -1,14 +1,15 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import configparser #To parse preference files. import io #To serialise the preference files afterwards. +from typing import Dict, List, Set, Tuple from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this. # a list of all legacy "Not Supported" quality profiles -_OLD_NOT_SUPPORTED_PROFILES = [ +_OLD_NOT_SUPPORTED_PROFILES = { "um2p_pp_0.25_normal", "um2p_tpu_0.8_normal", "um3_bb0.4_ABS_Fast_Print", @@ -42,7 +43,7 @@ _OLD_NOT_SUPPORTED_PROFILES = [ "um3_bb0.8_PP_Superdraft_Print", "um3_bb0.8_TPU_Fast_print", "um3_bb0.8_TPU_Superdraft_Print", -] +} # type: Set[str] # Some containers have their specific empty containers, those need to be set correctly. @@ -51,13 +52,13 @@ _EMPTY_CONTAINER_DICT = { "2": "empty_quality", "3": "empty_material", "4": "empty_variant", -} +} # type: Dict[str, str] # Renamed definition files _RENAMED_DEFINITION_DICT = { "jellybox": "imade3d_jellybox", -} +} # type: Dict[str, str] class VersionUpgrade30to31(VersionUpgrade): @@ -72,18 +73,18 @@ class VersionUpgrade30to31(VersionUpgrade): # \raises ValueError The format of the version number in the file is # incorrect. # \raises KeyError The format of the file is incorrect. - def getCfgVersion(self, serialised): + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version ## Upgrades a preferences file from version 3.0 to 3.1. # # \param serialised The serialised form of a preferences file. # \param filename The name of the file to upgrade. - def upgradePreferences(self, serialised, filename): + def upgradePreferences(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) @@ -104,7 +105,7 @@ class VersionUpgrade30to31(VersionUpgrade): # # \param serialised The serialised form of the container file. # \param filename The name of the file to upgrade. - def upgradeInstanceContainer(self, serialised, filename): + def upgradeInstanceContainer(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) @@ -129,7 +130,7 @@ class VersionUpgrade30to31(VersionUpgrade): # # \param serialised The serialised form of a container stack. # \param filename The name of the file to upgrade. - def upgradeStack(self, serialised, filename): + def upgradeStack(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) diff --git a/plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py b/plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py index 7b2c213a31..c5cc851d6a 100644 --- a/plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py @@ -1,11 +1,16 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade30to31 +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade30to31.VersionUpgrade30to31() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -55,5 +60,5 @@ def getMetaData(): } } -def register(app): +def register(app: "Application") -> Dict[str, Any]: return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json b/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json index cf42b3f6cd..d5f22649c1 100644 --- a/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json @@ -1,8 +1,8 @@ { "name": "Version Upgrade 3.0 to 3.1", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 3.0 to Cura 3.1.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py index 18851b82c7..83cb15c864 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/VersionUpgrade32to33.py @@ -3,6 +3,7 @@ import configparser #To parse preference files. import io #To serialise the preference files afterwards. +from typing import Dict, List, Tuple from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this. @@ -51,22 +52,22 @@ _EXTRUDER_TO_POSITION = { "ultimaker_original_dual_2nd": 1, "vertex_k8400_dual_1st": 0, "vertex_k8400_dual_2nd": 1 -} +} # type: Dict[str, int] _RENAMED_QUALITY_PROFILES = { "low": "fast", "um2_low": "um2_fast" -} +} # type: Dict[str, str] _RENAMED_QUALITY_TYPES = { "low": "fast" -} +} # type: Dict[str, str] ## Upgrades configurations from the state they were in at version 3.2 to the # state they should be in at version 3.3. class VersionUpgrade32to33(VersionUpgrade): - temporary_group_name_counter = 1 + ## Gets the version number from a CFG file in Uranium's 3.2 format. # # Since the format may change, this is implemented for the 3.2 format only @@ -78,18 +79,18 @@ class VersionUpgrade32to33(VersionUpgrade): # \raises ValueError The format of the version number in the file is # incorrect. # \raises KeyError The format of the file is incorrect. - def getCfgVersion(self, serialised): + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version ## Upgrades a preferences file from version 3.2 to 3.3. # # \param serialised The serialised form of a preferences file. # \param filename The name of the file to upgrade. - def upgradePreferences(self, serialised, filename): + def upgradePreferences(self, serialised: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) @@ -117,7 +118,7 @@ class VersionUpgrade32to33(VersionUpgrade): # # \param serialised The serialised form of a container stack. # \param filename The name of the file to upgrade. - def upgradeStack(self, serialized, filename): + def upgradeStack(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialized) @@ -141,7 +142,7 @@ class VersionUpgrade32to33(VersionUpgrade): ## Upgrades non-quality-changes instance containers to have the new version # number. - def upgradeInstanceContainer(self, serialized, filename): + def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialized) @@ -153,7 +154,7 @@ class VersionUpgrade32to33(VersionUpgrade): return [filename], [result.getvalue()] ## Upgrades a quality changes container to the new format. - def upgradeQualityChanges(self, serialized, filename): + def upgradeQualityChanges(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialized) @@ -182,7 +183,7 @@ class VersionUpgrade32to33(VersionUpgrade): return [filename], [result.getvalue()] ## Upgrades a variant container to the new format. - def upgradeVariants(self, serialized, filename): + def upgradeVariants(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialized) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py index 5073be772d..b55ea5ebaf 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -1,11 +1,16 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade32to33 +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade32to33.VersionUpgrade32to33() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -42,7 +47,7 @@ def getMetaData(): }, "user": { "get_version": upgrade.getCfgVersion, - "location": {"./user"} + "location": {"./user", "./materials/*"} }, "variant": { "get_version": upgrade.getCfgVersion, @@ -51,5 +56,5 @@ def getMetaData(): } } -def register(app): +def register(app: "Application") -> Dict[str, Any]: return { "version_upgrade": upgrade } \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json b/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json index f9cc968dae..eb489169e0 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json @@ -1,8 +1,8 @@ { "name": "Version Upgrade 3.2 to 3.3", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 3.2 to Cura 3.3.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade33to34/VersionUpgrade33to34.py b/plugins/VersionUpgrade/VersionUpgrade33to34/VersionUpgrade33to34.py index e2241fd195..704ede02d6 100644 --- a/plugins/VersionUpgrade/VersionUpgrade33to34/VersionUpgrade33to34.py +++ b/plugins/VersionUpgrade/VersionUpgrade33to34/VersionUpgrade33to34.py @@ -3,17 +3,17 @@ import configparser #To parse preference files. import io #To serialise the preference files afterwards. +from typing import Dict, List, Tuple from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this. _renamed_settings = { "infill_hollow": "infill_support_enabled" -} +} # type: Dict[str, str] ## Upgrades configurations from the state they were in at version 3.3 to the # state they should be in at version 3.4. class VersionUpgrade33to34(VersionUpgrade): - ## Gets the version number from a CFG file in Uranium's 3.3 format. # # Since the format may change, this is implemented for the 3.3 format only @@ -25,16 +25,16 @@ class VersionUpgrade33to34(VersionUpgrade): # \raises ValueError The format of the version number in the file is # incorrect. # \raises KeyError The format of the file is incorrect. - def getCfgVersion(self, serialised): + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version ## Upgrades instance containers to have the new version # number. - def upgradeInstanceContainer(self, serialized, filename): + def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialized) diff --git a/plugins/VersionUpgrade/VersionUpgrade33to34/__init__.py b/plugins/VersionUpgrade/VersionUpgrade33to34/__init__.py index 1130c1e9e2..5fd757f843 100644 --- a/plugins/VersionUpgrade/VersionUpgrade33to34/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade33to34/__init__.py @@ -1,11 +1,16 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade33to34 +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade33to34.VersionUpgrade33to34() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -35,5 +40,5 @@ def getMetaData(): } -def register(app): +def register(app: "Application") -> Dict[str, Any]: return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json b/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json index f5ba7235d1..9649010643 100644 --- a/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json @@ -1,8 +1,8 @@ { "name": "Version Upgrade 3.3 to 3.4", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 3.3 to Cura 3.4.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade34to35/VersionUpgrade34to35.py b/plugins/VersionUpgrade/VersionUpgrade34to35/VersionUpgrade34to35.py index 9d59133036..8e45d7cf73 100644 --- a/plugins/VersionUpgrade/VersionUpgrade34to35/VersionUpgrade34to35.py +++ b/plugins/VersionUpgrade/VersionUpgrade34to35/VersionUpgrade34to35.py @@ -3,13 +3,14 @@ import configparser import io +from typing import Dict, List, Set, Tuple from UM.VersionUpgrade import VersionUpgrade -deleted_settings = {"prime_tower_wall_thickness", "dual_pre_wipe", "prime_tower_purge_volume"} +deleted_settings = {"prime_tower_wall_thickness", "dual_pre_wipe", "prime_tower_purge_volume"} # type: Set[str] -changed_settings = {'retraction_combing': 'noskin'} -updated_settings = {'retraction_combing': 'infill'} +changed_settings = {"retraction_combing": "noskin"} # type: Dict[str, str] +updated_settings = {"retraction_combing": "infill"} # type: Dict[str, str] _RENAMED_MATERIAL_PROFILES = { "dsm_arnitel2045_175_cartesio_0.25_mm": "dsm_arnitel2045_175_cartesio_0.25mm_thermoplastic_extruder", @@ -57,15 +58,14 @@ _RENAMED_MATERIAL_PROFILES = { "ultimaker_pva_cartesio_0.25_mm": "ultimaker_pva_cartesio_0.25mm_thermoplastic_extruder", "ultimaker_pva_cartesio_0.4_mm": "ultimaker_pva_cartesio_0.4mm_thermoplastic_extruder", "ultimaker_pva_cartesio_0.8_mm": "ultimaker_pva_cartesio_0.8mm_thermoplastic_extruder" -} +} # type: Dict[str, str] ## Upgrades configurations from the state they were in at version 3.4 to the # state they should be in at version 3.5. class VersionUpgrade34to35(VersionUpgrade): - - ## Gets the version number from a CFG file in Uranium's 3.3 format. + ## Gets the version number from a CFG file in Uranium's 3.4 format. # - # Since the format may change, this is implemented for the 3.3 format only + # Since the format may change, this is implemented for the 3.4 format only # and needs to be included in the version upgrade system rather than # globally in Uranium. # @@ -74,15 +74,15 @@ class VersionUpgrade34to35(VersionUpgrade): # \raises ValueError The format of the version number in the file is # incorrect. # \raises KeyError The format of the file is incorrect. - def getCfgVersion(self, serialised): + def getCfgVersion(self, serialised: str) -> int: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialised) format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. - setting_version = int(parser.get("metadata", "setting_version", fallback = 0)) + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) return format_version * 1000000 + setting_version ## Upgrades Preferences to have the new version number. - def upgradePreferences(self, serialized, filename): + def upgradePreferences(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialized) @@ -103,7 +103,7 @@ class VersionUpgrade34to35(VersionUpgrade): return [filename], [result.getvalue()] ## Upgrades stacks to have the new version number. - def upgradeStack(self, serialized, filename): + def upgradeStack(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialized) @@ -121,7 +121,7 @@ class VersionUpgrade34to35(VersionUpgrade): ## Upgrades instance containers to have the new version # number. - def upgradeInstanceContainer(self, serialized, filename): + def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: parser = configparser.ConfigParser(interpolation = None) parser.read_string(serialized) @@ -147,7 +147,7 @@ class VersionUpgrade34to35(VersionUpgrade): parser.write(result) return [filename], [result.getvalue()] - def _resetConcentric3DInfillPattern(self, parser): + def _resetConcentric3DInfillPattern(self, parser: configparser.ConfigParser) -> None: if "values" not in parser: return @@ -161,5 +161,4 @@ class VersionUpgrade34to35(VersionUpgrade): if key not in parser["values"]: continue if parser["values"][key] == "concentric_3d": - del parser["values"][key] - + del parser["values"][key] \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade34to35/__init__.py b/plugins/VersionUpgrade/VersionUpgrade34to35/__init__.py index 2ea74f6194..332bc827b9 100644 --- a/plugins/VersionUpgrade/VersionUpgrade34to35/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade34to35/__init__.py @@ -1,11 +1,16 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from typing import Any, Dict, TYPE_CHECKING + from . import VersionUpgrade34to35 +if TYPE_CHECKING: + from UM.Application import Application + upgrade = VersionUpgrade34to35.VersionUpgrade34to35() -def getMetaData(): +def getMetaData() -> Dict[str, Any]: return { "version_upgrade": { # From To Upgrade function @@ -52,5 +57,5 @@ def getMetaData(): } -def register(app): +def register(app: "Application") -> Dict[str, Any]: return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade34to35/plugin.json b/plugins/VersionUpgrade/VersionUpgrade34to35/plugin.json index b73001b683..71b13ee5a9 100644 --- a/plugins/VersionUpgrade/VersionUpgrade34to35/plugin.json +++ b/plugins/VersionUpgrade/VersionUpgrade34to35/plugin.json @@ -1,8 +1,8 @@ - { +{ "name": "Version Upgrade 3.4 to 3.5", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Upgrades configurations from Cura 3.4 to Cura 3.5.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/VersionUpgrade/VersionUpgrade35to40/VersionUpgrade35to40.py b/plugins/VersionUpgrade/VersionUpgrade35to40/VersionUpgrade35to40.py new file mode 100644 index 0000000000..52cd7cf3cb --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade35to40/VersionUpgrade35to40.py @@ -0,0 +1,68 @@ +import configparser +from typing import Tuple, List, Set +import io +from UM.VersionUpgrade import VersionUpgrade +from cura.PrinterOutputDevice import ConnectionType +deleted_settings = {"bridge_wall_max_overhang"} # type: Set[str] + + +class VersionUpgrade35to40(VersionUpgrade): + # Upgrades stacks to have the new version number. + def upgradeStack(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation=None) + parser.read_string(serialized) + + # Update version number. + parser["general"]["version"] = "4" + parser["metadata"]["setting_version"] = "6" + + if parser["metadata"].get("um_network_key") is not None or parser["metadata"].get("octoprint_api_key") is not None: + # Set the connection type if um_network_key or the octoprint key is set. + parser["metadata"]["connection_type"] = str(ConnectionType.NetworkConnection.value) + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] + pass + + def getCfgVersion(self, serialised: str) -> int: + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialised) + format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) + return format_version * 1000000 + setting_version + + ## Upgrades Preferences to have the new version number. + def upgradePreferences(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation=None) + parser.read_string(serialized) + + if "metadata" not in parser: + parser["metadata"] = {} + parser["general"]["version"] = "6" + parser["metadata"]["setting_version"] = "6" + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] + + ## Upgrades instance containers to have the new version + # number. + def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation=None) + parser.read_string(serialized) + + # Update version number. + parser["general"]["version"] = "4" + parser["metadata"]["setting_version"] = "6" + + #self._resetConcentric3DInfillPattern(parser) + if "values" in parser: + for deleted_setting in deleted_settings: + if deleted_setting not in parser["values"]: + continue + del parser["values"][deleted_setting] + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade35to40/__init__.py b/plugins/VersionUpgrade/VersionUpgrade35to40/__init__.py new file mode 100644 index 0000000000..2ad1dddbf2 --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade35to40/__init__.py @@ -0,0 +1,56 @@ +from typing import Dict, Any + +from . import VersionUpgrade35to40 + +upgrade = VersionUpgrade35to40.VersionUpgrade35to40() + + +def getMetaData() -> Dict[str, Any]: + return { + "version_upgrade": { + # From To Upgrade function + ("preferences", 6000005): ("preferences", 6000006, upgrade.upgradePreferences), + + ("definition_changes", 4000005): ("definition_changes", 4000006, upgrade.upgradeInstanceContainer), + ("quality_changes", 4000005): ("quality_changes", 4000006, upgrade.upgradeInstanceContainer), + ("quality", 4000005): ("quality", 4000006, upgrade.upgradeInstanceContainer), + ("user", 4000005): ("user", 4000006, upgrade.upgradeInstanceContainer), + + ("machine_stack", 4000005): ("machine_stack", 4000006, upgrade.upgradeStack), + ("extruder_train", 4000005): ("extruder_train", 4000006, upgrade.upgradeStack), + }, + "sources": { + "preferences": { + "get_version": upgrade.getCfgVersion, + "location": {"."} + }, + "machine_stack": { + "get_version": upgrade.getCfgVersion, + "location": {"./machine_instances"} + }, + "extruder_train": { + "get_version": upgrade.getCfgVersion, + "location": {"./extruders"} + }, + "definition_changes": { + "get_version": upgrade.getCfgVersion, + "location": {"./definition_changes"} + }, + "quality_changes": { + "get_version": upgrade.getCfgVersion, + "location": {"./quality_changes"} + }, + "quality": { + "get_version": upgrade.getCfgVersion, + "location": {"./quality"} + }, + "user": { + "get_version": upgrade.getCfgVersion, + "location": {"./user"} + } + } + } + + +def register(app) -> Dict[str, Any]: + return {"version_upgrade": upgrade} \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade35to40/plugin.json b/plugins/VersionUpgrade/VersionUpgrade35to40/plugin.json new file mode 100644 index 0000000000..578594fb6d --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade35to40/plugin.json @@ -0,0 +1,8 @@ + { + "name": "Version Upgrade 3.5 to 4.0", + "author": "Ultimaker B.V.", + "version": "1.0.0", + "description": "Upgrades configurations from Cura 3.5 to Cura 4.0.", + "api": "6.0", + "i18n-catalog": "cura" +} diff --git a/plugins/VersionUpgrade/VersionUpgrade40to41/VersionUpgrade40to41.py b/plugins/VersionUpgrade/VersionUpgrade40to41/VersionUpgrade40to41.py new file mode 100644 index 0000000000..ac54b7c8e0 --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade40to41/VersionUpgrade40to41.py @@ -0,0 +1,86 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +import configparser +import io +from typing import Dict, List, Tuple + +from UM.VersionUpgrade import VersionUpgrade + +_renamed_quality_profiles = { + "gmax15plus_pla_dual_normal": "gmax15plus_global_dual_normal", + "gmax15plus_pla_dual_thick": "gmax15plus_global_dual_thick", + "gmax15plus_pla_dual_thin": "gmax15plus_global_dual_thin", + "gmax15plus_pla_dual_very_thick": "gmax15plus_global_dual_very_thick", + "gmax15plus_pla_normal": "gmax15plus_global_normal", + "gmax15plus_pla_thick": "gmax15plus_global_thick", + "gmax15plus_pla_thin": "gmax15plus_global_thin", + "gmax15plus_pla_very_thick": "gmax15plus_global_very_thick" +} # type: Dict[str, str] + +## Upgrades configurations from the state they were in at version 4.0 to the +# state they should be in at version 4.1. +class VersionUpgrade40to41(VersionUpgrade): + ## Gets the version number from a CFG file in Uranium's 4.0 format. + # + # Since the format may change, this is implemented for the 4.0 format only + # and needs to be included in the version upgrade system rather than + # globally in Uranium. + # + # \param serialised The serialised form of a CFG file. + # \return The version number stored in the CFG file. + # \raises ValueError The format of the version number in the file is + # incorrect. + # \raises KeyError The format of the file is incorrect. + def getCfgVersion(self, serialised: str) -> int: + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialised) + format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised. + setting_version = int(parser.get("metadata", "setting_version", fallback = "0")) + return format_version * 1000000 + setting_version + + ## Upgrades instance containers to have the new version + # number. + def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialized) + + # Update version number. + parser["general"]["version"] = "4" + parser["metadata"]["setting_version"] = "6" + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] + + ## Upgrades Preferences to have the new version number. + def upgradePreferences(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialized) + + # Update version number. + parser["general"]["version"] = "6" + if "metadata" not in parser: + parser["metadata"] = {} + parser["metadata"]["setting_version"] = "6" + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] + + ## Upgrades stacks to have the new version number. + def upgradeStack(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]: + parser = configparser.ConfigParser(interpolation = None) + parser.read_string(serialized) + + # Update version number. + parser["general"]["version"] = "4" + parser["metadata"]["setting_version"] = "6" + + #Update the name of the quality profile. + if parser["containers"]["4"] in _renamed_quality_profiles: + parser["containers"]["4"] = _renamed_quality_profiles[parser["containers"]["4"]] + + result = io.StringIO() + parser.write(result) + return [filename], [result.getvalue()] \ No newline at end of file diff --git a/plugins/VersionUpgrade/VersionUpgrade40to41/__init__.py b/plugins/VersionUpgrade/VersionUpgrade40to41/__init__.py new file mode 100644 index 0000000000..757a7a51c0 --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade40to41/__init__.py @@ -0,0 +1,39 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from typing import Any, Dict, TYPE_CHECKING + +from . import VersionUpgrade40to41 + +if TYPE_CHECKING: + from UM.Application import Application + +upgrade = VersionUpgrade40to41.VersionUpgrade40to41() + +def getMetaData() -> Dict[str, Any]: + return { + "version_upgrade": { + # From To Upgrade function + ("machine_stack", 4000005): ("machine_stack", 4000006, upgrade.upgradeStack), + ("extruder_train", 4000005): ("extruder_train", 4000006, upgrade.upgradeStack), + ("preferences", 6000005): ("preferences", 6000006, upgrade.upgradePreferences), + ("definition_changes", 4000005): ("definition_changes", 4000006, upgrade.upgradeInstanceContainer), + ("quality_changes", 4000005): ("quality_changes", 4000006, upgrade.upgradeInstanceContainer), + ("quality", 4000005): ("quality", 4000006, upgrade.upgradeInstanceContainer), + ("user", 4000005): ("user", 4000006, upgrade.upgradeInstanceContainer), + }, + "sources": { + "machine_stack": { + "get_version": upgrade.getCfgVersion, + "location": {"./machine_instances"} + }, + "extruder_train": { + "get_version": upgrade.getCfgVersion, + "location": {"./extruders"} + } + } + } + + +def register(app: "Application") -> Dict[str, Any]: + return { "version_upgrade": upgrade } diff --git a/plugins/VersionUpgrade/VersionUpgrade40to41/plugin.json b/plugins/VersionUpgrade/VersionUpgrade40to41/plugin.json new file mode 100644 index 0000000000..b1c6d75669 --- /dev/null +++ b/plugins/VersionUpgrade/VersionUpgrade40to41/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Version Upgrade 4.0 to 4.1", + "author": "Ultimaker B.V.", + "version": "1.0.1", + "description": "Upgrades configurations from Cura 4.0 to Cura 4.1.", + "api": "6.0", + "i18n-catalog": "cura" +} diff --git a/plugins/X3DReader/plugin.json b/plugins/X3DReader/plugin.json index 9ee09e43df..1fc14104ed 100644 --- a/plugins/X3DReader/plugin.json +++ b/plugins/X3DReader/plugin.json @@ -1,8 +1,8 @@ { "name": "X3D Reader", "author": "Seva Alekseyev", - "version": "0.5.0", + "version": "1.0.1", "description": "Provides support for reading X3D files.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/XRayView/plugin.json b/plugins/XRayView/plugin.json index 576dec4656..71cc165b6c 100644 --- a/plugins/XRayView/plugin.json +++ b/plugins/XRayView/plugin.json @@ -1,8 +1,8 @@ { "name": "X-Ray View", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides the X-Ray view.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/plugins/XmlMaterialProfile/__init__.py b/plugins/XmlMaterialProfile/__init__.py index e8bde78424..c50df69516 100644 --- a/plugins/XmlMaterialProfile/__init__.py +++ b/plugins/XmlMaterialProfile/__init__.py @@ -16,7 +16,7 @@ def getMetaData(): "mimetype": "application/x-ultimaker-material-profile" }, "version_upgrade": { - ("materials", 1000000): ("materials", 1000004, upgrader.upgradeMaterial), + ("materials", 1000000): ("materials", 1000006, upgrader.upgradeMaterial), }, "sources": { "materials": { diff --git a/plugins/XmlMaterialProfile/plugin.json b/plugins/XmlMaterialProfile/plugin.json index 4b2901c375..bb1db82fa4 100644 --- a/plugins/XmlMaterialProfile/plugin.json +++ b/plugins/XmlMaterialProfile/plugin.json @@ -1,8 +1,8 @@ { "name": "Material Profiles", "author": "Ultimaker B.V.", - "version": "1.0.0", + "version": "1.0.1", "description": "Provides capabilities to read and write XML-based material profiles.", - "api": 5, + "api": "6.0", "i18n-catalog": "cura" } diff --git a/resources/bundled_packages/cura.json b/resources/bundled_packages/cura.json index ee82b17a75..21da1d9fdb 100644 --- a/resources/bundled_packages/cura.json +++ b/resources/bundled_packages/cura.json @@ -5,8 +5,8 @@ "package_type": "plugin", "display_name": "3MF Reader", "description": "Provides support for reading 3MF files.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -22,8 +22,8 @@ "package_type": "plugin", "display_name": "3MF Writer", "description": "Provides support for writing 3MF files.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -39,8 +39,25 @@ "package_type": "plugin", "display_name": "Change Log", "description": "Shows changes since latest checked version.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.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", + "package_type": "plugin", + "display_name": "Cura Backups", + "description": "Backup and restore your configuration.", + "package_version": "1.2.0", + "sdk_version": 6, "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -56,8 +73,8 @@ "package_type": "plugin", "display_name": "CuraEngine Backend", "description": "Provides the link to the CuraEngine slicing backend.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -73,8 +90,8 @@ "package_type": "plugin", "display_name": "Cura Profile Reader", "description": "Provides support for importing Cura profiles.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -90,8 +107,8 @@ "package_type": "plugin", "display_name": "Cura Profile Writer", "description": "Provides support for exporting Cura profiles.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -107,8 +124,8 @@ "package_type": "plugin", "display_name": "Firmware Update Checker", "description": "Checks for firmware updates.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -124,8 +141,8 @@ "package_type": "plugin", "display_name": "Firmware Updater", "description": "Provides a machine actions for updating firmware.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -141,8 +158,8 @@ "package_type": "plugin", "display_name": "Compressed G-code Reader", "description": "Reads g-code from a compressed archive.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -158,8 +175,8 @@ "package_type": "plugin", "display_name": "Compressed G-code Writer", "description": "Writes g-code to a compressed archive.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -175,8 +192,8 @@ "package_type": "plugin", "display_name": "G-Code Profile Reader", "description": "Provides support for importing profiles from g-code files.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -192,8 +209,8 @@ "package_type": "plugin", "display_name": "G-Code Reader", "description": "Allows loading and displaying G-code files.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "VictorLarchenko", @@ -209,8 +226,8 @@ "package_type": "plugin", "display_name": "G-Code Writer", "description": "Writes g-code to a file.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -226,8 +243,8 @@ "package_type": "plugin", "display_name": "Image Reader", "description": "Enables ability to generate printable geometry from 2D image files.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -243,8 +260,8 @@ "package_type": "plugin", "display_name": "Legacy Cura Profile Reader", "description": "Provides support for importing profiles from legacy Cura versions.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -260,8 +277,8 @@ "package_type": "plugin", "display_name": "Machine Settings Action", "description": "Provides a way to change machine settings (such as build volume, nozzle size, etc.).", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "fieldOfView", @@ -277,8 +294,8 @@ "package_type": "plugin", "display_name": "Model Checker", "description": "Checks models and print configuration for possible printing issues and give suggestions.", - "package_version": "0.1.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -294,8 +311,8 @@ "package_type": "plugin", "display_name": "Monitor Stage", "description": "Provides a monitor stage in Cura.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -311,8 +328,8 @@ "package_type": "plugin", "display_name": "Per-Object Settings Tool", "description": "Provides the per-model settings.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -328,8 +345,8 @@ "package_type": "plugin", "display_name": "Post Processing", "description": "Extension that allows for user created scripts for post processing.", - "package_version": "2.2.0", - "sdk_version": 5, + "package_version": "2.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -345,8 +362,25 @@ "package_type": "plugin", "display_name": "Prepare Stage", "description": "Provides a prepare stage in Cura.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", + "website": "https://ultimaker.com", + "author": { + "author_id": "UltimakerPackages", + "display_name": "Ultimaker B.V.", + "email": "plugins@ultimaker.com", + "website": "https://ultimaker.com" + } + } + }, + "PreviewStage": { + "package_info": { + "package_id": "PreviewStage", + "package_type": "plugin", + "display_name": "Preview Stage", + "description": "Provides a preview stage in Cura.", + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -362,8 +396,8 @@ "package_type": "plugin", "display_name": "Removable Drive Output Device", "description": "Provides removable drive hotplugging and writing support.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -379,8 +413,8 @@ "package_type": "plugin", "display_name": "Simulation View", "description": "Provides the Simulation view.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -396,8 +430,8 @@ "package_type": "plugin", "display_name": "Slice Info", "description": "Submits anonymous slice info. Can be disabled through preferences.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -413,8 +447,8 @@ "package_type": "plugin", "display_name": "Solid View", "description": "Provides a normal solid mesh view.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -430,8 +464,8 @@ "package_type": "plugin", "display_name": "Support Eraser Tool", "description": "Creates an eraser mesh to block the printing of support in certain places.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -447,8 +481,8 @@ "package_type": "plugin", "display_name": "Toolbox", "description": "Find, manage and install new Cura packages.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -464,8 +498,8 @@ "package_type": "plugin", "display_name": "UFP Writer", "description": "Provides support for writing Ultimaker Format Packages.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -481,8 +515,8 @@ "package_type": "plugin", "display_name": "Ultimaker Machine Actions", "description": "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc.).", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -498,8 +532,8 @@ "package_type": "plugin", "display_name": "UM3 Network Printing", "description": "Manages network connections to Ultimaker 3 printers.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -515,8 +549,8 @@ "package_type": "plugin", "display_name": "USB Printing", "description": "Accepts G-Code and sends them to a printer. Plugin can also update firmware.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.2", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -532,8 +566,8 @@ "package_type": "plugin", "display_name": "User Agreement", "description": "Ask the user once if he/she agrees with our license.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -549,8 +583,8 @@ "package_type": "plugin", "display_name": "Version Upgrade 2.1 to 2.2", "description": "Upgrades configurations from Cura 2.1 to Cura 2.2.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -566,8 +600,8 @@ "package_type": "plugin", "display_name": "Version Upgrade 2.2 to 2.4", "description": "Upgrades configurations from Cura 2.2 to Cura 2.4.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -583,8 +617,8 @@ "package_type": "plugin", "display_name": "Version Upgrade 2.5 to 2.6", "description": "Upgrades configurations from Cura 2.5 to Cura 2.6.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -600,8 +634,8 @@ "package_type": "plugin", "display_name": "Version Upgrade 2.6 to 2.7", "description": "Upgrades configurations from Cura 2.6 to Cura 2.7.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -617,8 +651,8 @@ "package_type": "plugin", "display_name": "Version Upgrade 2.7 to 3.0", "description": "Upgrades configurations from Cura 2.7 to Cura 3.0.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -634,8 +668,8 @@ "package_type": "plugin", "display_name": "Version Upgrade 3.0 to 3.1", "description": "Upgrades configurations from Cura 3.0 to Cura 3.1.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -651,8 +685,8 @@ "package_type": "plugin", "display_name": "Version Upgrade 3.2 to 3.3", "description": "Upgrades configurations from Cura 3.2 to Cura 3.3.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -668,8 +702,8 @@ "package_type": "plugin", "display_name": "Version Upgrade 3.3 to 3.4", "description": "Upgrades configurations from Cura 3.3 to Cura 3.4.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -685,8 +719,42 @@ "package_type": "plugin", "display_name": "Version Upgrade 3.4 to 3.5", "description": "Upgrades configurations from Cura 3.4 to Cura 3.5.", + "package_version": "1.0.1", + "sdk_version": "6.0", + "website": "https://ultimaker.com", + "author": { + "author_id": "UltimakerPackages", + "display_name": "Ultimaker B.V.", + "email": "plugins@ultimaker.com", + "website": "https://ultimaker.com" + } + } + }, + "VersionUpgrade35to40": { + "package_info": { + "package_id": "VersionUpgrade35to40", + "package_type": "plugin", + "display_name": "Version Upgrade 3.5 to 4.0", + "description": "Upgrades configurations from Cura 3.5 to Cura 4.0.", "package_version": "1.0.0", - "sdk_version": 5, + "sdk_version": "6.0", + "website": "https://ultimaker.com", + "author": { + "author_id": "UltimakerPackages", + "display_name": "Ultimaker B.V.", + "email": "plugins@ultimaker.com", + "website": "https://ultimaker.com" + } + } + }, + "VersionUpgrade40to41": { + "package_info": { + "package_id": "VersionUpgrade40to41", + "package_type": "plugin", + "display_name": "Version Upgrade 4.0 to 4.1", + "description": "Upgrades configurations from Cura 4.0 to Cura 4.1.", + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -702,8 +770,8 @@ "package_type": "plugin", "display_name": "X3D Reader", "description": "Provides support for reading X3D files.", - "package_version": "0.5.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "SevaAlekseyev", @@ -719,8 +787,8 @@ "package_type": "plugin", "display_name": "XML Material Profiles", "description": "Provides capabilities to read and write XML-based material profiles.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -736,8 +804,8 @@ "package_type": "plugin", "display_name": "X-Ray View", "description": "Provides the X-Ray view.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://ultimaker.com", "author": { "author_id": "UltimakerPackages", @@ -753,8 +821,8 @@ "package_type": "material", "display_name": "Generic ABS", "description": "The generic ABS profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -771,8 +839,8 @@ "package_type": "material", "display_name": "Generic BAM", "description": "The generic BAM profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -789,8 +857,8 @@ "package_type": "material", "display_name": "Generic CFF CPE", "description": "The generic CFF CPE profile which other profiles can be based upon.", - "package_version": "1.1.0", - "sdk_version": 5, + "package_version": "1.1.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -807,8 +875,8 @@ "package_type": "material", "display_name": "Generic CFF PA", "description": "The generic CFF PA profile which other profiles can be based upon.", - "package_version": "1.1.0", - "sdk_version": 5, + "package_version": "1.1.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -825,8 +893,8 @@ "package_type": "material", "display_name": "Generic CPE", "description": "The generic CPE profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -843,8 +911,8 @@ "package_type": "material", "display_name": "Generic CPE+", "description": "The generic CPE+ profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -861,8 +929,8 @@ "package_type": "material", "display_name": "Generic GFF CPE", "description": "The generic GFF CPE profile which other profiles can be based upon.", - "package_version": "1.1.0", - "sdk_version": 5, + "package_version": "1.1.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -879,8 +947,8 @@ "package_type": "material", "display_name": "Generic GFF PA", "description": "The generic GFF PA profile which other profiles can be based upon.", - "package_version": "1.1.0", - "sdk_version": 5, + "package_version": "1.1.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -897,8 +965,8 @@ "package_type": "material", "display_name": "Generic HIPS", "description": "The generic HIPS profile which other profiles can be based upon.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -915,8 +983,8 @@ "package_type": "material", "display_name": "Generic Nylon", "description": "The generic Nylon profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -933,8 +1001,8 @@ "package_type": "material", "display_name": "Generic PC", "description": "The generic PC profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -951,8 +1019,8 @@ "package_type": "material", "display_name": "Generic PETG", "description": "The generic PETG profile which other profiles can be based upon.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -969,8 +1037,8 @@ "package_type": "material", "display_name": "Generic PLA", "description": "The generic PLA profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -987,8 +1055,8 @@ "package_type": "material", "display_name": "Generic PP", "description": "The generic PP profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -1005,8 +1073,8 @@ "package_type": "material", "display_name": "Generic PVA", "description": "The generic PVA profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -1023,8 +1091,8 @@ "package_type": "material", "display_name": "Generic Tough PLA", "description": "The generic Tough PLA profile which other profiles can be based upon.", - "package_version": "1.0.1", - "sdk_version": 5, + "package_version": "1.0.2", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -1041,8 +1109,8 @@ "package_type": "material", "display_name": "Generic TPU", "description": "The generic TPU profile which other profiles can be based upon.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://github.com/Ultimaker/fdm_materials", "author": { "author_id": "Generic", @@ -1059,8 +1127,8 @@ "package_type": "material", "display_name": "Dagoma Chromatik PLA", "description": "Filament testé et approuvé pour les imprimantes 3D Dagoma. Chromatik est l'idéal pour débuter et suivre les tutoriels premiers pas. Il vous offre qualité et résistance pour chacune de vos impressions.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://dagoma.fr/boutique/filaments.html", "author": { "author_id": "Dagoma", @@ -1076,8 +1144,8 @@ "package_type": "material", "display_name": "FABtotum ABS", "description": "This material is easy to be extruded but it is not the simplest to use. It is one of the most used in 3D printing to get very well finished objects. It is not sustainable and its smoke can be dangerous if inhaled. The reason to prefer this filament to PLA is mainly because of its precision and mechanical specs. ABS (for plastic) stands for Acrylonitrile Butadiene Styrene and it is a thermoplastic which is widely used in everyday objects. It can be printed with any FFF 3D printer which can get to high temperatures as it must be extruded in a range between 220° and 245°, so it’s compatible with all versions of the FABtotum Personal fabricator.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=40", "author": { "author_id": "FABtotum", @@ -1093,8 +1161,8 @@ "package_type": "material", "display_name": "FABtotum Nylon", "description": "When 3D printing started this material was not listed among the extrudable filaments. It is flexible as well as resistant to tractions. It is well known for its uses in textile but also in industries which require a strong and flexible material. There are different kinds of Nylon: 3D printing mostly uses Nylon 6 and Nylon 6.6, which are the most common. It requires higher temperatures to be printed, so a 3D printer must be able to reach them (around 240°C): the FABtotum, of course, can.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=53", "author": { "author_id": "FABtotum", @@ -1110,8 +1178,8 @@ "package_type": "material", "display_name": "FABtotum PLA", "description": "It is the most common filament used for 3D printing. It is studied to be bio-degradable as it comes from corn starch’s sugar mainly. It is completely made of renewable sources and has no footprint on polluting. PLA stands for PolyLactic Acid and it is a thermoplastic that today is still considered the easiest material to be 3D printed. It can be extruded at lower temperatures: the standard range of FABtotum’s one is between 185° and 195°.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=39", "author": { "author_id": "FABtotum", @@ -1127,8 +1195,8 @@ "package_type": "material", "display_name": "FABtotum TPU Shore 98A", "description": "", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://store.fabtotum.com/eu/products/filaments.html?filament_type=66", "author": { "author_id": "FABtotum", @@ -1144,8 +1212,8 @@ "package_type": "material", "display_name": "Fiberlogy HD PLA", "description": "With our HD PLA you have many more options. You can use this material in two ways. Choose the one you like best. You can use it as a normal PLA and get prints characterized by a very good adhesion between the layers and high precision. You can also make your prints acquire similar properties to that of ABS – better impact resistance and high temperature resistance. All you need is an oven. Yes, an oven! By annealing our HD PLA in an oven, in accordance with the manual, you will avoid all the inconveniences of printing with ABS, such as unpleasant odour or hazardous fumes.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "http://fiberlogy.com/en/fiberlogy-filaments/filament-hd-pla/", "author": { "author_id": "Fiberlogy", @@ -1161,8 +1229,8 @@ "package_type": "material", "display_name": "Filo3D PLA", "description": "Fast, safe and reliable printing. PLA is ideal for the fast and reliable printing of parts and prototypes with a great surface quality.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://dagoma.fr", "author": { "author_id": "Dagoma", @@ -1178,8 +1246,8 @@ "package_type": "material", "display_name": "IMADE3D JellyBOX PETG", "description": "", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "http://shop.imade3d.com/filament.html", "author": { "author_id": "IMADE3D", @@ -1195,8 +1263,8 @@ "package_type": "material", "display_name": "IMADE3D JellyBOX PLA", "description": "", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "http://shop.imade3d.com/filament.html", "author": { "author_id": "IMADE3D", @@ -1212,8 +1280,8 @@ "package_type": "material", "display_name": "Octofiber PLA", "description": "PLA material from Octofiber.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://nl.octofiber.com/3d-printing-filament/pla.html", "author": { "author_id": "Octofiber", @@ -1229,8 +1297,8 @@ "package_type": "material", "display_name": "PolyFlex™ PLA", "description": "PolyFlex™ is a highly flexible yet easy to print 3D printing material. Featuring good elasticity and a large strain-to- failure, PolyFlex™ opens up a completely new realm of applications.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "http://www.polymaker.com/shop/polyflex/", "author": { "author_id": "Polymaker", @@ -1246,8 +1314,8 @@ "package_type": "material", "display_name": "PolyMax™ PLA", "description": "PolyMax™ PLA is a 3D printing material with excellent mechanical properties and printing quality. PolyMax™ PLA has an impact resistance of up to nine times that of regular PLA, and better overall mechanical properties than ABS.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "http://www.polymaker.com/shop/polymax/", "author": { "author_id": "Polymaker", @@ -1263,8 +1331,8 @@ "package_type": "material", "display_name": "PolyPlus™ PLA True Colour", "description": "PolyPlus™ PLA is a premium PLA designed for all desktop FDM/FFF 3D printers. It is produced with our patented Jam-Free™ technology that ensures consistent extrusion and prevents jams.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "http://www.polymaker.com/shop/polyplus-true-colour/", "author": { "author_id": "Polymaker", @@ -1280,8 +1348,8 @@ "package_type": "material", "display_name": "PolyWood™ PLA", "description": "PolyWood™ is a wood mimic printing material that contains no actual wood ensuring a clean Jam-Free™ printing experience.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "http://www.polymaker.com/shop/polywood/", "author": { "author_id": "Polymaker", @@ -1297,8 +1365,8 @@ "package_type": "material", "display_name": "Ultimaker ABS", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/abs", "author": { "author_id": "UltimakerPackages", @@ -1316,8 +1384,8 @@ "package_type": "material", "display_name": "Ultimaker Breakaway", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/breakaway", "author": { "author_id": "UltimakerPackages", @@ -1335,8 +1403,8 @@ "package_type": "material", "display_name": "Ultimaker CPE", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/abs", "author": { "author_id": "UltimakerPackages", @@ -1354,8 +1422,8 @@ "package_type": "material", "display_name": "Ultimaker CPE+", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/cpe", "author": { "author_id": "UltimakerPackages", @@ -1373,8 +1441,8 @@ "package_type": "material", "display_name": "Ultimaker Nylon", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/abs", "author": { "author_id": "UltimakerPackages", @@ -1392,8 +1460,8 @@ "package_type": "material", "display_name": "Ultimaker PC", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.2", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/pc", "author": { "author_id": "UltimakerPackages", @@ -1411,8 +1479,8 @@ "package_type": "material", "display_name": "Ultimaker PLA", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/abs", "author": { "author_id": "UltimakerPackages", @@ -1430,8 +1498,8 @@ "package_type": "material", "display_name": "Ultimaker PP", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/pp", "author": { "author_id": "UltimakerPackages", @@ -1449,8 +1517,8 @@ "package_type": "material", "display_name": "Ultimaker PVA", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/abs", "author": { "author_id": "UltimakerPackages", @@ -1468,8 +1536,8 @@ "package_type": "material", "display_name": "Ultimaker TPU 95A", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.2.0", - "sdk_version": 5, + "package_version": "1.2.1", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/tpu-95a", "author": { "author_id": "UltimakerPackages", @@ -1487,8 +1555,8 @@ "package_type": "material", "display_name": "Ultimaker Tough PLA", "description": "Example package for material and quality profiles for Ultimaker materials.", - "package_version": "1.0.2", - "sdk_version": 5, + "package_version": "1.0.3", + "sdk_version": "6.0", "website": "https://ultimaker.com/products/materials/tough-pla", "author": { "author_id": "UltimakerPackages", @@ -1506,8 +1574,8 @@ "package_type": "material", "display_name": "Vertex Delta ABS", "description": "ABS material and quality files for the Delta Vertex K8800.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://vertex3dprinter.eu", "author": { "author_id": "Velleman", @@ -1523,8 +1591,8 @@ "package_type": "material", "display_name": "Vertex Delta PET", "description": "ABS material and quality files for the Delta Vertex K8800.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://vertex3dprinter.eu", "author": { "author_id": "Velleman", @@ -1540,8 +1608,8 @@ "package_type": "material", "display_name": "Vertex Delta PLA", "description": "ABS material and quality files for the Delta Vertex K8800.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://vertex3dprinter.eu", "author": { "author_id": "Velleman", @@ -1557,8 +1625,8 @@ "package_type": "material", "display_name": "Vertex Delta TPU", "description": "ABS material and quality files for the Delta Vertex K8800.", - "package_version": "1.0.0", - "sdk_version": 5, + "package_version": "1.0.1", + "sdk_version": "6.0", "website": "https://vertex3dprinter.eu", "author": { "author_id": "Velleman", @@ -1568,4 +1636,4 @@ } } } -} +} \ No newline at end of file diff --git a/resources/definitions/alfawise_u20.def.json b/resources/definitions/alfawise_u20.def.json new file mode 100644 index 0000000000..de8525fa4d --- /dev/null +++ b/resources/definitions/alfawise_u20.def.json @@ -0,0 +1,93 @@ +{ + "name": "Alfawise U20", + "version": 2, + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "Samuel Pinches", + "manufacturer": "Alfawise", + "file_formats": "text/x-gcode", + "preferred_quality_type": "fast", + "machine_extruder_trains": + { + "0": "alfawise_u20_extruder_0" + } + }, + "overrides": { + "machine_name": { + "default_value": "Alfawise U20" + }, + "machine_start_gcode": { + "default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --" + }, + "machine_end_gcode": { + "default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nM140 S0 ;turn off bed heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 ;move to the X-axis origin (Home)\nG0 Y280 F600 ;bring the bed to the front for easy print removal\nM84 ;turn off stepper motors\n; -- end of END GCODE --" + }, + "machine_width": { + "default_value": 300 + }, + "machine_height": { + "default_value": 400 + }, + "machine_depth": { + "default_value": 300 + }, + "machine_heated_bed": { + "default_value": true + }, + "machine_center_is_zero": { + "default_value": false + }, + "gantry_height": { + "default_value": 10 + }, + "machine_gcode_flavor": { + "default_value": "RepRap (Marlin/Sprinter)" + }, + "material_diameter": { + "default_value": 1.75 + }, + "material_print_temperature": { + "default_value": 210 + }, + "material_bed_temperature": { + "default_value": 50 + }, + "layer_height_0": { + "default_value": 0.2 + }, + "wall_thickness": { + "default_value": 1.2 + }, + "speed_print": { + "default_value": 40 + }, + "speed_infill": { + "default_value": 40 + }, + "speed_wall": { + "default_value": 35 + }, + "speed_topbottom": { + "default_value": 35 + }, + "speed_travel": { + "default_value": 120 + }, + "speed_layer_0": { + "default_value": 20 + }, + "support_enable": { + "default_value": true + }, + "retraction_enable": { + "default_value": true + }, + "retraction_amount": { + "default_value": 5 + }, + "retraction_speed": { + "default_value": 45 + } + } +} diff --git a/resources/definitions/bibo2_dual.def.json b/resources/definitions/bibo2_dual.def.json new file mode 100644 index 0000000000..2036290ebd --- /dev/null +++ b/resources/definitions/bibo2_dual.def.json @@ -0,0 +1,92 @@ +{ + "id": "BIBO2 dual", + "version": 2, + "name": "BIBO2 dual", + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "na", + "manufacturer": "BIBO", + "category": "Other", + "file_formats": "text/x-gcode", + "has_materials": true, + "machine_extruder_trains": { + "0": "bibo2_dual_extruder_0", + "1": "bibo2_dual_extruder_1" + }, + "first_start_actions": [ + "MachineSettingsAction" + ] + }, + "overrides": { + "machine_name": { + "default_value": "BIBO2 dual" + }, + "machine_width": { + "default_value": 214 + }, + "machine_height": { + "default_value": 160 + }, + "machine_depth": { + "default_value": 186 + }, + "machine_center_is_zero": { + "default_value": true + }, + "machine_heated_bed": { + "default_value": true + }, + "machine_nozzle_heat_up_speed": { + "default_value": 2 + }, + "machine_nozzle_cool_down_speed": { + "default_value": 2 + }, + "machine_head_with_fans_polygon": { + "default_value": [ + [ + -68.18, + 64.63 + ], + [ + -68.18, + -47.38 + ], + [ + 35.18, + 64.63 + ], + [ + 35.18, + -47.38 + ] + ] + }, + "gantry_height": { + "default_value": 12 + }, + "machine_use_extruder_offset_to_offset_coords": { + "default_value": true + }, + "machine_gcode_flavor": { + "default_value": "RepRap (Marlin/Sprinter)" + }, + "machine_start_gcode": { + "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z2.0 F400 ;move the platform down 15mm\nT0\nG92 E0\nG28\nG1 Y0 F1200 E0\nG92 E0\nM117 BIBO Printing..." + }, + "machine_end_gcode": { + "default_value": ";End GCode\nM104 T0 S0 ;extruder heater off\nM104 T1 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91\nG1 Z1 F100 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-2 X-20 Y-20 F300 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" + }, + "machine_extruder_count": { + "default_value": 2 + }, + "prime_tower_position_x": { + "default_value": 50 + }, + "prime_tower_position_y": { + "default_value": 50 + } + } +} + diff --git a/resources/definitions/cocoon_create_modelmaker.def.json b/resources/definitions/cocoon_create_modelmaker.def.json new file mode 100644 index 0000000000..22aa75d09e --- /dev/null +++ b/resources/definitions/cocoon_create_modelmaker.def.json @@ -0,0 +1,96 @@ +{ + "name": "Cocoon Create ModelMaker", + "version": 2, + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "Samuel Pinches", + "manufacturer": "Cocoon Create", + "file_formats": "text/x-gcode", + "preferred_quality_type": "fine", + "machine_extruder_trains": + { + "0": "cocoon_create_modelmaker_extruder_0" + } + }, + "overrides": { + "machine_name": { + "default_value": "Cocoon Create ModelMaker" + }, + "machine_start_gcode": { + "default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --" + }, + "machine_end_gcode": { + "default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 Y0 ;move to the XY-axis origin (Home)\nM84 ;turn off stepper motors\n; -- end of END GCODE --" + }, + "machine_width": { + "default_value": 120 + }, + "machine_height": { + "default_value": 100 + }, + "machine_depth": { + "default_value": 135 + }, + "machine_heated_bed": { + "default_value": false + }, + "machine_center_is_zero": { + "default_value": false + }, + "gantry_height": { + "default_value": 10 + }, + "machine_gcode_flavor": { + "default_value": "RepRap (Marlin/Sprinter)" + }, + "material_diameter": { + "default_value": 1.75 + }, + "material_print_temperature": { + "default_value": 220 + }, + "layer_height": { + "default_value": 0.10 + }, + "layer_height_0": { + "default_value": 0.2 + }, + "wall_thickness": { + "default_value": 1.2 + }, + "top_bottom_thickness": { + "default_value": 0.6 + }, + "speed_print": { + "default_value": 40 + }, + "speed_infill": { + "default_value": 40 + }, + "speed_wall": { + "default_value": 35 + }, + "speed_topbottom": { + "default_value": 35 + }, + "speed_travel": { + "default_value": 70 + }, + "speed_layer_0": { + "default_value": 20 + }, + "support_enable": { + "default_value": true + }, + "retraction_enable": { + "default_value": true + }, + "retraction_amount": { + "default_value": 7 + }, + "retraction_speed": { + "default_value": 40 + } + } +} diff --git a/resources/definitions/fdmextruder.def.json b/resources/definitions/fdmextruder.def.json index 19c9e92d18..0af1e68075 100644 --- a/resources/definitions/fdmextruder.def.json +++ b/resources/definitions/fdmextruder.def.json @@ -78,7 +78,7 @@ "machine_extruder_start_code": { "label": "Extruder Start G-Code", - "description": "Start g-code to execute whenever turning the extruder on.", + "description": "Start g-code to execute when switching to this extruder.", "type": "str", "default_value": "", "settable_per_mesh": false, @@ -124,7 +124,7 @@ "machine_extruder_end_code": { "label": "Extruder End G-Code", - "description": "End g-code to execute whenever turning the extruder off.", + "description": "End g-code to execute when switching away from this extruder.", "type": "str", "default_value": "", "settable_per_mesh": false, @@ -189,7 +189,7 @@ "settable_per_mesh": false, "settable_per_extruder": true, "settable_per_meshgroup": false, - "setttable_globally": false + "settable_globally": false } } }, diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 7cb6720f27..f39e267354 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2406,7 +2406,7 @@ "switch_extruder_retraction_amount": { "label": "Nozzle Switch Retraction Distance", - "description": "The amount of retraction: Set at 0 for no retraction at all. This should generally be the same as the length of the heat zone.", + "description": "The amount of retraction when switching extruders. Set to 0 for no retraction at all. This should generally be the same as the length of the heat zone.", "type": "float", "unit": "mm", "enabled": "retraction_enable", @@ -3385,7 +3385,7 @@ "retraction_combing": { "label": "Combing Mode", - "description": "Combing keeps the nozzle within already printed areas when traveling. This results in slightly longer travel moves but reduces the need for retractions. If combing is off, the material will retract and the nozzle moves in a straight line to the next point. It is also possible to avoid combing over top/bottom skin areas and also to only comb within the infill. Note that the 'Within Infill' option behaves exactly like the 'Not in Skin' option in earlier Cura releases.", + "description": "Combing keeps the nozzle within already printed areas when traveling. This results in slightly longer travel moves but reduces the need for retractions. If combing is off, the material will retract and the nozzle moves in a straight line to the next point. It is also possible to avoid combing over top/bottom skin areas or to only comb within the infill.", "type": "enum", "options": { diff --git a/resources/definitions/gmax15plus.def.json b/resources/definitions/gmax15plus.def.json index 16695714f4..069b8be999 100644 --- a/resources/definitions/gmax15plus.def.json +++ b/resources/definitions/gmax15plus.def.json @@ -14,19 +14,24 @@ "has_variants": true, "variants_name": "Hotend", "preferred_variant_name": "0.5mm E3D (Default)", + "preferred_quality_type": "gmax15plus_global_normal", "machine_extruder_trains": { "0": "gmax15plus_extruder_0" } + + }, "overrides": { - "machine_extruder_count": { "default_value": 1 }, + "machine_extruder_count": { "default_value": 1 }, "machine_name": { "default_value": "gMax 1.5 Plus" }, "machine_heated_bed": { "default_value": false }, "machine_width": { "default_value": 406 }, "machine_depth": { "default_value": 406 }, "machine_height": { "default_value": 533 }, "machine_center_is_zero": { "default_value": false }, + "material_diameter": { "default_value": 1.75 }, + "machine_nozzle_size": { "default_value": 0.5 }, "layer_height": { "default_value": 0.2 }, "layer_height_0": { "default_value": 0.3 }, "retraction_amount": { "default_value": 1 }, @@ -43,10 +48,10 @@ "machine_max_jerk_z": { "default_value": 0.4 }, "machine_max_jerk_e": { "default_value": 5.0 }, "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, - "machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 ;Home X/Y/Z\nG29 ; Bed level\nM104 S{material_print_temperature} ; Preheat\nM109 S{material_print_temperature} ; Preheat\nG91 ;relative positioning\nG90 ;absolute positioning\nG1 Z25.0 F9000 ;raise nozzle 25mm\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." }, + "machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 ;Home X/Y/Z\nM104 S{material_print_temperature} ; Preheat\nM109 S{material_print_temperature} ; Preheat\nG91 ;relative positioning\nG90 ;absolute positioning\nG1 Z25.0 F9000 ;raise nozzle 25mm\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." }, "machine_end_gcode": { "default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" }, - "material_print_temperature": { "default_value": 202 }, - "wall_thickness": { "default_value": 1 }, + "material_print_temperature": { "default_value": 202 }, + "wall_thickness": { "default_value": 1 }, "top_bottom_thickness": { "default_value": 1 }, "bottom_thickness": { "default_value": 1 } } diff --git a/resources/definitions/gmax15plus_dual.def.json b/resources/definitions/gmax15plus_dual.def.json index 5972061933..0264ef5977 100644 --- a/resources/definitions/gmax15plus_dual.def.json +++ b/resources/definitions/gmax15plus_dual.def.json @@ -10,24 +10,26 @@ "category": "Other", "file_formats": "text/x-gcode", "platform": "gmax_1-5_xt-plus_s3d_full model_150707.stl", - "has_variants": true, - "has_machine_quality": true, - "variants_name": "Hotend", - "preferred_variant_name": "0.5mm E3D (Default)", - "machine_extruder_trains": { - "0": "gmax15plus_dual_extruder_0", - "1": "gmax15plus_dual_extruder_1" - } + "has_variants": true, + "variants_name": "Hotend", + "preferred_variant_name": "0.5mm E3D (Default)", + "preferred_quality_type": "gmax15plus_global_dual_normal", + "machine_extruder_trains": { + "0": "gmax15plus_dual_extruder_0", + "1": "gmax15plus_dual_extruder_1" + } }, "overrides": { "machine_name": { "default_value": "gMax 1.5 Plus Dual Extruder" }, - "machine_extruder_count": { "default_value": 2 }, + "machine_extruder_count": { "default_value": 2 }, "machine_heated_bed": { "default_value": false }, "machine_width": { "default_value": 406 }, "machine_depth": { "default_value": 406 }, "machine_height": { "default_value": 533 }, "machine_center_is_zero": { "default_value": false }, + "material_diameter": { "default_value": 1.75 }, + "machine_nozzle_size": { "default_value": 0.5 }, "layer_height": { "default_value": 0.2 }, "layer_height_0": { "default_value": 0.3 }, "retraction_amount": { "default_value": 1 }, @@ -44,10 +46,10 @@ "machine_max_jerk_z": { "default_value": 0.4 }, "machine_max_jerk_e": { "default_value": 5.0 }, "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" }, - "machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 ;Home X/Y/Z\nG29 ; Bed level\nM104 S{material_print_temperature} T0 ; Preheat Left Extruder\nM104 S{material_print_temperature} T1 ; Preheat Right Extruder\nM109 S{material_print_temperature} T0 ; Preheat Left Extruder\nM109 S{material_print_temperature} T1 ; Preheat Right Extruder\nG91 ;relative positioning\nG90 ;absolute positioning\nM218 T1 X34.3 Y0; Set 2nd extruder offset. This can be changed later if needed\nG1 Z25.0 F9000 ;raise nozzle 25mm\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." }, + "machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 ;Home X/Y/Z\nM104 S{material_print_temperature} T0 ; Preheat Left Extruder\nM104 S{material_print_temperature} T1 ; Preheat Right Extruder\nM109 S{material_print_temperature} T0 ; Preheat Left Extruder\nM109 S{material_print_temperature} T1 ; Preheat Right Extruder\nG91 ;relative positioning\nG90 ;absolute positioning\nM218 T1 X34.3 Y0; Set 2nd extruder offset. This can be changed later if needed\nG1 Z25.0 F9000 ;raise nozzle 25mm\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." }, "machine_end_gcode": { "default_value": "M104 S0 T0;Left extruder off\nM104 S0 T1; Right extruder off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" }, - "material_print_temperature": { "default_value": 202 }, - "wall_thickness": { "default_value": 1 }, + "material_print_temperature": { "default_value": 202 }, + "wall_thickness": { "default_value": 1 }, "top_bottom_thickness": { "default_value": 1 }, "bottom_thickness": { "default_value": 1 } } diff --git a/resources/definitions/jgaurora_a1.def.json b/resources/definitions/jgaurora_a1.def.json new file mode 100644 index 0000000000..b9a921c311 --- /dev/null +++ b/resources/definitions/jgaurora_a1.def.json @@ -0,0 +1,93 @@ +{ + "name": "JGAurora A1", + "version": 2, + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "Samuel Pinches", + "manufacturer": "JGAurora", + "file_formats": "text/x-gcode", + "preferred_quality_type": "fast", + "machine_extruder_trains": + { + "0": "jgaurora_a1_extruder_0" + } + }, + "overrides": { + "machine_name": { + "default_value": "JGAurora A1" + }, + "machine_start_gcode": { + "default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nM420 S1 ;turn on mesh bed levelling if enabled in firmware\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --" + }, + "machine_end_gcode": { + "default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nM140 S0 ;turn off bed heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 ;move to the X-axis origin (Home)\nG0 Y280 F600 ;bring the bed to the front for easy print removal\nM84 ;turn off stepper motors\n; -- end of END GCODE --" + }, + "machine_width": { + "default_value": 300 + }, + "machine_height": { + "default_value": 300 + }, + "machine_depth": { + "default_value": 300 + }, + "machine_heated_bed": { + "default_value": true + }, + "machine_center_is_zero": { + "default_value": false + }, + "gantry_height": { + "default_value": 10 + }, + "machine_gcode_flavor": { + "default_value": "RepRap (Marlin/Sprinter)" + }, + "material_diameter": { + "default_value": 1.75 + }, + "material_print_temperature": { + "default_value": 215 + }, + "material_bed_temperature": { + "default_value": 67 + }, + "layer_height_0": { + "default_value": 0.12 + }, + "wall_thickness": { + "default_value": 1.2 + }, + "speed_print": { + "default_value": 40 + }, + "speed_infill": { + "default_value": 40 + }, + "speed_wall": { + "default_value": 35 + }, + "speed_topbottom": { + "default_value": 35 + }, + "speed_travel": { + "default_value": 120 + }, + "speed_layer_0": { + "default_value": 12 + }, + "support_enable": { + "default_value": true + }, + "retraction_enable": { + "default_value": true + }, + "retraction_amount": { + "default_value": 6 + }, + "retraction_speed": { + "default_value": 40 + } + } +} diff --git a/resources/definitions/jgaurora_a5.def.json b/resources/definitions/jgaurora_a5.def.json new file mode 100644 index 0000000000..d84a8440e6 --- /dev/null +++ b/resources/definitions/jgaurora_a5.def.json @@ -0,0 +1,95 @@ +{ + "name": "JGAurora A5 & A5S", + "version": 2, + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "Samuel Pinches", + "manufacturer": "JGAurora", + "file_formats": "text/x-gcode", + "platform": "jgaurora_a5.stl", + "platform_offset": [-242, -101, 273], + "preferred_quality_type": "fast", + "machine_extruder_trains": + { + "0": "jgaurora_a5_extruder_0" + } + }, + "overrides": { + "machine_name": { + "default_value": "JGAurora A5 & A5S" + }, + "machine_start_gcode": { + "default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nM420 S1 ;turn on mesh bed levelling if enabled in firmware\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --" + }, + "machine_end_gcode": { + "default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nM140 S0 ;turn off bed heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 ;move to the X-axis origin (Home)\nG0 Y280 F600 ;bring the bed to the front for easy print removal\nM84 ;turn off stepper motors\n; -- end of END GCODE --" + }, + "machine_width": { + "default_value": 300 + }, + "machine_height": { + "default_value": 320 + }, + "machine_depth": { + "default_value": 300 + }, + "machine_heated_bed": { + "default_value": true + }, + "machine_center_is_zero": { + "default_value": false + }, + "gantry_height": { + "default_value": 10 + }, + "machine_gcode_flavor": { + "default_value": "RepRap (Marlin/Sprinter)" + }, + "material_diameter": { + "default_value": 1.75 + }, + "material_print_temperature": { + "default_value": 215 + }, + "material_bed_temperature": { + "default_value": 67 + }, + "layer_height_0": { + "default_value": 0.12 + }, + "wall_thickness": { + "default_value": 1.2 + }, + "speed_print": { + "default_value": 40 + }, + "speed_infill": { + "default_value": 40 + }, + "speed_wall": { + "default_value": 35 + }, + "speed_topbottom": { + "default_value": 35 + }, + "speed_travel": { + "default_value": 120 + }, + "speed_layer_0": { + "default_value": 12 + }, + "support_enable": { + "default_value": true + }, + "retraction_enable": { + "default_value": true + }, + "retraction_amount": { + "default_value": 8 + }, + "retraction_speed": { + "default_value": 45 + } + } +} diff --git a/resources/definitions/jgaurora_z_603s.def.json b/resources/definitions/jgaurora_z_603s.def.json new file mode 100644 index 0000000000..3a78585240 --- /dev/null +++ b/resources/definitions/jgaurora_z_603s.def.json @@ -0,0 +1,93 @@ +{ + "name": "JGAurora Z-603S", + "version": 2, + "inherits": "fdmprinter", + "metadata": { + "visible": true, + "author": "Samuel Pinches", + "manufacturer": "JGAurora", + "file_formats": "text/x-gcode", + "preferred_quality_type": "fast", + "machine_extruder_trains": + { + "0": "jgaurora_z_603s_extruder_0" + } + }, + "overrides": { + "machine_name": { + "default_value": "JGAurora Z-603S" + }, + "machine_start_gcode": { + "default_value": "; -- START GCODE --\nG21 ;set units to millimetres\nG90 ;set to absolute positioning\nM106 S0 ;set fan speed to zero (turned off)\nG28 ;home all axis\nM420 S1 ;turn on mesh bed levelling if enabled in firmware\nG92 E0 ;zero the extruded length\nG1 Z1 F1000 ;move up slightly\nG1 X60.0 Z0 E9.0 F1000.0;intro line\nG1 X100.0 E21.5 F1000.0 ;continue line\nG92 E0 ;zero the extruded length again\n; -- end of START GCODE --" + }, + "machine_end_gcode": { + "default_value": "; -- END GCODE --\nM104 S0 ;turn off nozzle heater\nM140 S0 ;turn off bed heater\nG91 ;set to relative positioning\nG1 E-10 F300 ;retract the filament slightly\nG90 ;set to absolute positioning\nG28 X0 ;move to the X-axis origin (Home)\nG0 Y280 F600 ;bring the bed to the front for easy print removal\nM84 ;turn off stepper motors\n; -- end of END GCODE --" + }, + "machine_width": { + "default_value": 280 + }, + "machine_height": { + "default_value": 175 + }, + "machine_depth": { + "default_value": 180 + }, + "machine_heated_bed": { + "default_value": true + }, + "machine_center_is_zero": { + "default_value": false + }, + "gantry_height": { + "default_value": 10 + }, + "machine_gcode_flavor": { + "default_value": "RepRap (Marlin/Sprinter)" + }, + "material_diameter": { + "default_value": 1.75 + }, + "material_print_temperature": { + "default_value": 210 + }, + "material_bed_temperature": { + "default_value": 55 + }, + "layer_height_0": { + "default_value": 0.2 + }, + "wall_thickness": { + "default_value": 1.2 + }, + "speed_print": { + "default_value": 60 + }, + "speed_infill": { + "default_value": 60 + }, + "speed_wall": { + "default_value": 30 + }, + "speed_topbottom": { + "default_value": 45 + }, + "speed_travel": { + "default_value": 125 + }, + "speed_layer_0": { + "default_value": 20 + }, + "support_enable": { + "default_value": true + }, + "retraction_enable": { + "default_value": true + }, + "retraction_amount": { + "default_value": 5 + }, + "retraction_speed": { + "default_value": 50 + } + } +} diff --git a/resources/definitions/tevo_tarantula.def.json b/resources/definitions/tevo_tarantula.def.json index 570ae24a3d..ec4ae667d5 100644 --- a/resources/definitions/tevo_tarantula.def.json +++ b/resources/definitions/tevo_tarantula.def.json @@ -42,7 +42,7 @@ "machine_max_feedrate_x": { "default_value": 255 }, "machine_max_feedrate_y": { "default_value": 225 }, "machine_max_feedrate_z": { "default_value": 3 }, - "machine_max_acceleration_x": { "default_value": 2620 }, + "machine_max_acceleration_x": { "default_value": 2650 }, "machine_max_acceleration_y": { "default_value": 2650 }, "acceleration_print": { "default_value": 2650 }, "machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." }, diff --git a/resources/definitions/ultimaker_original_plus.def.json b/resources/definitions/ultimaker_original_plus.def.json index 5ad7ae66e8..bdb8a3d788 100644 --- a/resources/definitions/ultimaker_original_plus.def.json +++ b/resources/definitions/ultimaker_original_plus.def.json @@ -16,7 +16,8 @@ { "0": "ultimaker_original_plus_extruder_0" }, - "firmware_file": "MarlinUltimaker-UMOP-{baudrate}.hex" + "firmware_file": "MarlinUltimaker-UMOP-{baudrate}.hex", + "firmware_hbk_file": "MarlinUltimaker-UMOP-{baudrate}.hex" }, "overrides": { diff --git a/resources/definitions/wanhao_d4s.def.json b/resources/definitions/wanhao_d4s.def.json index 8788353e92..c1807923c6 100644 --- a/resources/definitions/wanhao_d4s.def.json +++ b/resources/definitions/wanhao_d4s.def.json @@ -39,10 +39,10 @@ "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..." + "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..." }, "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" + "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" } } } diff --git a/resources/definitions/wanhao_d6.def.json b/resources/definitions/wanhao_d6.def.json index 7ca3031124..c8a690d02c 100644 --- a/resources/definitions/wanhao_d6.def.json +++ b/resources/definitions/wanhao_d6.def.json @@ -42,10 +42,10 @@ "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..." + "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..." }, "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" + "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" } } } diff --git a/resources/definitions/wanhao_d6_plus.def.json b/resources/definitions/wanhao_d6_plus.def.json index f17b58db85..b3b5ed9b0a 100644 --- a/resources/definitions/wanhao_d6_plus.def.json +++ b/resources/definitions/wanhao_d6_plus.def.json @@ -39,10 +39,10 @@ "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..." + "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..." }, "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" + "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" } } } diff --git a/resources/definitions/wanhao_duplicator5S.def.json b/resources/definitions/wanhao_duplicator5S.def.json index 1d29b90249..b27a13fda8 100644 --- a/resources/definitions/wanhao_duplicator5S.def.json +++ b/resources/definitions/wanhao_duplicator5S.def.json @@ -42,10 +42,10 @@ "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..." + "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..." }, "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" + "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" } } } diff --git a/resources/definitions/wanhao_duplicator5Smini.def.json b/resources/definitions/wanhao_duplicator5Smini.def.json index e7f9359cf1..e3ef0b92fe 100644 --- a/resources/definitions/wanhao_duplicator5Smini.def.json +++ b/resources/definitions/wanhao_duplicator5Smini.def.json @@ -39,10 +39,10 @@ "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..." + "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..." }, "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" + "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" } } } diff --git a/resources/definitions/wanhao_i3.def.json b/resources/definitions/wanhao_i3.def.json index 15121f8b8b..42b19c8748 100644 --- a/resources/definitions/wanhao_i3.def.json +++ b/resources/definitions/wanhao_i3.def.json @@ -39,10 +39,10 @@ "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..." + "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..." }, "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" + "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" } } } diff --git a/resources/definitions/wanhao_i3mini.def.json b/resources/definitions/wanhao_i3mini.def.json index 057fca81a6..0c70391c27 100644 --- a/resources/definitions/wanhao_i3mini.def.json +++ b/resources/definitions/wanhao_i3mini.def.json @@ -39,10 +39,10 @@ "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..." + "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..." }, "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" + "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" } } } diff --git a/resources/definitions/wanhao_i3plus.def.json b/resources/definitions/wanhao_i3plus.def.json index 2b705c6ff5..e454a40ae1 100644 --- a/resources/definitions/wanhao_i3plus.def.json +++ b/resources/definitions/wanhao_i3plus.def.json @@ -39,10 +39,10 @@ "default_value": "RepRap (Marlin/Sprinter)" }, "machine_start_gcode": { - "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{travel_speed} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{travel_speed} \n ;Put printing message on LCD screen\n M117 Printing..." + "default_value": "G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X/Y to min endstops\n G28 Z0 ;move Z to min endstops\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E6 ;extrude 6 mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel} \n ;Put printing message on LCD screen\n M117 Printing..." }, "machine_end_gcode": { - "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" + "default_value": "M104 S0 ;extruder heater off \n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning" } } } diff --git a/resources/extruders/alfawise_u20_extruder_0.def.json b/resources/extruders/alfawise_u20_extruder_0.def.json new file mode 100644 index 0000000000..2fbe3f1772 --- /dev/null +++ b/resources/extruders/alfawise_u20_extruder_0.def.json @@ -0,0 +1,16 @@ +{ + "id": "alfawise_u20_extruder_0", + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "alfawise_u20", + "position": "0" + }, + + "overrides": { + "extruder_nr": { "default_value": 0 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "material_diameter": { "default_value": 1.75 } + } +} \ No newline at end of file diff --git a/resources/extruders/bibo2_dual_extruder_0.def.json b/resources/extruders/bibo2_dual_extruder_0.def.json new file mode 100644 index 0000000000..f83801fa0c --- /dev/null +++ b/resources/extruders/bibo2_dual_extruder_0.def.json @@ -0,0 +1,46 @@ +{ + "id": "BIBO1", + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "BIBO2 dual", + "position": "0" + }, + "overrides": { + "extruder_nr": { + "default_value": 0, + "maximum_value": "1" + }, + "material_diameter": { + "default_value": 1.75 + }, + "machine_nozzle_size": { + "default_value": 0.4 + }, + "machine_nozzle_offset_x": { + "default_value": 0.0 + }, + "machine_nozzle_offset_y": { + "default_value": 0.0 + }, + "machine_extruder_start_pos_abs": { + "default_value": true + }, + "machine_extruder_start_pos_x": { + "value": "prime_tower_position_x" + }, + "machine_extruder_start_pos_y": { + "value": "prime_tower_position_y" + }, + "machine_extruder_end_pos_abs": { + "default_value": true + }, + "machine_extruder_end_pos_x": { + "value": "prime_tower_position_x" + }, + "machine_extruder_end_pos_y": { + "value": "prime_tower_position_y" + } + } +} diff --git a/resources/extruders/bibo2_dual_extruder_1.def.json b/resources/extruders/bibo2_dual_extruder_1.def.json new file mode 100644 index 0000000000..5f479ba54b --- /dev/null +++ b/resources/extruders/bibo2_dual_extruder_1.def.json @@ -0,0 +1,46 @@ +{ + "id": "BIBO2", + "version": 2, + "name": "Extruder 2", + "inherits": "fdmextruder", + "metadata": { + "machine": "BIBO2 dual", + "position": "1" + }, + "overrides": { + "extruder_nr": { + "default_value": 1, + "maximum_value": "1" + }, + "material_diameter": { + "default_value": 1.75 + }, + "machine_nozzle_size": { + "default_value": 0.4 + }, + "machine_nozzle_offset_x": { + "default_value": 0.0 + }, + "machine_nozzle_offset_y": { + "default_value": 0.0 + }, + "machine_extruder_start_pos_abs": { + "default_value": true + }, + "machine_extruder_start_pos_x": { + "value": "prime_tower_position_x" + }, + "machine_extruder_start_pos_y": { + "value": "prime_tower_position_y" + }, + "machine_extruder_end_pos_abs": { + "default_value": true + }, + "machine_extruder_end_pos_x": { + "value": "prime_tower_position_x" + }, + "machine_extruder_end_pos_y": { + "value": "prime_tower_position_y" + } + } +} diff --git a/resources/extruders/cocoon_create_modelmaker_extruder_0.def.json b/resources/extruders/cocoon_create_modelmaker_extruder_0.def.json new file mode 100644 index 0000000000..26d847483d --- /dev/null +++ b/resources/extruders/cocoon_create_modelmaker_extruder_0.def.json @@ -0,0 +1,16 @@ +{ + "id": "cocoon_create_modelmaker_extruder_0", + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "cocoon_create_modelmaker", + "position": "0" + }, + + "overrides": { + "extruder_nr": { "default_value": 0 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "material_diameter": { "default_value": 1.75 } + } +} diff --git a/resources/extruders/gmax15plus_dual_extruder_0.def.json b/resources/extruders/gmax15plus_dual_extruder_0.def.json index b490f4a40e..d3146a0576 100644 --- a/resources/extruders/gmax15plus_dual_extruder_0.def.json +++ b/resources/extruders/gmax15plus_dual_extruder_0.def.json @@ -15,10 +15,10 @@ }, "machine_nozzle_offset_x": { "default_value": 0.0 }, "machine_nozzle_offset_y": { "default_value": 0.0 }, - "machine_nozzle_size": { "default_value": 0.5 }, + "machine_nozzle_size": { "default_value": 0.5 }, "material_diameter": { "default_value": 1.75 }, - - "machine_extruder_start_pos_abs": { "default_value": true }, + + "machine_extruder_start_pos_abs": { "default_value": true }, "machine_extruder_start_pos_x": { "value": 40 }, "machine_extruder_start_pos_y": { "value": 210 }, "machine_extruder_end_pos_abs": { "default_value": true }, diff --git a/resources/extruders/gmax15plus_dual_extruder_1.def.json b/resources/extruders/gmax15plus_dual_extruder_1.def.json index ad3c628d6f..7b7354d794 100644 --- a/resources/extruders/gmax15plus_dual_extruder_1.def.json +++ b/resources/extruders/gmax15plus_dual_extruder_1.def.json @@ -15,10 +15,10 @@ }, "machine_nozzle_offset_x": { "default_value": 0.0 }, "machine_nozzle_offset_y": { "default_value": 0.0 }, - "machine_nozzle_size": { "default_value": 0.5 }, + "machine_nozzle_size": { "default_value": 0.5 }, "material_diameter": { "default_value": 1.75 }, - - "machine_extruder_start_pos_abs": { "default_value": true }, + + "machine_extruder_start_pos_abs": { "default_value": true }, "machine_extruder_start_pos_x": { "value": 40 }, "machine_extruder_start_pos_y": { "value": 210 }, "machine_extruder_end_pos_abs": { "default_value": true }, diff --git a/resources/extruders/jgaurora_a1_extruder_0.def.json b/resources/extruders/jgaurora_a1_extruder_0.def.json new file mode 100644 index 0000000000..71742b734a --- /dev/null +++ b/resources/extruders/jgaurora_a1_extruder_0.def.json @@ -0,0 +1,16 @@ +{ + "id": "jgaurora_a1_extruder_0", + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "jgaurora_a1", + "position": "0" + }, + + "overrides": { + "extruder_nr": { "default_value": 0 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "material_diameter": { "default_value": 1.75 } + } +} diff --git a/resources/extruders/jgaurora_a5_extruder_0.def.json b/resources/extruders/jgaurora_a5_extruder_0.def.json new file mode 100644 index 0000000000..fbc6ba77e6 --- /dev/null +++ b/resources/extruders/jgaurora_a5_extruder_0.def.json @@ -0,0 +1,16 @@ +{ + "id": "jgaurora_a5_extruder_0", + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "jgaurora_a5", + "position": "0" + }, + + "overrides": { + "extruder_nr": { "default_value": 0 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "material_diameter": { "default_value": 1.75 } + } +} diff --git a/resources/extruders/jgaurora_z_603s_extruder_0.def.json b/resources/extruders/jgaurora_z_603s_extruder_0.def.json new file mode 100644 index 0000000000..987425b28a --- /dev/null +++ b/resources/extruders/jgaurora_z_603s_extruder_0.def.json @@ -0,0 +1,16 @@ +{ + "id": "jgaurora_z_603s_extruder_0", + "version": 2, + "name": "Extruder 1", + "inherits": "fdmextruder", + "metadata": { + "machine": "jgaurora_z_603s", + "position": "0" + }, + + "overrides": { + "extruder_nr": { "default_value": 0 }, + "machine_nozzle_size": { "default_value": 0.4 }, + "material_diameter": { "default_value": 1.75 } + } +} diff --git a/resources/meshes/jgaurora_a5.stl b/resources/meshes/jgaurora_a5.stl new file mode 100644 index 0000000000..c525b03649 Binary files /dev/null and b/resources/meshes/jgaurora_a5.stl differ diff --git a/resources/qml/AboutDialog.qml b/resources/qml/AboutDialog.qml deleted file mode 100644 index 9a7e53260b..0000000000 --- a/resources/qml/AboutDialog.qml +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2015 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.Window 2.1 - -import UM 1.1 as UM - -UM.Dialog -{ - id: base - - //: About dialog title - title: catalog.i18nc("@title:window","About Cura") - - minimumWidth: 500 * screenScaleFactor - minimumHeight: 650 * screenScaleFactor - width: minimumWidth - height: minimumHeight - - Rectangle - { - width: parent.width + 2 * margin // margin from Dialog.qml - height: version.y + version.height + margin - - anchors.top: parent.top - anchors.topMargin: - margin - anchors.horizontalCenter: parent.horizontalCenter - - color: UM.Theme.getColor("viewport_background") - } - - Image - { - id: logo - width: (base.minimumWidth * 0.85) | 0 - height: (width * (1/4.25)) | 0 - - source: UM.Theme.getImage("logo") - - sourceSize.width: width - sourceSize.height: height - anchors.top: parent.top - anchors.topMargin: ((base.minimumWidth - width) / 2) | 0 - anchors.horizontalCenter: parent.horizontalCenter - - UM.I18nCatalog{id: catalog; name:"cura"} - } - - Label - { - id: version - - text: catalog.i18nc("@label","version: %1").arg(UM.Application.version) - font: UM.Theme.getFont("large") - color: UM.Theme.getColor("text") - anchors.right : logo.right - anchors.top: logo.bottom - anchors.topMargin: (UM.Theme.getSize("default_margin").height / 2) | 0 - } - - Label - { - id: description - width: parent.width - - //: About dialog application description - text: catalog.i18nc("@label","End-to-end solution for fused filament 3D printing.") - font: UM.Theme.getFont("system") - wrapMode: Text.WordWrap - anchors.top: version.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height - } - - Label - { - id: creditsNotes - width: parent.width - - //: About dialog application author note - text: catalog.i18nc("@info:credit","Cura is developed by Ultimaker B.V. in cooperation with the community.\nCura proudly uses the following open source projects:") - font: UM.Theme.getFont("system") - wrapMode: Text.WordWrap - anchors.top: description.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height - } - - ScrollView - { - id: credits - anchors.top: creditsNotes.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height - - width: parent.width - height: base.height - y - (2 * UM.Theme.getSize("default_margin").height + closeButton.height) - - ListView - { - id: projectsList - - width: parent.width - - delegate: Row - { - Label - { - text: "%2".arg(model.url).arg(model.name) - width: (projectsList.width * 0.25) | 0 - elide: Text.ElideRight - onLinkActivated: Qt.openUrlExternally(link) - } - Label - { - text: model.description - elide: Text.ElideRight - width: (projectsList.width * 0.6) | 0 - } - Label - { - text: model.license - elide: Text.ElideRight - width: (projectsList.width * 0.15) | 0 - } - } - model: ListModel - { - id: projectsModel - } - Component.onCompleted: - { - projectsModel.append({ name:"Cura", description: catalog.i18nc("@label", "Graphical user interface"), license: "LGPLv3", url: "https://github.com/Ultimaker/Cura" }); - projectsModel.append({ name:"Uranium", description: catalog.i18nc("@label", "Application framework"), license: "LGPLv3", url: "https://github.com/Ultimaker/Uranium" }); - projectsModel.append({ name:"CuraEngine", description: catalog.i18nc("@label", "G-code generator"), license: "AGPLv3", url: "https://github.com/Ultimaker/CuraEngine" }); - projectsModel.append({ name:"libArcus", description: catalog.i18nc("@label", "Interprocess communication library"), license: "LGPLv3", url: "https://github.com/Ultimaker/libArcus" }); - - projectsModel.append({ name:"Python", description: catalog.i18nc("@label", "Programming language"), license: "Python", url: "http://python.org/" }); - projectsModel.append({ name:"Qt5", description: catalog.i18nc("@label", "GUI framework"), license: "LGPLv3", url: "https://www.qt.io/" }); - projectsModel.append({ name:"PyQt", description: catalog.i18nc("@label", "GUI framework bindings"), license: "GPL", url: "https://riverbankcomputing.com/software/pyqt" }); - projectsModel.append({ name:"SIP", description: catalog.i18nc("@label", "C/C++ Binding library"), license: "GPL", url: "https://riverbankcomputing.com/software/sip" }); - projectsModel.append({ name:"Protobuf", description: catalog.i18nc("@label", "Data interchange format"), license: "BSD", url: "https://developers.google.com/protocol-buffers" }); - projectsModel.append({ name:"SciPy", description: catalog.i18nc("@label", "Support library for scientific computing"), license: "BSD-new", url: "https://www.scipy.org/" }); - projectsModel.append({ name:"NumPy", description: catalog.i18nc("@label", "Support library for faster math"), license: "BSD", url: "http://www.numpy.org/" }); - projectsModel.append({ name:"NumPy-STL", description: catalog.i18nc("@label", "Support library for handling STL files"), license: "BSD", url: "https://github.com/WoLpH/numpy-stl" }); - projectsModel.append({ name:"Shapely", description: catalog.i18nc("@label", "Support library for handling planar objects"), license: "BSD", url: "https://github.com/Toblerity/Shapely" }); - projectsModel.append({ name:"Trimesh", description: catalog.i18nc("@label", "Support library for handling triangular meshes"), license: "MIT", url: "https://trimsh.org" }); - projectsModel.append({ name:"NetworkX", description: catalog.i18nc("@label", "Support library for analysis of complex networks"), license: "3-clause BSD", url: "https://networkx.github.io/" }); - projectsModel.append({ name:"libSavitar", description: catalog.i18nc("@label", "Support library for handling 3MF files"), license: "LGPLv3", url: "https://github.com/ultimaker/libsavitar" }); - projectsModel.append({ name:"libCharon", description: catalog.i18nc("@label", "Support library for file metadata and streaming"), license: "LGPLv3", url: "https://github.com/ultimaker/libcharon" }); - projectsModel.append({ name:"PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" }); - projectsModel.append({ name:"python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" }); - projectsModel.append({ name:"Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" }); - projectsModel.append({ name:"Requests", description: catalog.i18nc("@Label", "Python HTTP library"), license: "GPL", url: "http://docs.python-requests.org" }); - - projectsModel.append({ name:"Noto Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://www.google.com/get/noto/" }); - projectsModel.append({ name:"Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" }); - projectsModel.append({ name:"AppImageKit", description: catalog.i18nc("@label", "Linux cross-distribution application deployment"), license: "MIT", url: "https://github.com/AppImage/AppImageKit" }); - } - } - } - - rightButtons: Button - { - //: Close about dialog button - id: closeButton - text: catalog.i18nc("@action:button","Close"); - - onClicked: base.visible = false; - } -} diff --git a/resources/qml/Account/AccountDetails.qml b/resources/qml/Account/AccountDetails.qml new file mode 100644 index 0000000000..45f822e41f --- /dev/null +++ b/resources/qml/Account/AccountDetails.qml @@ -0,0 +1,69 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 + +import UM 1.4 as UM +import Cura 1.1 as Cura + +Column +{ + property var profile: null + property var loggedIn: false + property var profileImage: "" + + padding: UM.Theme.getSize("wide_margin").height + spacing: UM.Theme.getSize("wide_margin").height + + AvatarImage + { + id: avatar + width: UM.Theme.getSize("avatar_image").width + height: UM.Theme.getSize("avatar_image").height + anchors.horizontalCenter: parent.horizontalCenter + source: + { + if(loggedIn) + { + if(profileImage) + { + return profileImage + } + return UM.Theme.getImage("avatar_no_user") + } + return UM.Theme.getImage("avatar_no_user") + } + outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining") + } + + Label + { + id: information + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + renderType: Text.NativeRendering + text: loggedIn ? profile["username"] : catalog.i18nc("@label", "Please log in or create an account to\nenjoy all features of Ultimaker Cura.") + font: loggedIn ? UM.Theme.getFont("large_bold") : UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + } + + Loader + { + id: accountOperations + anchors.horizontalCenter: parent.horizontalCenter + sourceComponent: loggedIn ? userOperations : generalOperations + } + + Component + { + id: userOperations + UserOperations { } + } + + Component + { + id: generalOperations + GeneralOperations { } + } +} \ No newline at end of file diff --git a/resources/qml/Account/AccountWidget.qml b/resources/qml/Account/AccountWidget.qml new file mode 100644 index 0000000000..d3bd6fd130 --- /dev/null +++ b/resources/qml/Account/AccountWidget.qml @@ -0,0 +1,76 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 + +import UM 1.4 as UM +import Cura 1.1 as Cura + +Button +{ + id: accountWidget + property var profile: Cura.API.account.userProfile + property var loggedIn: Cura.API.account.isLoggedIn + + implicitHeight: UM.Theme.getSize("main_window_header").height + implicitWidth: UM.Theme.getSize("main_window_header").height + + background: AvatarImage + { + id: avatar + + width: Math.round(0.8 * accountWidget.width) + height: Math.round(0.8 * accountWidget.height) + anchors.verticalCenter: accountWidget.verticalCenter + anchors.horizontalCenter: accountWidget.horizontalCenter + + source: + { + if(loggedIn) + { + if(profile["profile_image_url"]) + { + return profile["profile_image_url"] + } + return UM.Theme.getImage("avatar_no_user") + } + return UM.Theme.getImage("avatar_no_user") + } + outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining") + } + + onClicked: popup.opened ? popup.close() : popup.open() + + Popup + { + id: popup + + y: parent.height + UM.Theme.getSize("default_arrow").height + x: parent.width - width + + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent + + opacity: opened ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + + contentItem: AccountDetails + { + id: panel + profile: Cura.API.account.userProfile + loggedIn: Cura.API.account.isLoggedIn + profileImage: Cura.API.account.profileImageUrl + } + + background: UM.PointingRectangle + { + color: UM.Theme.getColor("tool_panel_background") + borderColor: UM.Theme.getColor("lining") + borderWidth: UM.Theme.getSize("default_lining").width + + target: Qt.point(width - (accountWidget.width / 2), -10) + + arrowSize: UM.Theme.getSize("default_arrow").width + } + } +} diff --git a/resources/qml/Account/AvatarImage.qml b/resources/qml/Account/AvatarImage.qml new file mode 100644 index 0000000000..b76aff6990 --- /dev/null +++ b/resources/qml/Account/AvatarImage.qml @@ -0,0 +1,56 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtGraphicalEffects 1.0 + +import UM 1.4 as UM + +Item +{ + // This item shows the provided image while applying a round mask to it. + // It also shows a round border around it. The color is defined by the outlineColor property. + + id: avatar + + property alias source: profileImage.source + property alias outlineColor: profileImageOutline.color + + Image + { + id: profileImage + anchors.fill: parent + source: UM.Theme.getImage("avatar_default") + fillMode: Image.PreserveAspectCrop + visible: false + mipmap: true + } + + Rectangle + { + id: profileImageMask + anchors.fill: parent + radius: width + } + + OpacityMask + { + anchors.fill: parent + source: profileImage + maskSource: profileImageMask + cached: true + } + + UM.RecolorImage + { + id: profileImageOutline + anchors.centerIn: parent + // Make it a bit bigger than it has to, otherwise it sometimes shows a white border. + width: parent.width + 2 + height: parent.height + 2 + source: UM.Theme.getIcon("circle_outline") + sourceSize: Qt.size(parent.width, parent.height) + color: UM.Theme.getColor("account_widget_ouline_active") + } +} \ No newline at end of file diff --git a/resources/qml/Account/GeneralOperations.qml b/resources/qml/Account/GeneralOperations.qml new file mode 100644 index 0000000000..b9f1025d5e --- /dev/null +++ b/resources/qml/Account/GeneralOperations.qml @@ -0,0 +1,31 @@ +// 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 UM 1.4 as UM +import Cura 1.1 as Cura + +Row +{ + spacing: UM.Theme.getSize("default_margin").width + + Cura.SecondaryButton + { + width: UM.Theme.getSize("account_button").width + height: UM.Theme.getSize("account_button").height + text: catalog.i18nc("@button", "Create account") + onClicked: Qt.openUrlExternally("https://account.ultimaker.com/app/create") + fixedWidthMode: true + } + + Cura.PrimaryButton + { + width: UM.Theme.getSize("account_button").width + height: UM.Theme.getSize("account_button").height + text: catalog.i18nc("@button", "Login") + onClicked: Cura.API.account.login() + fixedWidthMode: true + } +} \ No newline at end of file diff --git a/resources/qml/Account/UserOperations.qml b/resources/qml/Account/UserOperations.qml new file mode 100644 index 0000000000..b9ffa395d6 --- /dev/null +++ b/resources/qml/Account/UserOperations.qml @@ -0,0 +1,31 @@ +// 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 UM 1.4 as UM +import Cura 1.1 as Cura + +Row +{ + spacing: UM.Theme.getSize("default_margin").width + + Cura.SecondaryButton + { + width: UM.Theme.getSize("account_button").width + height: UM.Theme.getSize("account_button").height + text: catalog.i18nc("@button", "Manage account") + onClicked: Qt.openUrlExternally("https://account.ultimaker.com") + fixedWidthMode: true + } + + Cura.PrimaryButton + { + width: UM.Theme.getSize("account_button").width + height: UM.Theme.getSize("account_button").height + text: catalog.i18nc("@button", "Logout") + onClicked: Cura.API.account.logout() + fixedWidthMode: true + } +} \ No newline at end of file diff --git a/resources/qml/ActionButton.qml b/resources/qml/ActionButton.qml new file mode 100644 index 0000000000..fabdcebc64 --- /dev/null +++ b/resources/qml/ActionButton.qml @@ -0,0 +1,134 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtGraphicalEffects 1.0 // For the dropshadow + +import UM 1.1 as UM +import Cura 1.0 as Cura + + +Button +{ + id: button + property bool isIconOnRightSide: false + + property alias iconSource: buttonIconLeft.source + property alias textFont: buttonText.font + property alias cornerRadius: backgroundRect.radius + property alias tooltip: tooltip.tooltipText + property alias cornerSide: backgroundRect.cornerSide + + property color color: UM.Theme.getColor("primary") + property color hoverColor: UM.Theme.getColor("primary_hover") + property color disabledColor: color + property color textColor: UM.Theme.getColor("button_text") + property color textHoverColor: textColor + property color textDisabledColor: textColor + property color outlineColor: color + property color outlineHoverColor: hoverColor + property color outlineDisabledColor: outlineColor + property alias shadowColor: shadow.color + property alias shadowEnabled: shadow.visible + property alias busy: busyIndicator.visible + + property alias toolTipContentAlignment: tooltip.contentAlignment + + // This property is used to indicate whether the button has a fixed width or the width would depend on the contents + // Be careful when using fixedWidthMode, the translated texts can be too long that they won't fit. In any case, + // we elide the text to the right so the text will be cut off with the three dots at the end. + property var fixedWidthMode: false + + leftPadding: UM.Theme.getSize("default_margin").width + rightPadding: UM.Theme.getSize("default_margin").width + height: UM.Theme.getSize("action_button").height + hoverEnabled: true + + contentItem: Row + { + spacing: UM.Theme.getSize("narrow_margin").width + //Left side icon. Only displayed if !isIconOnRightSide. + UM.RecolorImage + { + id: buttonIconLeft + source: "" + height: UM.Theme.getSize("action_button_icon").height + width: visible ? height : 0 + sourceSize.width: width + sourceSize.height: height + color: button.enabled ? (button.hovered ? button.textHoverColor : button.textColor) : button.textDisabledColor + visible: source != "" && !button.isIconOnRightSide + anchors.verticalCenter: parent.verticalCenter + } + + Label + { + id: buttonText + text: button.text + color: button.enabled ? (button.hovered ? button.textHoverColor : button.textColor): button.textDisabledColor + font: UM.Theme.getFont("medium") + visible: text != "" + renderType: Text.NativeRendering + anchors.verticalCenter: parent.verticalCenter + width: fixedWidthMode ? button.width - button.leftPadding - button.rightPadding : undefined + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + } + + //Right side icon. Only displayed if isIconOnRightSide. + UM.RecolorImage + { + id: buttonIconRight + source: buttonIconLeft.source + height: UM.Theme.getSize("action_button_icon").height + width: visible ? height : 0 + sourceSize.width: width + sourceSize.height: height + color: buttonIconLeft.color + visible: source != "" && button.isIconOnRightSide + anchors.verticalCenter: buttonIconLeft.verticalCenter + } + } + + background: Cura.RoundedRectangle + { + id: backgroundRect + cornerSide: Cura.RoundedRectangle.Direction.All + color: button.enabled ? (button.hovered ? button.hoverColor : button.color) : button.disabledColor + radius: UM.Theme.getSize("action_button_radius").width + border.width: UM.Theme.getSize("default_lining").width + border.color: button.enabled ? (button.hovered ? button.outlineHoverColor : button.outlineColor) : button.outlineDisabledColor + } + + DropShadow + { + id: shadow + // Don't blur the shadow + radius: 0 + anchors.fill: backgroundRect + source: backgroundRect + verticalOffset: 2 + visible: false + // Should always be drawn behind the background. + z: backgroundRect.z - 1 + } + + Cura.ToolTip + { + id: tooltip + visible: button.hovered + } + + BusyIndicator + { + id: busyIndicator + + anchors.centerIn: parent + + width: height + height: parent.height + + visible: false + } +} \ No newline at end of file diff --git a/resources/qml/ActionPanel/ActionPanelWidget.qml b/resources/qml/ActionPanel/ActionPanelWidget.qml new file mode 100644 index 0000000000..1d9ee95548 --- /dev/null +++ b/resources/qml/ActionPanel/ActionPanelWidget.qml @@ -0,0 +1,56 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + + +// This element hold all the elements needed for the user to trigger the slicing process, and later +// to get information about the printing times, material consumption and the output process (such as +// saving to a file, printing over network, ... +Rectangle +{ + id: actionPanelWidget + + width: UM.Theme.getSize("action_panel_widget").width + height: childrenRect.height + 2 * UM.Theme.getSize("thick_margin").height + + color: UM.Theme.getColor("main_background") + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + radius: UM.Theme.getSize("default_radius").width + z: 10 + + property bool outputAvailable: UM.Backend.state == UM.Backend.Done || UM.Backend.state == UM.Backend.Disabled + + Loader + { + id: loader + anchors + { + top: parent.top + topMargin: UM.Theme.getSize("thick_margin").height + left: parent.left + leftMargin: UM.Theme.getSize("thick_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("thick_margin").width + } + sourceComponent: outputAvailable ? outputProcessWidget : sliceProcessWidget + } + + Component + { + id: sliceProcessWidget + SliceProcessWidget { } + } + + Component + { + id: outputProcessWidget + OutputProcessWidget { } + } +} \ No newline at end of file diff --git a/resources/qml/ActionPanel/OutputDevicesActionButton.qml b/resources/qml/ActionPanel/OutputDevicesActionButton.qml new file mode 100644 index 0000000000..3bfaab0fc1 --- /dev/null +++ b/resources/qml/ActionPanel/OutputDevicesActionButton.qml @@ -0,0 +1,112 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 + +import UM 1.1 as UM +import Cura 1.0 as Cura + +Item +{ + id: widget + + function requestWriteToDevice() + { + UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName, + { "filter_by_machine": true, "preferred_mimetypes": Cura.MachineManager.activeMachine.preferred_output_file_formats }); + } + + Cura.PrimaryButton + { + id: saveToButton + height: parent.height + fixedWidthMode: true + cornerSide: deviceSelectionMenu.visible ? Cura.RoundedRectangle.Direction.Left : Cura.RoundedRectangle.Direction.All + + anchors + { + top: parent.top + left: parent.left + right: deviceSelectionMenu.visible ? deviceSelectionMenu.left : parent.right + } + + tooltip: UM.OutputDeviceManager.activeDeviceDescription + + text: UM.OutputDeviceManager.activeDeviceShortDescription + + onClicked: + { + forceActiveFocus() + widget.requestWriteToDevice() + } + } + + Cura.ActionButton + { + id: deviceSelectionMenu + height: parent.height + + shadowEnabled: true + shadowColor: UM.Theme.getColor("primary_shadow") + cornerSide: Cura.RoundedRectangle.Direction.Right + + anchors + { + top: parent.top + right: parent.right + } + + leftPadding: UM.Theme.getSize("narrow_margin").width //Need more space than usual here for wide text. + rightPadding: UM.Theme.getSize("narrow_margin").width + iconSource: popup.opened ? UM.Theme.getIcon("arrow_top") : UM.Theme.getIcon("arrow_bottom") + color: UM.Theme.getColor("action_panel_secondary") + visible: (devicesModel.deviceCount > 1) + + onClicked: popup.opened ? popup.close() : popup.open() + + Popup + { + id: popup + padding: 0 + + y: -height + x: parent.width - width + + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent + + contentItem: ColumnLayout + { + Repeater + { + model: devicesModel + + delegate: Cura.ActionButton + { + text: model.description + visible: model.id != UM.OutputDeviceManager.activeDevice // Don't show the active device in the list + color: "transparent" + cornerRadius: 0 + hoverColor: UM.Theme.getColor("primary") + Layout.fillWidth: true + onClicked: + { + UM.OutputDeviceManager.setActiveDevice(model.id) + popup.close() + } + } + } + } + + background: Rectangle + { + opacity: visible ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + color: UM.Theme.getColor("action_panel_secondary") + } + } + } + + UM.OutputDevicesModel { id: devicesModel } +} \ No newline at end of file diff --git a/resources/qml/ActionPanel/OutputProcessWidget.qml b/resources/qml/ActionPanel/OutputProcessWidget.qml new file mode 100644 index 0000000000..63974d7f34 --- /dev/null +++ b/resources/qml/ActionPanel/OutputProcessWidget.qml @@ -0,0 +1,135 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 + +import UM 1.1 as UM +import Cura 1.0 as Cura + + +// This element contains all the elements the user needs to visualize the data +// that is gather after the slicing process, such as printint time, material usage, ... +// There are also two buttons: one to previsualize the output layers, and the other to +// select what to do with it (such as print over network, save to file, ...) +Column +{ + id: widget + + spacing: UM.Theme.getSize("thin_margin").height + property bool preSlicedData: PrintInformation.preSliced + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + Item + { + id: information + width: parent.width + height: childrenRect.height + + PrintInformationWidget + { + id: printInformationPanel + visible: !preSlicedData + anchors.right: parent.right + } + + Column + { + id: timeAndCostsInformation + spacing: UM.Theme.getSize("thin_margin").height + + anchors + { + left: parent.left + right: parent.right + } + + Cura.IconWithText + { + id: estimatedTime + width: parent.width + + text: preSlicedData ? catalog.i18nc("@label", "No time estimation available") : PrintInformation.currentPrintTime.getDisplayString(UM.DurationFormat.Long) + source: UM.Theme.getIcon("clock") + font: UM.Theme.getFont("medium_bold") + } + + Cura.IconWithText + { + id: estimatedCosts + width: parent.width + + property var printMaterialLengths: PrintInformation.materialLengths + property var printMaterialWeights: PrintInformation.materialWeights + + text: + { + if (preSlicedData) + { + return catalog.i18nc("@label", "No cost estimation available") + } + var totalLengths = 0 + var totalWeights = 0 + if (printMaterialLengths) + { + for(var index = 0; index < printMaterialLengths.length; index++) + { + if(printMaterialLengths[index] > 0) + { + totalLengths += printMaterialLengths[index] + totalWeights += Math.round(printMaterialWeights[index]) + } + } + } + return totalWeights + "g · " + totalLengths.toFixed(2) + "m" + } + source: UM.Theme.getIcon("spool") + } + } + } + + Item + { + id: buttonRow + anchors.right: parent.right + anchors.left: parent.left + height: UM.Theme.getSize("action_button").height + + Cura.SecondaryButton + { + id: previewStageShortcut + + anchors + { + left: parent.left + right: outputDevicesButton.left + rightMargin: UM.Theme.getSize("default_margin").width + } + + height: UM.Theme.getSize("action_button").height + text: catalog.i18nc("@button", "Preview") + tooltip: text + fixedWidthMode: true + + toolTipContentAlignment: Cura.ToolTip.ContentAlignment.AlignLeft + + onClicked: UM.Controller.setActiveStage("PreviewStage") + visible: UM.Controller.activeStage != null && UM.Controller.activeStage.stageId != "PreviewStage" + } + + Cura.OutputDevicesActionButton + { + id: outputDevicesButton + + anchors.right: parent.right + width: previewStageShortcut.visible ? UM.Theme.getSize("action_button").width : parent.width + height: UM.Theme.getSize("action_button").height + } + } +} \ No newline at end of file diff --git a/resources/qml/ActionPanel/PrintInformationWidget.qml b/resources/qml/ActionPanel/PrintInformationWidget.qml new file mode 100644 index 0000000000..2e108b05d7 --- /dev/null +++ b/resources/qml/ActionPanel/PrintInformationWidget.qml @@ -0,0 +1,58 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 + +import UM 1.1 as UM +import Cura 1.0 as Cura + +UM.RecolorImage +{ + id: widget + + source: UM.Theme.getIcon("info") + width: visible ? UM.Theme.getSize("section_icon").width : 0 + height: UM.Theme.getSize("section_icon").height + + color: UM.Theme.getColor("icon") + + MouseArea + { + anchors.fill: parent + hoverEnabled: true + onEntered: popup.open() + onExited: popup.close() + } + + Popup + { + id: popup + + y: -(height + UM.Theme.getSize("default_arrow").height + UM.Theme.getSize("thin_margin").height) + x: parent.width - width + UM.Theme.getSize("thin_margin").width + + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent + + opacity: opened ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } + + contentItem: PrintJobInformation + { + id: printJobInformation + width: UM.Theme.getSize("action_panel_information_widget").width + } + + background: UM.PointingRectangle + { + color: UM.Theme.getColor("tool_panel_background") + borderColor: UM.Theme.getColor("lining") + borderWidth: UM.Theme.getSize("default_lining").width + + target: Qt.point(width - (widget.width / 2) - UM.Theme.getSize("thin_margin").width, + height + UM.Theme.getSize("default_arrow").height - UM.Theme.getSize("thin_margin").height) + + arrowSize: UM.Theme.getSize("default_arrow").width + } + } +} \ No newline at end of file diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml new file mode 100644 index 0000000000..8bd5d5a0d3 --- /dev/null +++ b/resources/qml/ActionPanel/PrintJobInformation.qml @@ -0,0 +1,159 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 + +import UM 1.1 as UM +import Cura 1.0 as Cura + +Column +{ + id: base + spacing: UM.Theme.getSize("default_margin").width + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + Column + { + id: timeSpecification + width: parent.width + topPadding: UM.Theme.getSize("default_margin").height + leftPadding: UM.Theme.getSize("default_margin").width + rightPadding: UM.Theme.getSize("default_margin").width + + Label + { + text: catalog.i18nc("@label", "Time specification").toUpperCase() + color: UM.Theme.getColor("primary") + font: UM.Theme.getFont("default_bold") + renderType: Text.NativeRendering + } + + Label + { + property var printDuration: PrintInformation.currentPrintTime + + text: + { + // All the time information for the different features is achieved + var printTime = PrintInformation.getFeaturePrintTimes() + var totalSeconds = parseInt(printDuration.getDisplayString(UM.DurationFormat.Seconds)) + + // A message is created and displayed when the user hover the time label + var text = "" + for(var feature in printTime) + { + if(!printTime[feature].isTotalDurationZero) + { + text += "" + + "".arg(printTime[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)) + + "".arg(Math.round(100 * parseInt(printTime[feature].getDisplayString(UM.DurationFormat.Seconds)) / totalSeconds)) + + "" + } + } + text += "
" + feature + ":  %1  %1%
" + return text + } + width: parent.width - 2 * UM.Theme.getSize("default_margin").width + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + textFormat: Text.RichText + } + } + + Column + { + id: materialSpecification + width: parent.width + bottomPadding: UM.Theme.getSize("default_margin").height + leftPadding: UM.Theme.getSize("default_margin").width + rightPadding: UM.Theme.getSize("default_margin").width + + Label + { + text: catalog.i18nc("@label", "Material specification").toUpperCase() + color: UM.Theme.getColor("primary") + font: UM.Theme.getFont("default_bold") + renderType: Text.NativeRendering + } + + Label + { + property var printMaterialLengths: PrintInformation.materialLengths + property var printMaterialWeights: PrintInformation.materialWeights + property var printMaterialCosts: PrintInformation.materialCosts + property var printMaterialNames: PrintInformation.materialNames + + function formatRow(items) + { + var rowHTML = "" + for(var item = 0; item < items.length; item++) + { + if (item == 0) + { + rowHTML += "%1".arg(items[item]) + } + else + { + rowHTML += "  %1".arg(items[item]) + } + } + rowHTML += "" + return rowHTML + } + + text: + { + var lengths = [] + var weights = [] + var costs = [] + var names = [] + if(printMaterialLengths) + { + for(var index = 0; index < printMaterialLengths.length; index++) + { + if(printMaterialLengths[index] > 0) + { + names.push(printMaterialNames[index]) + lengths.push(printMaterialLengths[index].toFixed(2)) + weights.push(String(Math.round(printMaterialWeights[index]))) + var cost = printMaterialCosts[index] == undefined ? 0 : printMaterialCosts[index].toFixed(2) + costs.push(cost) + } + } + } + if(lengths.length == 0) + { + lengths = ["0.00"] + weights = ["0"] + costs = ["0.00"] + } + + var text = "" + for(var index = 0; index < lengths.length; index++) + { + text += formatRow([ + "%1:".arg(names[index]), + catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]), + catalog.i18nc("@label g for grams", "%1g").arg(weights[index]), + "%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]), + ]) + } + text += "
" + + return text + } + width: parent.width - 2 * UM.Theme.getSize("default_margin").width + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + textFormat: Text.RichText + } + } +} \ No newline at end of file diff --git a/resources/qml/ActionPanel/SliceProcessWidget.qml b/resources/qml/ActionPanel/SliceProcessWidget.qml new file mode 100644 index 0000000000..08966ce82c --- /dev/null +++ b/resources/qml/ActionPanel/SliceProcessWidget.qml @@ -0,0 +1,169 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 1.4 as Controls1 + +import UM 1.1 as UM +import Cura 1.0 as Cura + + +// This element contains all the elements the user needs to create a printjob from the +// model(s) that is(are) on the buildplate. Mainly the button to start/stop the slicing +// process and a progress bar to see the progress of the process. +Column +{ + id: widget + + spacing: UM.Theme.getSize("thin_margin").height + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + property real progress: UM.Backend.progress + property int backendState: UM.Backend.state + + function sliceOrStopSlicing() + { + if (widget.backendState == UM.Backend.NotStarted) + { + CuraApplication.backend.forceSlice() + } + else + { + CuraApplication.backend.stopSlicing() + } + } + + Label + { + id: autoSlicingLabel + width: parent.width + visible: progressBar.visible + + text: catalog.i18nc("@label:PrintjobStatus", "Slicing...") + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + } + + Cura.IconWithText + { + id: unableToSliceMessage + width: parent.width + visible: widget.backendState == UM.Backend.Error + + text: catalog.i18nc("@label:PrintjobStatus", "Unable to Slice") + source: UM.Theme.getIcon("warning") + iconColor: UM.Theme.getColor("warning") + } + + // Progress bar, only visible when the backend is in the process of slice the printjob + ProgressBar + { + id: progressBar + width: parent.width + height: UM.Theme.getSize("progressbar").height + value: progress + indeterminate: widget.backendState == UM.Backend.NotStarted + visible: (widget.backendState == UM.Backend.Processing || (prepareButtons.autoSlice && widget.backendState == UM.Backend.NotStarted)) + + background: Rectangle + { + anchors.fill: parent + radius: UM.Theme.getSize("progressbar_radius").width + color: UM.Theme.getColor("progressbar_background") + } + + contentItem: Item + { + anchors.fill: parent + Rectangle + { + width: progressBar.visualPosition * parent.width + height: parent.height + radius: UM.Theme.getSize("progressbar_radius").width + color: UM.Theme.getColor("progressbar_control") + } + } + } + + Item + { + id: prepareButtons + // Get the current value from the preferences + property bool autoSlice: UM.Preferences.getValue("general/auto_slice") + // Disable the slice process when + + width: parent.width + height: UM.Theme.getSize("action_button").height + visible: !autoSlice + Cura.PrimaryButton + { + id: sliceButton + fixedWidthMode: true + + height: parent.height + + anchors.right: parent.right + anchors.left: parent.left + + text: catalog.i18nc("@button", "Slice") + tooltip: catalog.i18nc("@label", "Start the slicing process") + enabled: widget.backendState != UM.Backend.Error + visible: widget.backendState == UM.Backend.NotStarted || widget.backendState == UM.Backend.Error + onClicked: sliceOrStopSlicing() + } + + Cura.SecondaryButton + { + id: cancelButton + fixedWidthMode: true + height: parent.height + anchors.left: parent.left + + anchors.right: parent.right + text: catalog.i18nc("@button", "Cancel") + enabled: sliceButton.enabled + visible: !sliceButton.visible + onClicked: sliceOrStopSlicing() + } + } + + + // React when the user changes the preference of having the auto slice enabled + Connections + { + target: UM.Preferences + onPreferenceChanged: + { + var autoSlice = UM.Preferences.getValue("general/auto_slice") + if(prepareButtons.autoSlice != autoSlice) + { + prepareButtons.autoSlice = autoSlice + if(autoSlice) + { + CuraApplication.backend.forceSlice() + } + } + } + } + + // Shortcut for "slice/stop" + Controls1.Action + { + shortcut: "Ctrl+P" + onTriggered: + { + if (sliceButton.enabled) + { + sliceOrStopSlicing() + } + } + } +} diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index bd7b15a1c7..a1077f5fb7 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. pragma Singleton @@ -23,8 +23,6 @@ Item property alias viewLeftSideCamera: viewLeftSideCameraAction; property alias viewRightSideCamera: viewRightSideCameraAction; - property alias expandSidebar: expandSidebarAction; - property alias deleteSelection: deleteSelectionAction; property alias centerSelection: centerSelectionAction; property alias multiplySelection: multiplySelectionAction; @@ -58,7 +56,6 @@ Item property alias preferences: preferencesAction; - property alias showEngineLog: showEngineLogAction; property alias showProfileFolder: showProfileFolderAction; property alias documentation: documentationAction; property alias reportBug: reportBugAction; @@ -70,7 +67,7 @@ Item property alias browsePackages: browsePackagesAction - UM.I18nCatalog{id: catalog; name:"cura"} + UM.I18nCatalog{id: catalog; name: "cura"} Action { @@ -398,14 +395,6 @@ Item shortcut: StandardKey.New } - Action - { - id: showEngineLogAction; - text: catalog.i18nc("@action:inmenu menubar:help","Show Engine &Log..."); - iconName: "view-list-text"; - shortcut: StandardKey.WhatsThis; - } - Action { id: showProfileFolderAction; @@ -426,11 +415,4 @@ Item text: catalog.i18nc("@action:menu", "&Marketplace") iconName: "plugins_browse" } - - Action - { - id: expandSidebarAction; - text: catalog.i18nc("@action:inmenu menubar:view","Expand/Collapse Sidebar"); - shortcut: "Ctrl+E"; - } } diff --git a/resources/qml/BorderGroup.qml b/resources/qml/BorderGroup.qml new file mode 100644 index 0000000000..38ad9fadff --- /dev/null +++ b/resources/qml/BorderGroup.qml @@ -0,0 +1,10 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.0 + +QtObject +{ + property real width: 0 + property color color: "black" +} diff --git a/resources/qml/CheckBoxWithTooltip.qml b/resources/qml/CheckBoxWithTooltip.qml new file mode 100644 index 0000000000..403efb4d7b --- /dev/null +++ b/resources/qml/CheckBoxWithTooltip.qml @@ -0,0 +1,63 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 + +import UM 1.3 as UM + +CheckBox +{ + id: checkbox + hoverEnabled: true + + property alias tooltip: tooltip.text + + indicator: Rectangle + { + implicitWidth: UM.Theme.getSize("checkbox").width + implicitHeight: UM.Theme.getSize("checkbox").height + x: 0 + anchors.verticalCenter: parent.verticalCenter + color: UM.Theme.getColor("main_background") + radius: UM.Theme.getSize("checkbox_radius").width + border.width: UM.Theme.getSize("default_lining").width + border.color: checkbox.hovered ? UM.Theme.getColor("checkbox_border_hover") : UM.Theme.getColor("checkbox_border") + + UM.RecolorImage + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: Math.round(parent.width / 2.5) + height: Math.round(parent.height / 2.5) + sourceSize.height: width + color: UM.Theme.getColor("checkbox_mark") + source: UM.Theme.getIcon("check") + opacity: checkbox.checked + Behavior on opacity { NumberAnimation { duration: 100; } } + } + } + + contentItem: Label + { + anchors + { + left: checkbox.indicator.right + leftMargin: UM.Theme.getSize("narrow_margin").width + } + text: checkbox.text + color: UM.Theme.getColor("checkbox_text") + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + + ToolTip + { + id: tooltip + text: "" + delay: 500 + visible: text != "" && checkbox.hovered + } +} diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 029149f1d0..a522e3ffa0 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 @@ -6,53 +6,42 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.1 import QtQuick.Dialogs 1.2 +import QtGraphicalEffects 1.0 import UM 1.3 as UM import Cura 1.1 as Cura +import "Dialogs" import "Menus" +import "MainWindow" UM.MainWindow { id: base - //: Cura application window title - title: catalog.i18nc("@title:window","Ultimaker Cura"); - viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0) - property bool showPrintMonitor: false + // Cura application window title + title: catalog.i18nc("@title:window", "Ultimaker Cura") backgroundColor: UM.Theme.getColor("viewport_background") - // This connection is here to support legacy printer output devices that use the showPrintMonitor signal on Application to switch to the monitor stage - // It should be phased out in newer plugin versions. - Connections + + UM.I18nCatalog { - target: CuraApplication - onShowPrintMonitor: { - if (show) { - UM.Controller.setActiveStage("MonitorStage") - } else { - UM.Controller.setActiveStage("PrepareStage") - } - } + id: catalog + name: "cura" } - onWidthChanged: + function showTooltip(item, position, text) { - // If slidebar is collapsed then it should be invisible - // otherwise after the main_window resize the sidebar will be fully re-drawn - if (sidebar.collapsed){ - if (sidebar.visible == true){ - sidebar.visible = false - sidebar.initialWidth = 0 - } - } - else{ - if (sidebar.visible == false){ - sidebar.visible = true - sidebar.initialWidth = UM.Theme.getSize("sidebar").width - } - } + tooltip.text = text; + position = item.mapToItem(backgroundItem, position.x - UM.Theme.getSize("default_arrow").width, position.y); + tooltip.show(position); } + function hideTooltip() + { + tooltip.hide(); + } + + Component.onCompleted: { CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size")) @@ -72,12 +61,12 @@ UM.MainWindow Item { - id: backgroundItem; - anchors.fill: parent; - UM.I18nCatalog{id: catalog; name:"cura"} + id: backgroundItem + anchors.fill: parent signal hasMesh(string name) //this signal sends the filebase name so it can be used for the JobSpecs.qml - function getMeshName(path){ + function getMeshName(path) + { //takes the path the complete path of the meshname and returns only the filebase var fileName = path.slice(path.lastIndexOf("/") + 1) var fileBase = fileName.slice(0, fileName.indexOf(".")) @@ -85,253 +74,97 @@ UM.MainWindow } //DeleteSelection on the keypress backspace event - Keys.onPressed: { + Keys.onPressed: + { if (event.key == Qt.Key_Backspace) { Cura.Actions.deleteSelection.trigger() } } - UM.ApplicationMenu + ApplicationMenu { - id: menu + id: applicationMenu window: base - - Menu - { - id: fileMenu - title: catalog.i18nc("@title:menu menubar:toplevel","&File"); - MenuItem - { - id: newProjectMenu - action: Cura.Actions.newProject; - } - - MenuItem - { - id: openMenu - action: Cura.Actions.open; - } - - RecentFilesMenu { } - - MenuItem - { - id: saveWorkspaceMenu - text: catalog.i18nc("@title:menu menubar:file","&Save...") - onTriggered: - { - var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml" }; - if(UM.Preferences.getValue("cura/dialog_on_project_save")) - { - saveWorkspaceDialog.args = args; - saveWorkspaceDialog.open() - } - else - { - UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, args) - } - } - } - - MenuSeparator { } - - MenuItem - { - id: saveAsMenu - text: catalog.i18nc("@title:menu menubar:file", "&Export...") - onTriggered: - { - var localDeviceId = "local_file"; - UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"}); - } - } - - MenuItem - { - id: exportSelectionMenu - text: catalog.i18nc("@action:inmenu menubar:file", "Export Selection..."); - enabled: UM.Selection.hasSelection; - iconName: "document-save-as"; - onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"}); - } - - MenuSeparator { } - - MenuItem - { - id: reloadAllMenu - action: Cura.Actions.reloadAll; - } - - MenuSeparator { } - - MenuItem { action: Cura.Actions.quit; } - } - - Menu - { - title: catalog.i18nc("@title:menu menubar:toplevel","&Edit"); - - MenuItem { action: Cura.Actions.undo; } - MenuItem { action: Cura.Actions.redo; } - MenuSeparator { } - MenuItem { action: Cura.Actions.selectAll; } - MenuItem { action: Cura.Actions.arrangeAll; } - MenuItem { action: Cura.Actions.deleteSelection; } - MenuItem { action: Cura.Actions.deleteAll; } - MenuItem { action: Cura.Actions.resetAllTranslation; } - MenuItem { action: Cura.Actions.resetAll; } - MenuSeparator { } - MenuItem { action: Cura.Actions.groupObjects;} - MenuItem { action: Cura.Actions.mergeObjects;} - MenuItem { action: Cura.Actions.unGroupObjects;} - } - - ViewMenu { title: catalog.i18nc("@title:menu", "&View") } - - Menu - { - id: settingsMenu - title: catalog.i18nc("@title:menu", "&Settings") - - PrinterMenu { title: catalog.i18nc("@title:menu menubar:settings", "&Printer") } - - Instantiator - { - model: Cura.ExtrudersModel { simpleNames: true } - Menu { - title: model.name - - NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants; extruderIndex: index } - MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials; extruderIndex: index } - - MenuSeparator - { - visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials - } - - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Set as Active Extruder") - onTriggered: Cura.MachineManager.setExtruderIndex(model.index) - } - - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Enable Extruder") - onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) - visible: !Cura.MachineManager.getExtruder(model.index).isEnabled - } - - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Disable Extruder") - onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) - visible: Cura.MachineManager.getExtruder(model.index).isEnabled - enabled: Cura.MachineManager.numberExtrudersEnabled > 1 - } - - } - onObjectAdded: settingsMenu.insertItem(index, object) - onObjectRemoved: settingsMenu.removeItem(object) - } - - // TODO Only show in dev mode. Remove check when feature ready - BuildplateMenu { title: catalog.i18nc("@title:menu", "&Build plate"); visible: CuraSDKVersion == "dev" ? Cura.MachineManager.hasVariantBuildplates : false } - ProfileMenu { title: catalog.i18nc("@title:settings", "&Profile"); } - - MenuSeparator { } - - MenuItem { action: Cura.Actions.configureSettingVisibility } - } - - Menu - { - id: extension_menu - title: catalog.i18nc("@title:menu menubar:toplevel","E&xtensions"); - - Instantiator - { - id: extensions - model: UM.ExtensionModel { } - - Menu - { - id: sub_menu - title: model.name; - visible: actions != null - enabled: actions != null - Instantiator - { - model: actions - MenuItem - { - text: model.text - onTriggered: extensions.model.subMenuTriggered(name, model.text) - } - onObjectAdded: sub_menu.insertItem(index, object) - onObjectRemoved: sub_menu.removeItem(object) - } - } - - onObjectAdded: extension_menu.insertItem(index, object) - onObjectRemoved: extension_menu.removeItem(object) - } - } - - Menu - { - id: plugin_menu - title: catalog.i18nc("@title:menu menubar:toplevel", "&Marketplace") - - MenuItem { action: Cura.Actions.browsePackages } - } - - Menu - { - id: preferencesMenu - title: catalog.i18nc("@title:menu menubar:toplevel","P&references"); - - MenuItem { action: Cura.Actions.preferences; } - } - - Menu - { - id: helpMenu - title: catalog.i18nc("@title:menu menubar:toplevel","&Help"); - - MenuItem { action: Cura.Actions.showProfileFolder; } - MenuItem { action: Cura.Actions.documentation; } - MenuItem { action: Cura.Actions.reportBug; } - MenuSeparator { } - MenuItem { action: Cura.Actions.about; } - } - } - - UM.SettingPropertyProvider - { - id: machineExtruderCount - - containerStack: Cura.MachineManager.activeMachine - key: "machine_extruder_count" - watchedProperties: [ "value" ] - storeIndex: 0 } Item { - id: contentItem; + id: headerBackground + anchors + { + top: applicationMenu.bottom + left: parent.left + right: parent.right + } + height: stageMenu.source != "" ? Math.round(mainWindowHeader.height + stageMenu.height / 2) : mainWindowHeader.height - y: menu.height - width: parent.width; - height: parent.height - menu.height; + LinearGradient + { + anchors.fill: parent + start: Qt.point(0, 0) + end: Qt.point(parent.width, 0) + gradient: Gradient + { + GradientStop + { + position: 0.0 + color: UM.Theme.getColor("main_window_header_background") + } + GradientStop + { + position: 0.5 + color: UM.Theme.getColor("main_window_header_background_gradient") + } + GradientStop + { + position: 1.0 + color: UM.Theme.getColor("main_window_header_background") + } + } + } - Keys.forwardTo: menu + // This is a placehoder for adding a pattern in the header + Image + { + id: backgroundPattern + anchors.fill: parent + fillMode: Image.Tile + source: UM.Theme.getImage("header_pattern") + horizontalAlignment: Image.AlignLeft + verticalAlignment: Image.AlignTop + } + } + + MainWindowHeader + { + id: mainWindowHeader + anchors + { + left: parent.left + right: parent.right + top: applicationMenu.bottom + } + } + + Item + { + id: contentItem + + anchors + { + top: mainWindowHeader.bottom + bottom: parent.bottom + left: parent.left + right: parent.right + } + + Keys.forwardTo: applicationMenu DropArea { - anchors.fill: parent; + // The drop area is here to handle files being dropped onto Cura. + anchors.fill: parent onDropped: { if (drop.urls.length > 0) @@ -359,178 +192,194 @@ UM.MainWindow } } - JobSpecs - { - id: jobSpecs - anchors - { - bottom: parent.bottom; - right: sidebar.left; - bottomMargin: UM.Theme.getSize("default_margin").height; - rightMargin: UM.Theme.getSize("default_margin").width; - } - } - - Button - { - id: openFileButton; - text: catalog.i18nc("@action:button","Open File"); - iconSource: UM.Theme.getIcon("load") - style: UM.Theme.styles.tool_button - tooltip: "" - anchors - { - top: topbar.bottom; - topMargin: UM.Theme.getSize("default_margin").height; - left: parent.left; - } - action: Cura.Actions.open; - } - Toolbar { - id: toolbar; + // The toolbar is the left bar that is populated by all the tools (which are dynamicly populated by + // plugins) + id: toolbar property int mouseX: base.mouseX property int mouseY: base.mouseY - anchors { - top: openFileButton.bottom; - topMargin: UM.Theme.getSize("window_margin").height; - left: parent.left; + anchors + { + verticalCenter: parent.verticalCenter + left: parent.left } + visible: CuraApplication.platformActivity && !PrintInformation.preSliced } ObjectsList { - id: objectsList; - visible: UM.Preferences.getValue("cura/use_multi_build_plate"); + id: objectsList + visible: UM.Preferences.getValue("cura/use_multi_build_plate") anchors { - bottom: parent.bottom; - left: parent.left; + bottom: viewOrientationControls.top + left: toolbar.right + margins: UM.Theme.getSize("default_margin").width } - } - Topbar + JobSpecs { - id: topbar - anchors.left: parent.left + id: jobSpecs + visible: CuraApplication.platformActivity + anchors + { + left: parent.left + bottom: viewOrientationControls.top + margins: UM.Theme.getSize("default_margin").width + bottomMargin: UM.Theme.getSize("thin_margin").width + } + } + + ViewOrientationControls + { + id: viewOrientationControls + + anchors + { + left: parent.left + bottom: parent.bottom + margins: UM.Theme.getSize("default_margin").width + } + } + + Cura.ActionPanelWidget + { + id: actionPanelWidget anchors.right: parent.right - anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.rightMargin: UM.Theme.getSize("thick_margin").width + anchors.bottomMargin: UM.Theme.getSize("thick_margin").height + + /* + Show this panel only if there is something on the build plate, and there is NOT an opaque item in front of the build plate. + This cannot be solved by Z indexing! If you want to try solving this, please increase this counter when you're done: + Number of people having tried to fix this by z-indexing: 2 + The problem arises from the following render order requirements: + - The stage menu must be rendered above the stage main. + - The stage main must be rendered above the action panel (because the monitor page must be rendered above the action panel). + - The action panel must be rendered above the expandable components drop-down. + However since the expandable components drop-downs are child elements of the stage menu, + they can't be rendered lower than elements that are lower than the stage menu. + Therefore we opted to forego the second requirement and hide the action panel instead when something obscures it (except the expandable components). + We assume that QQuickRectangles are always opaque and any other item is not. + */ + visible: CuraApplication.platformActivity && (main.item == null || !qmlTypeOf(main.item, "QQuickRectangle")) + } + + Item + { + id: additionalComponents + width: childrenRect.width + anchors.right: actionPanelWidget.left + anchors.rightMargin: UM.Theme.getSize("default_margin").width + anchors.bottom: actionPanelWidget.bottom + anchors.bottomMargin: UM.Theme.getSize("thick_margin").height * 2 + visible: actionPanelWidget.visible + Row + { + id: additionalComponentsRow + anchors.verticalCenter: parent.verticalCenter + spacing: UM.Theme.getSize("default_margin").width + } + } + + Component.onCompleted: contentItem.addAdditionalComponents() + + Connections + { + target: CuraApplication + onAdditionalComponentsChanged: contentItem.addAdditionalComponents("saveButton") + } + + function addAdditionalComponents() + { + for (var component in CuraApplication.additionalComponents["saveButton"]) + { + CuraApplication.additionalComponents["saveButton"][component].parent = additionalComponentsRow + } } Loader { + // A stage can control this area. If nothing is set, it will therefore show the 3D view. id: main anchors { - top: topbar.bottom - bottom: parent.bottom + // Align to the top of the stageMenu since the stageMenu may not exist + top: stageMenu.source ? stageMenu.verticalCenter : parent.top left: parent.left - right: sidebar.left + right: parent.right + bottom: parent.bottom } - MouseArea - { - visible: UM.Controller.activeStage.mainComponent != "" - anchors.fill: parent - acceptedButtons: Qt.AllButtons - onWheel: wheel.accepted = true - } - - source: UM.Controller.activeStage.mainComponent + source: UM.Controller.activeStage != null ? UM.Controller.activeStage.mainComponent : "" } Loader { - id: sidebar - - property bool collapsed: false; - property var initialWidth: UM.Theme.getSize("sidebar").width; - - function callExpandOrCollapse() { - if (collapsed) { - sidebar.visible = true; - sidebar.initialWidth = UM.Theme.getSize("sidebar").width; - viewportRect = Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0); - expandSidebarAnimation.start(); - } else { - viewportRect = Qt.rect(0, 0, 1, 1.0); - collapseSidebarAnimation.start(); - } - collapsed = !collapsed; - UM.Preferences.setValue("cura/sidebar_collapsed", collapsed); - } + // The stage menu is, as the name implies, a menu that is defined by the active stage. + // Note that this menu does not need to be set at all! It's perfectly acceptable to have a stage + // without this menu! + id: stageMenu anchors { - top: topbar.top - bottom: parent.bottom + left: parent.left + right: parent.right + top: parent.top } - width: initialWidth - x: base.width - sidebar.width - source: UM.Controller.activeStage.sidebarComponent + height: UM.Theme.getSize("stage_menu").height + source: UM.Controller.activeStage != null ? UM.Controller.activeStage.stageMenuComponent : "" - NumberAnimation { - id: collapseSidebarAnimation - target: sidebar - properties: "x" - to: base.width - duration: 100 - } - - NumberAnimation { - id: expandSidebarAnimation - target: sidebar - properties: "x" - to: base.width - sidebar.width - duration: 100 - } - - Component.onCompleted: + // HACK: This is to ensure that the parent never gets set to null, as this wreaks havoc on the focus. + function onParentDestroyed() { - var sidebar_collapsed = UM.Preferences.getValue("cura/sidebar_collapsed"); - - if (sidebar_collapsed) - { - sidebar.collapsed = true; - viewportRect = Qt.rect(0, 0, 1, 1.0) - collapseSidebarAnimation.start(); - } + printSetupSelector.parent = stageMenu + printSetupSelector.visible = false } + property Item oldParent: null - MouseArea + // The printSetupSelector is defined here so that the setting list doesn't need to get re-instantiated + // Every time the stage is changed. + property var printSetupSelector: Cura.PrintSetupSelector { - visible: UM.Controller.activeStage.sidebarComponent != "" - anchors.fill: parent - acceptedButtons: Qt.AllButtons - onWheel: wheel.accepted = true + width: UM.Theme.getSize("print_setup_widget").width + height: UM.Theme.getSize("stage_menu").height + headerCornerSide: RoundedRectangle.Direction.Right + onParentChanged: + { + if(stageMenu.oldParent !=null) + { + stageMenu.oldParent.Component.destruction.disconnect(stageMenu.onParentDestroyed) + } + stageMenu.oldParent = parent + visible = parent != stageMenu + parent.Component.destruction.connect(stageMenu.onParentDestroyed) + } } } - UM.MessageStack { anchors { horizontalCenter: parent.horizontalCenter - horizontalCenterOffset: -(Math.round(UM.Theme.getSize("sidebar").width / 2)) - top: parent.verticalCenter; - bottom: parent.bottom; + top: parent.verticalCenter + bottom: parent.bottom bottomMargin: UM.Theme.getSize("default_margin").height } } } - } - // Expand or collapse sidebar - Connections - { - target: Cura.Actions.expandSidebar - onTriggered: sidebar.callExpandOrCollapse() + PrintSetupTooltip + { + id: tooltip + } } UM.PreferencesDialog @@ -552,9 +401,6 @@ UM.MainWindow insertPage(4, catalog.i18nc("@title:tab", "Profiles"), Qt.resolvedUrl("Preferences/ProfilesPage.qml")); - // Remove plug-ins page because we will use the shiny new plugin browser: - removePage(5); - //Force refresh setPage(0); } @@ -567,13 +413,6 @@ UM.MainWindow } } - WorkspaceSummaryDialog - { - id: saveWorkspaceDialog - property var args - onYes: UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, args) - } - Connections { target: Cura.Actions.preferences @@ -586,33 +425,6 @@ UM.MainWindow onShowPreferencesWindow: preferences.visible = true } - MessageDialog - { - id: newProjectDialog - modality: Qt.ApplicationModal - title: catalog.i18nc("@title:window", "New project") - text: catalog.i18nc("@info:question", "Are you sure you want to start a new project? This will clear the build plate and any unsaved settings.") - standardButtons: StandardButton.Yes | StandardButton.No - icon: StandardIcon.Question - onYes: - { - CuraApplication.deleteAll(); - Cura.Actions.resetProfile.trigger(); - } - } - - Connections - { - target: Cura.Actions.newProject - onTriggered: - { - if(Printer.platformActivity || Cura.MachineManager.hasUserSettings) - { - newProjectDialog.visible = true - } - } - } - Connections { target: Cura.Actions.addProfile @@ -670,19 +482,6 @@ UM.MainWindow } } - UM.ExtensionModel { - id: curaExtensions - } - - // show the plugin browser dialog - Connections - { - target: Cura.Actions.browsePackages - onTriggered: { - curaExtensions.callExtensionMethod("Toolbox", "browsePackages") - } - } - Timer { id: createProfileTimer @@ -703,7 +502,8 @@ UM.MainWindow } } - ContextMenu { + ContextMenu + { id: contextMenu } @@ -870,7 +670,8 @@ UM.MainWindow modality: Qt.ApplicationModal } - MessageDialog { + MessageDialog + { id: infoMultipleFilesWithGcodeDialog title: catalog.i18nc("@title:window", "Open File(s)") icon: StandardIcon.Information @@ -914,11 +715,6 @@ UM.MainWindow } } - EngineLog - { - id: engineLog; - } - Connections { target: Cura.Actions.showProfileFolder @@ -1067,4 +863,21 @@ UM.MainWindow } } } + + /** + * Function to check whether a QML object has a certain type. + * Taken from StackOverflow: https://stackoverflow.com/a/28384228 and + * adapted to our code style. + * Licensed under CC BY-SA 3.0. + * \param obj The QtObject to get the name of. + * \param class_name (str) The name of the class to check against. Has to be + * the QtObject class name, not the QML entity name. + */ + function qmlTypeOf(obj, class_name) + { + //className plus "(" is the class instance without modification. + //className plus "_QML" is the class instance with user-defined properties. + var str = obj.toString(); + return str.indexOf(class_name + "(") == 0 || str.indexOf(class_name + "_QML") == 0; + } } diff --git a/resources/qml/Dialogs/AboutDialog.qml b/resources/qml/Dialogs/AboutDialog.qml new file mode 100644 index 0000000000..ac115a0e5f --- /dev/null +++ b/resources/qml/Dialogs/AboutDialog.qml @@ -0,0 +1,168 @@ +// 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.Window 2.1 + +import UM 1.1 as UM + +UM.Dialog +{ + id: base + + //: About dialog title + title: catalog.i18nc("@title:window","About Cura") + + minimumWidth: 500 * screenScaleFactor + minimumHeight: 650 * screenScaleFactor + width: minimumWidth + height: minimumHeight + + Rectangle + { + width: parent.width + 2 * margin // margin from Dialog.qml + height: version.y + version.height + margin + + anchors.top: parent.top + anchors.topMargin: - margin + anchors.horizontalCenter: parent.horizontalCenter + + color: UM.Theme.getColor("viewport_background") + } + + Image + { + id: logo + width: (base.minimumWidth * 0.85) | 0 + height: (width * (UM.Theme.getSize("logo").height / UM.Theme.getSize("logo").width)) | 0 + + source: UM.Theme.getImage("logo_about") + + anchors.top: parent.top + anchors.topMargin: ((base.minimumWidth - width) / 2) | 0 + anchors.horizontalCenter: parent.horizontalCenter + + UM.I18nCatalog{id: catalog; name: "cura"} + } + + Label + { + id: version + + text: catalog.i18nc("@label","version: %1").arg(UM.Application.version) + font: UM.Theme.getFont("large_bold") + color: UM.Theme.getColor("text") + anchors.right : logo.right + anchors.top: logo.bottom + anchors.topMargin: (UM.Theme.getSize("default_margin").height / 2) | 0 + } + + Label + { + id: description + width: parent.width + + //: About dialog application description + text: catalog.i18nc("@label","End-to-end solution for fused filament 3D printing.") + font: UM.Theme.getFont("system") + wrapMode: Text.WordWrap + anchors.top: version.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height + } + + Label + { + id: creditsNotes + width: parent.width + + //: About dialog application author note + text: catalog.i18nc("@info:credit","Cura is developed by Ultimaker B.V. in cooperation with the community.\nCura proudly uses the following open source projects:") + font: UM.Theme.getFont("system") + wrapMode: Text.WordWrap + anchors.top: description.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height + } + + ScrollView + { + id: credits + anchors.top: creditsNotes.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height + + width: parent.width + height: base.height - y - (2 * UM.Theme.getSize("default_margin").height + closeButton.height) + + ListView + { + id: projectsList + + width: parent.width + + delegate: Row + { + Label + { + text: "%2".arg(model.url).arg(model.name) + width: (projectsList.width * 0.25) | 0 + elide: Text.ElideRight + onLinkActivated: Qt.openUrlExternally(link) + } + Label + { + text: model.description + elide: Text.ElideRight + width: (projectsList.width * 0.6) | 0 + } + Label + { + text: model.license + elide: Text.ElideRight + width: (projectsList.width * 0.15) | 0 + } + } + model: ListModel + { + id: projectsModel + } + Component.onCompleted: + { + projectsModel.append({ name: "Cura", description: catalog.i18nc("@label", "Graphical user interface"), license: "LGPLv3", url: "https://github.com/Ultimaker/Cura" }); + projectsModel.append({ name: "Uranium", description: catalog.i18nc("@label", "Application framework"), license: "LGPLv3", url: "https://github.com/Ultimaker/Uranium" }); + projectsModel.append({ name: "CuraEngine", description: catalog.i18nc("@label", "G-code generator"), license: "AGPLv3", url: "https://github.com/Ultimaker/CuraEngine" }); + projectsModel.append({ name: "libArcus", description: catalog.i18nc("@label", "Interprocess communication library"), license: "LGPLv3", url: "https://github.com/Ultimaker/libArcus" }); + + projectsModel.append({ name: "Python", description: catalog.i18nc("@label", "Programming language"), license: "Python", url: "http://python.org/" }); + projectsModel.append({ name: "Qt5", description: catalog.i18nc("@label", "GUI framework"), license: "LGPLv3", url: "https://www.qt.io/" }); + projectsModel.append({ name: "PyQt", description: catalog.i18nc("@label", "GUI framework bindings"), license: "GPL", url: "https://riverbankcomputing.com/software/pyqt" }); + projectsModel.append({ name: "SIP", description: catalog.i18nc("@label", "C/C++ Binding library"), license: "GPL", url: "https://riverbankcomputing.com/software/sip" }); + projectsModel.append({ name: "Protobuf", description: catalog.i18nc("@label", "Data interchange format"), license: "BSD", url: "https://developers.google.com/protocol-buffers" }); + projectsModel.append({ name: "SciPy", description: catalog.i18nc("@label", "Support library for scientific computing"), license: "BSD-new", url: "https://www.scipy.org/" }); + projectsModel.append({ name: "NumPy", description: catalog.i18nc("@label", "Support library for faster math"), license: "BSD", url: "http://www.numpy.org/" }); + projectsModel.append({ name: "NumPy-STL", description: catalog.i18nc("@label", "Support library for handling STL files"), license: "BSD", url: "https://github.com/WoLpH/numpy-stl" }); + projectsModel.append({ name: "Shapely", description: catalog.i18nc("@label", "Support library for handling planar objects"), license: "BSD", url: "https://github.com/Toblerity/Shapely" }); + projectsModel.append({ name: "Trimesh", description: catalog.i18nc("@label", "Support library for handling triangular meshes"), license: "MIT", url: "https://trimsh.org" }); + projectsModel.append({ name: "NetworkX", description: catalog.i18nc("@label", "Support library for analysis of complex networks"), license: "3-clause BSD", url: "https://networkx.github.io/" }); + projectsModel.append({ name: "libSavitar", description: catalog.i18nc("@label", "Support library for handling 3MF files"), license: "LGPLv3", url: "https://github.com/ultimaker/libsavitar" }); + projectsModel.append({ name: "libCharon", description: catalog.i18nc("@label", "Support library for file metadata and streaming"), license: "LGPLv3", url: "https://github.com/ultimaker/libcharon" }); + projectsModel.append({ name: "PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" }); + projectsModel.append({ name: "python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" }); + projectsModel.append({ name: "Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" }); + projectsModel.append({ name: "Requests", description: catalog.i18nc("@Label", "Python HTTP library"), license: "GPL", url: "http://docs.python-requests.org" }); + + projectsModel.append({ name: "Noto Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://www.google.com/get/noto/" }); + projectsModel.append({ name: "Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" }); + projectsModel.append({ name: "AppImageKit", description: catalog.i18nc("@label", "Linux cross-distribution application deployment"), license: "MIT", url: "https://github.com/AppImage/AppImageKit" }); + } + } + } + + rightButtons: Button + { + //: Close about dialog button + id: closeButton + text: catalog.i18nc("@action:button","Close"); + + onClicked: base.visible = false; + } +} diff --git a/resources/qml/AddMachineDialog.qml b/resources/qml/Dialogs/AddMachineDialog.qml similarity index 89% rename from resources/qml/AddMachineDialog.qml rename to resources/qml/Dialogs/AddMachineDialog.qml index 0df8b891d9..f00359869c 100644 --- a/resources/qml/AddMachineDialog.qml +++ b/resources/qml/Dialogs/AddMachineDialog.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 @@ -73,7 +73,7 @@ UM.Dialog { top: parent.top left: parent.left - topMargin: UM.Theme.getSize("default_margin") + topMargin: UM.Theme.getSize("default_margin").height } text: catalog.i18nc("@title:tab", "Add a printer to Cura") @@ -156,7 +156,6 @@ UM.Dialog anchors.rightMargin: UM.Theme.getSize("default_margin").width width: UM.Theme.getSize("standard_arrow").width height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width sourceSize.height: width color: palette.windowText source: base.activeCategory == section ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_right") @@ -170,7 +169,7 @@ UM.Dialog if (machineList.model.getItem(machineList.currentIndex).section != section) { // Find the first machine from this section - for(var i = 0; i < machineList.model.rowCount(); i++) + for(var i = 0; i < machineList.model.count; i++) { var item = machineList.model.getItem(i); if (item.section == section) @@ -213,28 +212,6 @@ UM.Dialog PropertyChanges { target: machineButton; opacity: 0; height: 0; } } - - transitions: - [ - Transition - { - to: "collapsed"; - SequentialAnimation - { - NumberAnimation { property: "opacity"; duration: 75; } - NumberAnimation { property: "height"; duration: 75; } - } - }, - Transition - { - from: "collapsed"; - SequentialAnimation - { - NumberAnimation { property: "height"; duration: 75; } - NumberAnimation { property: "opacity"; duration: 75; } - } - } - ] } } } @@ -298,7 +275,6 @@ UM.Dialog id: machineName text: getMachineName() width: Math.floor(parent.width * 0.75) - implicitWidth: UM.Theme.getSize("standard_list_input").width maximumLength: 40 //validator: Cura.MachineNameValidator { } //TODO: Gives a segfault in PyQt5.6. For now, we must use a signal on text changed. validator: RegExpValidator diff --git a/resources/qml/AskOpenAsProjectOrModelsDialog.qml b/resources/qml/Dialogs/AskOpenAsProjectOrModelsDialog.qml similarity index 100% rename from resources/qml/AskOpenAsProjectOrModelsDialog.qml rename to resources/qml/Dialogs/AskOpenAsProjectOrModelsDialog.qml diff --git a/resources/qml/DiscardOrKeepProfileChangesDialog.qml b/resources/qml/Dialogs/DiscardOrKeepProfileChangesDialog.qml similarity index 100% rename from resources/qml/DiscardOrKeepProfileChangesDialog.qml rename to resources/qml/Dialogs/DiscardOrKeepProfileChangesDialog.qml diff --git a/resources/qml/OpenFilesIncludingProjectsDialog.qml b/resources/qml/Dialogs/OpenFilesIncludingProjectsDialog.qml similarity index 100% rename from resources/qml/OpenFilesIncludingProjectsDialog.qml rename to resources/qml/Dialogs/OpenFilesIncludingProjectsDialog.qml diff --git a/resources/qml/WorkspaceSummaryDialog.qml b/resources/qml/Dialogs/WorkspaceSummaryDialog.qml similarity index 99% rename from resources/qml/WorkspaceSummaryDialog.qml rename to resources/qml/Dialogs/WorkspaceSummaryDialog.qml index 1b3a7aac55..35630bd19b 100644 --- a/resources/qml/WorkspaceSummaryDialog.qml +++ b/resources/qml/Dialogs/WorkspaceSummaryDialog.qml @@ -11,6 +11,7 @@ import Cura 1.0 as Cura UM.Dialog { + id: base title: catalog.i18nc("@title:window", "Save Project") minimumWidth: 500 * screenScaleFactor @@ -49,7 +50,7 @@ UM.Dialog UM.SettingDefinitionsModel { id: definitionsModel - containerId: Cura.MachineManager.activeDefinitionId + containerId: base.visible ? Cura.MachineManager.activeDefinitionId: "" showAll: true exclude: ["command_line_settings"] showAncestors: true diff --git a/resources/qml/EngineLog.qml b/resources/qml/EngineLog.qml deleted file mode 100644 index 965587b59e..0000000000 --- a/resources/qml/EngineLog.qml +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2015 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.Layouts 1.1 - -import UM 1.1 as UM - -UM.Dialog -{ - id: dialog; - - //: Engine Log dialog title - title: catalog.i18nc("@title:window","Engine Log"); - - modality: Qt.NonModal; - - TextArea - { - id: textArea - anchors.fill: parent; - - Timer - { - id: updateTimer; - interval: 1000; - running: false; - repeat: true; - onTriggered: textArea.text = CuraApplication.getEngineLog(); - } - UM.I18nCatalog{id: catalog; name:"cura"} - } - - rightButtons: Button - { - //: Close engine log button - text: catalog.i18nc("@action:button","Close"); - onClicked: dialog.visible = false; - } - - onVisibleChanged: - { - if(visible) - { - textArea.text = CuraApplication.getEngineLog(); - updateTimer.start(); - } else - { - updateTimer.stop(); - } - } -} diff --git a/resources/qml/ExpandableComponent.qml b/resources/qml/ExpandableComponent.qml new file mode 100644 index 0000000000..025c63d754 --- /dev/null +++ b/resources/qml/ExpandableComponent.qml @@ -0,0 +1,262 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +import QtGraphicalEffects 1.0 // For the dropshadow + +// The expandable component has 2 major sub components: +// * The headerItem; Always visible and should hold some info about what happens if the component is expanded +// * The contentItem; The content that needs to be shown if the component is expanded. +Item +{ + id: base + + // Enumeration with the different possible alignments of the content with respect of the headerItem + enum ContentAlignment + { + AlignLeft, + AlignRight + } + + // The headerItem holds the QML item that is always displayed. + property alias headerItem: headerItemLoader.sourceComponent + + // The contentItem holds the QML item that is shown when the "open" button is pressed + property alias contentItem: content.contentItem + + property color contentBackgroundColor: UM.Theme.getColor("action_button") + + property color headerBackgroundColor: UM.Theme.getColor("action_button") + property color headerActiveColor: UM.Theme.getColor("secondary") + property color headerHoverColor: UM.Theme.getColor("action_button_hovered") + + property alias enabled: mouseArea.enabled + + // Text to show when this component is disabled + property alias disabledText: disabledLabel.text + + // Defines the alignment of the content with respect of the headerItem, by default to the right + property int contentAlignment: ExpandableComponent.ContentAlignment.AlignRight + + // How much spacing is needed around the contentItem + property alias contentPadding: content.padding + + // Adds a title to the content item + property alias contentHeaderTitle: contentHeader.headerTitle + + // How much spacing is needed for the contentItem by Y coordinate + property var contentSpacingY: UM.Theme.getSize("narrow_margin").width + + // How much padding is needed around the header & button + property alias headerPadding: background.padding + + // What icon should be displayed on the right. + property alias iconSource: collapseButton.source + + property alias iconColor: collapseButton.color + + // The icon size (it's always drawn as a square) + property alias iconSize: collapseButton.height + + // Is the "drawer" open? + property alias expanded: contentContainer.visible + + // What should the radius of the header be. This is also influenced by the headerCornerSide + property alias headerRadius: background.radius + + // On what side should the header corners be shown? 1 is down, 2 is left, 3 is up and 4 is right. + property alias headerCornerSide: background.cornerSide + + property alias headerShadowColor: shadow.color + + property alias enableHeaderShadow: shadow.visible + + property int shadowOffset: 2 + + function toggleContent() + { + contentContainer.visible = !expanded + } + + // Add this binding since the background color is not updated otherwise + Binding + { + target: background + property: "color" + value: + { + return base.enabled ? (expanded ? headerActiveColor : headerBackgroundColor) : UM.Theme.getColor("disabled") + } + } + + // The panel needs to close when it becomes disabled + Connections + { + target: base + onEnabledChanged: + { + if (!base.enabled && expanded) + { + toggleContent() + } + } + } + + implicitHeight: 100 * screenScaleFactor + implicitWidth: 400 * screenScaleFactor + + RoundedRectangle + { + id: background + property real padding: UM.Theme.getSize("default_margin").width + + color: base.enabled ? (base.expanded ? headerActiveColor : headerBackgroundColor) : UM.Theme.getColor("disabled") + anchors.fill: parent + + Label + { + id: disabledLabel + visible: !base.enabled + anchors.fill: parent + leftPadding: background.padding + rightPadding: background.padding + text: "" + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + color: UM.Theme.getColor("text") + wrapMode: Text.WordWrap + } + + Item + { + anchors.fill: parent + visible: base.enabled + + Loader + { + id: headerItemLoader + anchors + { + left: parent.left + right: collapseButton.visible ? collapseButton.left : parent.right + top: parent.top + bottom: parent.bottom + margins: background.padding + } + } + + UM.RecolorImage + { + id: collapseButton + anchors + { + right: parent.right + verticalCenter: parent.verticalCenter + margins: background.padding + } + source: UM.Theme.getIcon("pencil") + visible: source != "" + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + color: UM.Theme.getColor("small_button_text") + } + } + + MouseArea + { + id: mouseArea + anchors.fill: parent + onClicked: toggleContent() + hoverEnabled: true + onEntered: background.color = headerHoverColor + onExited: background.color = base.enabled ? (base.expanded ? headerActiveColor : headerBackgroundColor) : UM.Theme.getColor("disabled") + } + } + + DropShadow + { + id: shadow + // Don't blur the shadow + radius: 0 + anchors.fill: background + source: background + verticalOffset: base.shadowOffset + visible: true + color: UM.Theme.getColor("action_button_shadow") + // Should always be drawn behind the background. + z: background.z - 1 + } + + Cura.RoundedRectangle + { + id: contentContainer + + visible: false + width: childrenRect.width + height: childrenRect.height + + // Ensure that the content is located directly below the headerItem + y: background.height + base.shadowOffset + base.contentSpacingY + + // Make the content aligned with the rest, using the property contentAlignment to decide whether is right or left. + // In case of right alignment, the 3x padding is due to left, right and padding between the button & text. + x: contentAlignment == ExpandableComponent.ContentAlignment.AlignRight ? -width + collapseButton.width + headerItemLoader.width + 3 * background.padding : 0 + + cornerSide: Cura.RoundedRectangle.Direction.All + color: contentBackgroundColor + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + radius: UM.Theme.getSize("default_radius").width + + ExpandableComponentHeader + { + id: contentHeader + headerTitle: "" + anchors + { + top: parent.top + right: parent.right + left: parent.left + } + + } + + Control + { + id: content + + anchors.top: contentHeader.bottom + padding: UM.Theme.getSize("default_margin").width + + contentItem: Item {} + + onContentItemChanged: + { + // Since we want the size of the content to be set by the size of the content, + // we need to do it like this. + content.width = contentItem.width + 2 * content.padding + content.height = contentItem.height + 2 * content.padding + } + } + } + + // DO NOT MOVE UP IN THE CODE: This connection has to be here, after the definition of the content item. + // Apparently the order in which these are handled matters and so the height is correctly updated if this is here. + Connections + { + // Since it could be that the content is dynamically populated, we should also take these changes into account. + target: content.contentItem + onWidthChanged: content.width = content.contentItem.width + 2 * content.padding + onHeightChanged: + { + content.height = content.contentItem.height + 2 * content.padding + contentContainer.height = contentHeader.height + content.height + } + } +} diff --git a/resources/qml/ExpandableComponentHeader.qml b/resources/qml/ExpandableComponentHeader.qml new file mode 100644 index 0000000000..94066340e3 --- /dev/null +++ b/resources/qml/ExpandableComponentHeader.qml @@ -0,0 +1,68 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +// Header of the popup +Cura.RoundedRectangle +{ + id: header + + property alias headerTitle: headerLabel.text + + height: UM.Theme.getSize("expandable_component_content_header").height + color: UM.Theme.getColor("secondary") + cornerSide: Cura.RoundedRectangle.Direction.Up + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + radius: UM.Theme.getSize("default_radius").width + + Label + { + id: headerLabel + text: "" + font: UM.Theme.getFont("medium") + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + color: UM.Theme.getColor("small_button_text") + height: parent.height + + anchors + { + topMargin: UM.Theme.getSize("default_margin").height + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").height + } + } + + Button + { + id: closeButton + width: UM.Theme.getSize("message_close").width + height: UM.Theme.getSize("message_close").height + hoverEnabled: true + + anchors + { + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + verticalCenter: parent.verticalCenter + } + + contentItem: UM.RecolorImage + { + anchors.fill: parent + sourceSize.width: width + color: closeButton.hovered ? UM.Theme.getColor("small_button_text_hover") : UM.Theme.getColor("small_button_text") + source: UM.Theme.getIcon("cross1") + } + + background: Item {} + + onClicked: toggleContent() // Will hide the popup item + } +} \ No newline at end of file diff --git a/resources/qml/ExpandablePopup.qml b/resources/qml/ExpandablePopup.qml new file mode 100644 index 0000000000..2d2665373e --- /dev/null +++ b/resources/qml/ExpandablePopup.qml @@ -0,0 +1,250 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +import QtGraphicalEffects 1.0 // For the dropshadow + +// The expandable component has 2 major sub components: +// * The headerItem; Always visible and should hold some info about what happens if the component is expanded +// * The contentItem; The content that needs to be shown if the component is expanded. +Item +{ + id: base + + // Enumeration with the different possible alignments of the content with respect of the headerItem + enum ContentAlignment + { + AlignLeft, + AlignRight + } + + // The headerItem holds the QML item that is always displayed. + property alias headerItem: headerItemLoader.sourceComponent + + // The contentItem holds the QML item that is shown when the "open" button is pressed + property alias contentItem: content.contentItem + + property color contentBackgroundColor: UM.Theme.getColor("action_button") + + property color headerBackgroundColor: UM.Theme.getColor("action_button") + property color headerActiveColor: UM.Theme.getColor("secondary") + property color headerHoverColor: UM.Theme.getColor("action_button_hovered") + + property alias enabled: mouseArea.enabled + + // Text to show when this component is disabled + property alias disabledText: disabledLabel.text + + // Defines the alignment of the content with respect of the headerItem, by default to the right + property int contentAlignment: ExpandablePopup.ContentAlignment.AlignRight + + // How much spacing is needed around the contentItem + property alias contentPadding: content.padding + + // How much padding is needed around the header & button + property alias headerPadding: background.padding + + // What icon should be displayed on the right. + property alias iconSource: collapseButton.source + + property alias iconColor: collapseButton.color + + // The icon size (it's always drawn as a square) + property alias iconSize: collapseButton.height + + // Is the "drawer" open? + readonly property alias expanded: content.visible + + property alias expandedHighlightColor: expandedHighlight.color + + // What should the radius of the header be. This is also influenced by the headerCornerSide + property alias headerRadius: background.radius + + // On what side should the header corners be shown? 1 is down, 2 is left, 3 is up and 4 is right. + property alias headerCornerSide: background.cornerSide + + // Change the contentItem close behaviour + property alias contentClosePolicy : content.closePolicy + + property alias headerShadowColor: shadow.color + + property alias enableHeaderShadow: shadow.visible + + property int shadowOffset: 2 + + function toggleContent() + { + if (content.visible) + { + content.close() + } + else + { + content.open() + } + } + + // Add this binding since the background color is not updated otherwise + Binding + { + target: background + property: "color" + value: base.enabled ? headerBackgroundColor : UM.Theme.getColor("disabled") + } + + // The panel needs to close when it becomes disabled + Connections + { + target: base + onEnabledChanged: + { + if (!base.enabled && expanded) + { + toggleContent() + } + } + } + + implicitHeight: 100 * screenScaleFactor + implicitWidth: 400 * screenScaleFactor + + RoundedRectangle + { + id: background + property real padding: UM.Theme.getSize("default_margin").width + + color: base.enabled ? headerBackgroundColor : UM.Theme.getColor("disabled") + anchors.fill: parent + + Label + { + id: disabledLabel + visible: !base.enabled + leftPadding: background.padding + text: "" + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + color: UM.Theme.getColor("text") + height: parent.height + } + + Item + { + anchors.fill: parent + visible: base.enabled + + Loader + { + id: headerItemLoader + anchors + { + left: parent.left + right: collapseButton.visible ? collapseButton.left : parent.right + top: parent.top + bottom: parent.bottom + margins: background.padding + } + } + + // A highlight that is shown when the content is expanded + Rectangle + { + id: expandedHighlight + width: parent.width + height: UM.Theme.getSize("thick_lining").height + color: UM.Theme.getColor("primary") + visible: expanded + anchors.bottom: parent.bottom + } + + UM.RecolorImage + { + id: collapseButton + anchors + { + right: parent.right + verticalCenter: parent.verticalCenter + margins: background.padding + } + source: expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left") + visible: source != "" + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + color: UM.Theme.getColor("small_button_text") + } + } + + MouseArea + { + id: mouseArea + anchors.fill: parent + onClicked: toggleContent() + hoverEnabled: true + onEntered: background.color = headerHoverColor + onExited: background.color = base.enabled ? headerBackgroundColor : UM.Theme.getColor("disabled") + } + } + + DropShadow + { + id: shadow + // Don't blur the shadow + radius: 0 + anchors.fill: background + source: background + verticalOffset: base.shadowOffset + visible: true + color: UM.Theme.getColor("action_button_shadow") + // Should always be drawn behind the background. + z: background.z - 1 + } + + Popup + { + id: content + + // Ensure that the content is located directly below the headerItem + y: background.height + base.shadowOffset + + // Make the content aligned with the rest, using the property contentAlignment to decide whether is right or left. + // In case of right alignment, the 3x padding is due to left, right and padding between the button & text. + x: contentAlignment == ExpandablePopup.ContentAlignment.AlignRight ? -width + collapseButton.width + headerItemLoader.width + 3 * background.padding : 0 + padding: UM.Theme.getSize("default_margin").width + closePolicy: Popup.CloseOnPressOutsideParent + + background: Cura.RoundedRectangle + { + cornerSide: Cura.RoundedRectangle.Direction.Down + color: contentBackgroundColor + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("lining") + radius: UM.Theme.getSize("default_radius").width + } + + contentItem: Item {} + + onContentItemChanged: + { + // Since we want the size of the content to be set by the size of the content, + // we need to do it like this. + content.width = contentItem.width + 2 * content.padding + content.height = contentItem.height + 2 * content.padding + } + } + + // DO NOT MOVE UP IN THE CODE: This connection has to be here, after the definition of the content item. + // Apparently the order in which these are handled matters and so the height is correctly updated if this is here. + Connections + { + // Since it could be that the content is dynamically populated, we should also take these changes into account. + target: content.contentItem + onWidthChanged: content.width = content.contentItem.width + 2 * content.padding + onHeightChanged: content.height = content.contentItem.height + 2 * content.padding + } +} diff --git a/resources/qml/ExtruderButton.qml b/resources/qml/ExtruderButton.qml index 2c1b80047e..feb399d528 100644 --- a/resources/qml/ExtruderButton.qml +++ b/resources/qml/ExtruderButton.qml @@ -2,80 +2,32 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 -import QtQuick.Controls 1.1 +import QtQuick.Controls 2.0 import UM 1.2 as UM import Cura 1.0 as Cura -Button +Cura.ToolbarButton { id: base - property var extruder; + property var extruder text: catalog.i18ncp("@label %1 is filled in with the name of an extruder", "Print Selected Model with %1", "Print Selected Models with %1", UM.Selection.selectionCount).arg(extruder.name) - style: UM.Theme.styles.tool_button; - iconSource: UM.Theme.getIcon("extruder_button") - checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1 enabled: UM.Selection.hasSelection && extruder.stack.isEnabled - property color customColor: base.hovered ? UM.Theme.getColor("button_hover") : UM.Theme.getColor("button"); - - Rectangle + toolItem: ExtruderIcon { - anchors.fill: parent - anchors.margins: UM.Theme.getSize("default_lining").width; - - color: "transparent" - - border.width: base.checked ? UM.Theme.getSize("default_lining").width : 0; - border.color: UM.Theme.getColor("button_text") - } - - Item - { - anchors.centerIn: parent - width: UM.Theme.getSize("default_margin").width - height: UM.Theme.getSize("default_margin").height - - Label - { - anchors.centerIn: parent; - text: index + 1; - color: parent.enabled ? UM.Theme.getColor("button_text") : UM.Theme.getColor("button_disabled_text") - font: UM.Theme.getFont("default_bold"); - } - } - - // Material colour circle - // Only draw the filling colour of the material inside the SVG border. - Rectangle - { - anchors - { - right: parent.right - top: parent.top - rightMargin: UM.Theme.getSize("extruder_button_material_margin").width - topMargin: UM.Theme.getSize("extruder_button_material_margin").height - } - - color: model.color - - width: UM.Theme.getSize("extruder_button_material").width - height: UM.Theme.getSize("extruder_button_material").height - radius: Math.round(width / 2) - - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("extruder_button_material_border") - - opacity: !base.enabled ? 0.2 : 1.0 + materialColor: extruder.color + extruderEnabled: extruder.stack.isEnabled + property int index: extruder.index } onClicked: { forceActiveFocus() //First grab focus, so all the text fields are updated - CuraActions.setExtruderForSelection(extruder.id); + CuraActions.setExtruderForSelection(extruder.id) } } diff --git a/resources/qml/ExtruderIcon.qml b/resources/qml/ExtruderIcon.qml new file mode 100644 index 0000000000..015ebea52e --- /dev/null +++ b/resources/qml/ExtruderIcon.qml @@ -0,0 +1,72 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.1 +import UM 1.2 as UM + +Item +{ + id: extruderIconItem + + implicitWidth: UM.Theme.getSize("extruder_icon").width + implicitHeight: UM.Theme.getSize("extruder_icon").height + + property bool checked: true + property color materialColor + property alias textColor: extruderNumberText.color + property bool extruderEnabled: true + + UM.RecolorImage + { + id: mainIcon + anchors.fill: parent + + source: UM.Theme.getIcon("extruder_button") + color: extruderEnabled ? materialColor: UM.Theme.getColor("disabled") + } + + Rectangle + { + id: extruderNumberCircle + + width: height + height: Math.round(parent.height / 2) + radius: Math.round(width / 2) + color: UM.Theme.getColor("toolbar_background") + + anchors + { + horizontalCenter: parent.horizontalCenter + top: parent.top + // The circle needs to be slightly off center (so it sits in the middle of the square bit of the icon) + topMargin: (parent.height - height) / 2 - 0.1 * parent.height + } + + Label + { + id: extruderNumberText + anchors.centerIn: parent + text: index + 1 + font: UM.Theme.getFont("small") + color: UM.Theme.getColor("text") + width: contentWidth + height: contentHeight + visible: extruderEnabled + renderType: Text.NativeRendering + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + UM.RecolorImage + { + id: disabledIcon + anchors.fill: parent + anchors.margins: UM.Theme.getSize("thick_lining").width + sourceSize.height: width + source: UM.Theme.getIcon("cross1") + visible: !extruderEnabled + color: UM.Theme.getColor("text") + } + } +} \ No newline at end of file diff --git a/resources/qml/IconWithText.qml b/resources/qml/IconWithText.qml new file mode 100644 index 0000000000..24b6dc7fe2 --- /dev/null +++ b/resources/qml/IconWithText.qml @@ -0,0 +1,70 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +// Reusable component that holds an (re-colorable) icon on the left with some text on the right. +// This component is also designed to be used with layouts. It will use the width of the text + icon as preferred width +// It sets the icon size + half of the content as its minium width (in which case it will elide the text) +Item +{ + property alias source: icon.source + property alias iconSize: icon.width + property alias iconColor: icon.color + property alias color: label.color + property alias text: label.text + property alias font: label.font + property real margin: UM.Theme.getSize("narrow_margin").width + + // These properties can be used in combination with layouts. + readonly property real contentWidth: icon.width + margin + label.contentWidth + readonly property real minContentWidth: Math.round(icon.width + margin + 0.5 * label.contentWidth) + + Layout.minimumWidth: minContentWidth + Layout.preferredWidth: contentWidth + Layout.fillHeight: true + Layout.fillWidth: true + + implicitWidth: icon.width + 100 + implicitHeight: icon.height + + UM.RecolorImage + { + id: icon + width: UM.Theme.getSize("section_icon").width + height: width + + color: UM.Theme.getColor("icon") + + anchors + { + left: parent.left + verticalCenter: parent.verticalCenter + } + } + + Label + { + id: label + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + renderType: Text.NativeRendering + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + + anchors + { + left: icon.right + right: parent.right + top: parent.top + bottom: parent.bottom + rightMargin: 0 + margins: margin + } + } +} \ No newline at end of file diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml index 1a5b604886..144616c22d 100644 --- a/resources/qml/JobSpecs.qml +++ b/resources/qml/JobSpecs.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 @@ -9,141 +9,145 @@ import QtQuick.Layouts 1.1 import UM 1.1 as UM import Cura 1.0 as Cura -Item { +Item +{ id: base property bool activity: CuraApplication.platformActivity property string fileBaseName: PrintInformation.baseName - UM.I18nCatalog { id: catalog; name:"cura"} + UM.I18nCatalog + { + id: catalog + name: "cura" + } + width: childrenRect.width height: childrenRect.height - onActivityChanged: { - if (activity == false) { + onActivityChanged: + { + if (!activity) + { //When there is no mesh in the buildplate; the printJobTextField is set to an empty string so it doesn't set an empty string as a jobName (which is later used for saving the file) - PrintInformation.baseName = '' + PrintInformation.baseName = "" } } - Rectangle + Item { id: jobNameRow anchors.top: parent.top - anchors.right: parent.right + anchors.left: parent.left height: UM.Theme.getSize("jobspecs_line").height - visible: base.activity - Item + Button { - width: parent.width - height: parent.height + id: printJobPencilIcon + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + width: UM.Theme.getSize("save_button_specs_icons").width + height: UM.Theme.getSize("save_button_specs_icons").height - Button + onClicked: { - id: printJobPencilIcon - 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 - - onClicked: - { - printJobTextfield.selectAll(); - printJobTextfield.focus = true; - } - 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: UM.Theme.getIcon("pencil"); - } - } - } + printJobTextfield.selectAll() + printJobTextfield.focus = true } - TextField + style: ButtonStyle { - id: printJobTextfield - anchors.right: printJobPencilIcon.left - anchors.rightMargin: Math.round(UM.Theme.getSize("default_margin").width / 2) - height: UM.Theme.getSize("jobspecs_line").height - width: Math.max(__contentWidth + UM.Theme.getSize("default_margin").width, 50) - maximumLength: 120 - property int unremovableSpacing: 5 - text: PrintInformation.jobName - horizontalAlignment: TextInput.AlignRight - onEditingFinished: { - var new_name = text == "" ? catalog.i18nc("@text Print job name", "Untitled") : text; - PrintInformation.setJobName(new_name, true); - printJobTextfield.focus = false; - } - validator: RegExpValidator { - regExp: /^[^\\\/\*\?\|\[\]]*$/ - } - style: TextFieldStyle{ - textColor: UM.Theme.getColor("text_scene"); - font: UM.Theme.getFont("default_bold"); - background: Rectangle { - opacity: 0 - border.width: 0 + 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: UM.Theme.getIcon("pencil") } } } } - } - Row { - id: additionalComponentsRow - anchors.top: jobNameRow.bottom - anchors.right: parent.right + TextField + { + id: printJobTextfield + anchors.left: printJobPencilIcon.right + anchors.leftMargin: UM.Theme.getSize("narrow_margin").width + height: UM.Theme.getSize("jobspecs_line").height + width: Math.max(__contentWidth + UM.Theme.getSize("default_margin").width, 50) + maximumLength: 120 + text: PrintInformation.jobName + horizontalAlignment: TextInput.AlignLeft + + onEditingFinished: + { + var new_name = text == "" ? catalog.i18nc("@text Print job name", "Untitled") : text + PrintInformation.setJobName(new_name, true) + printJobTextfield.focus = false + } + + validator: RegExpValidator { + regExp: /^[^\\\/\*\?\|\[\]]*$/ + } + + style: TextFieldStyle + { + textColor: UM.Theme.getColor("text_scene") + font: UM.Theme.getFont("default") + background: Rectangle + { + opacity: 0 + border.width: 0 + } + } + } } Label { id: boundingSpec anchors.top: jobNameRow.bottom - anchors.right: additionalComponentsRow.left - anchors.rightMargin: - { - if (additionalComponentsRow.width > 0) - { - return UM.Theme.getSize("default_margin").width - } - else - { - return 0; - } - } + anchors.left: parent.left + height: UM.Theme.getSize("jobspecs_line").height verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("small") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text_scene") text: CuraApplication.getSceneBoundingBoxString } - Component.onCompleted: { + Row + { + id: additionalComponentsRow + anchors.top: boundingSpec.top + anchors.bottom: boundingSpec.bottom + anchors.left: boundingSpec.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + } + + Component.onCompleted: + { base.addAdditionalComponents("jobSpecsButton") } - Connections { + Connections + { target: CuraApplication onAdditionalComponentsChanged: base.addAdditionalComponents("jobSpecsButton") } - function addAdditionalComponents (areaId) { - if(areaId == "jobSpecsButton") { - for (var component in CuraApplication.additionalComponents["jobSpecsButton"]) { + function addAdditionalComponents(areaId) + { + if (areaId == "jobSpecsButton") + { + for (var component in CuraApplication.additionalComponents["jobSpecsButton"]) + { CuraApplication.additionalComponents["jobSpecsButton"][component].parent = additionalComponentsRow } } } - } diff --git a/resources/qml/MachineSelection.qml b/resources/qml/MachineSelection.qml deleted file mode 100644 index 7a8a6b476b..0000000000 --- a/resources/qml/MachineSelection.qml +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2017 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 UM 1.2 as UM -import Cura 1.0 as Cura -import "Menus" - -ToolButton -{ - id: base - property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" - property bool printerConnected: Cura.MachineManager.printerConnected - property var printerStatus: Cura.MachineManager.printerConnected ? "connected" : "disconnected" - text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName - - tooltip: Cura.MachineManager.activeMachineName - - style: ButtonStyle - { - background: Rectangle - { - color: - { - if (control.pressed) { - return UM.Theme.getColor("sidebar_header_active"); - } - else if (control.hovered) { - return UM.Theme.getColor("sidebar_header_hover"); - } - else { - return UM.Theme.getColor("sidebar_header_bar"); - } - } - Behavior on color { ColorAnimation { duration: 50; } } - - UM.RecolorImage - { - id: downArrow - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: width - color: UM.Theme.getColor("text_emphasis") - source: UM.Theme.getIcon("arrow_bottom") - } - - PrinterStatusIcon - { - id: printerStatusIcon - visible: printerConnected || isNetworkPrinter - status: printerStatus - anchors - { - verticalCenter: parent.verticalCenter - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - } - } - - Label - { - id: sidebarComboBoxLabel - color: UM.Theme.getColor("sidebar_header_text_active") - text: control.text; - elide: Text.ElideRight; - anchors.left: printerStatusIcon.visible ? printerStatusIcon.right : parent.left; - anchors.leftMargin: printerStatusIcon.visible ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width - anchors.right: downArrow.left; - anchors.rightMargin: control.rightMargin; - anchors.verticalCenter: parent.verticalCenter; - font: UM.Theme.getFont("medium_bold") - } - } - label: Label {} - } - - menu: PrinterMenu { } -} diff --git a/resources/qml/MainWindow/ApplicationMenu.qml b/resources/qml/MainWindow/ApplicationMenu.qml new file mode 100644 index 0000000000..a694b8e403 --- /dev/null +++ b/resources/qml/MainWindow/ApplicationMenu.qml @@ -0,0 +1,163 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.2 + +import UM 1.3 as UM +import Cura 1.1 as Cura + +import "../Menus" +import "../Dialogs" + +Item +{ + id: menu + width: applicationMenu.width + height: applicationMenu.height + property alias window: applicationMenu.window + + UM.ApplicationMenu + { + id: applicationMenu + + FileMenu { title: catalog.i18nc("@title:menu menubar:toplevel", "&File") } + + Menu + { + title: catalog.i18nc("@title:menu menubar:toplevel", "&Edit") + + MenuItem { action: Cura.Actions.undo } + MenuItem { action: Cura.Actions.redo } + MenuSeparator { } + MenuItem { action: Cura.Actions.selectAll } + MenuItem { action: Cura.Actions.arrangeAll } + MenuItem { action: Cura.Actions.deleteSelection } + MenuItem { action: Cura.Actions.deleteAll } + MenuItem { action: Cura.Actions.resetAllTranslation } + MenuItem { action: Cura.Actions.resetAll } + MenuSeparator { } + MenuItem { action: Cura.Actions.groupObjects } + MenuItem { action: Cura.Actions.mergeObjects } + MenuItem { action: Cura.Actions.unGroupObjects } + } + + ViewMenu { title: catalog.i18nc("@title:menu menubar:toplevel", "&View") } + + SettingsMenu { title: catalog.i18nc("@title:menu menubar:toplevel", "&Settings") } + + Menu + { + id: extensionMenu + title: catalog.i18nc("@title:menu menubar:toplevel", "E&xtensions") + + Instantiator + { + id: extensions + model: UM.ExtensionModel { } + + Menu + { + id: sub_menu + title: model.name; + visible: actions != null + enabled: actions != null + Instantiator + { + model: actions + MenuItem + { + text: model.text + onTriggered: extensions.model.subMenuTriggered(name, model.text) + } + onObjectAdded: sub_menu.insertItem(index, object) + onObjectRemoved: sub_menu.removeItem(object) + } + } + + onObjectAdded: extensionMenu.insertItem(index, object) + onObjectRemoved: extensionMenu.removeItem(object) + } + } + + Menu + { + id: preferencesMenu + title: catalog.i18nc("@title:menu menubar:toplevel", "P&references") + + MenuItem { action: Cura.Actions.preferences } + } + + Menu + { + id: helpMenu + title: catalog.i18nc("@title:menu menubar:toplevel", "&Help") + + MenuItem { action: Cura.Actions.showProfileFolder } + MenuItem { action: Cura.Actions.documentation } + MenuItem { action: Cura.Actions.reportBug } + MenuSeparator { } + MenuItem { action: Cura.Actions.about } + } + } + + // ############################################################################################### + // Definition of other components that are linked to the menus + // ############################################################################################### + + WorkspaceSummaryDialog + { + id: saveWorkspaceDialog + property var args + onYes: UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, args) + } + + MessageDialog + { + id: newProjectDialog + modality: Qt.ApplicationModal + title: catalog.i18nc("@title:window", "New project") + text: catalog.i18nc("@info:question", "Are you sure you want to start a new project? This will clear the build plate and any unsaved settings.") + standardButtons: StandardButton.Yes | StandardButton.No + icon: StandardIcon.Question + onYes: + { + CuraApplication.deleteAll(); + Cura.Actions.resetProfile.trigger(); + } + } + + UM.ExtensionModel + { + id: curaExtensions + } + + // ############################################################################################### + // Definition of all the connections + // ############################################################################################### + + Connections + { + target: Cura.Actions.newProject + onTriggered: + { + if(Printer.platformActivity || Cura.MachineManager.hasUserSettings) + { + newProjectDialog.visible = true + } + } + } + + // show the plugin browser dialog + Connections + { + target: Cura.Actions.browsePackages + onTriggered: + { + curaExtensions.callExtensionMethod("Toolbox", "browsePackages") + } + } +} \ No newline at end of file diff --git a/resources/qml/MainWindow/MainWindowHeader.qml b/resources/qml/MainWindow/MainWindowHeader.qml new file mode 100644 index 0000000000..3e296ead40 --- /dev/null +++ b/resources/qml/MainWindow/MainWindowHeader.qml @@ -0,0 +1,129 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 as Controls2 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.1 + +import UM 1.4 as UM +import Cura 1.0 as Cura +import QtGraphicalEffects 1.0 + +import "../Account" + +Item +{ + id: base + + implicitHeight: UM.Theme.getSize("main_window_header").height + implicitWidth: UM.Theme.getSize("main_window_header").width + + Image + { + id: logo + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.verticalCenter: parent.verticalCenter + + source: UM.Theme.getImage("logo") + width: UM.Theme.getSize("logo").width + height: UM.Theme.getSize("logo").height + + sourceSize.width: width + sourceSize.height: height + } + + Row + { + id: stagesListContainer + spacing: Math.round(UM.Theme.getSize("default_margin").width / 2) + + anchors + { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + leftMargin: UM.Theme.getSize("default_margin").width + } + + // The main window header is dynamically filled with all available stages + Repeater + { + id: stagesHeader + + model: UM.StageModel { } + + delegate: Button + { + text: model.name.toUpperCase() + checkable: true + checked: UM.Controller.activeStage !== null && model.id == UM.Controller.activeStage.stageId + + anchors.verticalCenter: parent.verticalCenter + exclusiveGroup: mainWindowHeaderMenuGroup + style: UM.Theme.styles.main_window_header_tab + height: UM.Theme.getSize("main_window_header_button").height + iconSource: model.stage.iconSource + + property color overlayColor: "transparent" + property string overlayIconSource: "" + + // This is a trick to assure the activeStage is correctly changed. It doesn't work propertly if done in the onClicked (see CURA-6028) + MouseArea + { + anchors.fill: parent + onClicked: UM.Controller.setActiveStage(model.id) + } + } + } + + ExclusiveGroup { id: mainWindowHeaderMenuGroup } + } + + // Shortcut button to quick access the Toolbox + Controls2.Button + { + id: marketplaceButton + text: catalog.i18nc("@action:button", "Marketplace") + height: Math.round(0.5 * UM.Theme.getSize("main_window_header").height) + onClicked: Cura.Actions.browsePackages.trigger() + + hoverEnabled: true + + background: Rectangle + { + radius: UM.Theme.getSize("action_button_radius").width + color: marketplaceButton.hovered ? UM.Theme.getColor("primary_text") : UM.Theme.getColor("main_window_header_background") + border.width: UM.Theme.getSize("default_lining").width + border.color: UM.Theme.getColor("primary_text") + } + + contentItem: Label + { + id: label + text: marketplaceButton.text + font: UM.Theme.getFont("default") + color: marketplaceButton.hovered ? UM.Theme.getColor("main_window_header_background") : UM.Theme.getColor("primary_text") + width: contentWidth + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + } + + anchors + { + right: accountWidget.left + rightMargin: UM.Theme.getSize("default_margin").width + verticalCenter: parent.verticalCenter + } + } + + AccountWidget + { + id: accountWidget + anchors + { + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + } + } +} diff --git a/resources/qml/Menus/ConfigurationMenu/AutoConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/AutoConfiguration.qml new file mode 100644 index 0000000000..18409dd43a --- /dev/null +++ b/resources/qml/Menus/ConfigurationMenu/AutoConfiguration.qml @@ -0,0 +1,39 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.3 as UM +import Cura 1.0 as Cura + +Item +{ + width: parent.width + height: childrenRect.height + + Label + { + id: header + text: catalog.i18nc("@header", "Configurations") + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("small_button_text") + height: contentHeight + renderType: Text.NativeRendering + + anchors + { + left: parent.left + right: parent.right + } + } + + ConfigurationListView + { + anchors.top: header.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").width + width: parent.width + + outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null + } +} \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index 942dd81d9c..058c1ff4c2 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -7,51 +7,153 @@ import QtQuick.Controls 2.0 import UM 1.2 as UM import Cura 1.0 as Cura -Rectangle +Button { id: configurationItem property var configuration: null - property var selected: false - signal activateConfiguration() + hoverEnabled: isValidMaterial - height: childrenRect.height - border.width: UM.Theme.getSize("default_lining").width - border.color: updateBorderColor() - color: selected ? UM.Theme.getColor("configuration_item_active") : UM.Theme.getColor("configuration_item") - property var textColor: selected ? UM.Theme.getColor("configuration_item_text_active") : UM.Theme.getColor("configuration_item_text") - - function updateBorderColor() + property bool isValidMaterial: { - border.color = selected ? UM.Theme.getColor("configuration_item_border_active") : UM.Theme.getColor("configuration_item_border") + var extruderConfigurations = configuration.extruderConfigurations + + for (var index in extruderConfigurations) + { + var name = extruderConfigurations[index].material ? extruderConfigurations[index].material.name : "" + + if (name == "" || name == "Unknown") + { + return false + } + } + return true } - Column + background: Rectangle + { + color: parent.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") + border.color: parent.checked ? UM.Theme.getColor("primary") : UM.Theme.getColor("lining") + border.width: UM.Theme.getSize("default_lining").width + radius: UM.Theme.getSize("default_radius").width + } + + contentItem: Column { id: contentColumn width: parent.width padding: UM.Theme.getSize("default_margin").width - spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) + spacing: UM.Theme.getSize("narrow_margin").height Row { id: extruderRow - width: parent.width - 2 * parent.padding + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("wide_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("wide_margin").width + } height: childrenRect.height - spacing: UM.Theme.getSize("default_margin").width Repeater { id: repeater - height: childrenRect.height model: configuration.extruderConfigurations + delegate: PrintCoreConfiguration { width: Math.round(parent.width / 2) printCoreConfiguration: modelData - mainColor: textColor + visible: configurationItem.isValidMaterial + } + } + + // Unknown material + Item + { + id: unknownMaterial + height: unknownMaterialMessage.height + UM.Theme.getSize("thin_margin").width / 2 + width: parent.width + + anchors.top: parent.top + anchors.topMargin: UM.Theme.getSize("thin_margin").width / 2 + + visible: !configurationItem.isValidMaterial + + UM.RecolorImage + { + id: icon + anchors.verticalCenter: unknownMaterialMessage.verticalCenter + + source: UM.Theme.getIcon("warning") + color: UM.Theme.getColor("warning") + width: UM.Theme.getSize("section_icon").width + height: width + } + + Label + { + id: unknownMaterialMessage + text: + { + var extruderConfigurations = configuration.extruderConfigurations + var unknownMaterials = [] + for (var index in extruderConfigurations) + { + var name = extruderConfigurations[index].material ? extruderConfigurations[index].material.name : "" + if (name == "" || name == "Unknown") + { + var materialType = extruderConfigurations[index].material.type + if (extruderConfigurations[index].material.type == "") + { + materialType = "Unknown" + } + + var brand = extruderConfigurations[index].material.brand + if (brand == "") + { + brand = "Unknown" + } + + name = materialType + " (" + brand + ")" + unknownMaterials.push(name) + } + } + + unknownMaterials = "" + unknownMaterials + "" + var draftResult = catalog.i18nc("@label", "This configuration is not available because %1 is not recognized. Please visit %2 to download the correct material profile."); + var result = draftResult.arg(unknownMaterials).arg("" + catalog.i18nc("@label","Marketplace") + " ") + + return result + } + width: extruderRow.width + + anchors.left: icon.right + anchors.right: unknownMaterial.right + anchors.leftMargin: UM.Theme.getSize("wide_margin").height + anchors.top: unknownMaterial.top + + wrapMode: Text.WordWrap + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + verticalAlignment: Text.AlignVCenter + linkColor: UM.Theme.getColor("text_link") + + onLinkActivated: + { + Cura.Actions.browsePackages.trigger() + } + } + + MouseArea + { + anchors.fill: parent + cursorShape: unknownMaterialMessage.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + acceptedButtons: Qt.NoButton } } } @@ -62,63 +164,38 @@ Rectangle id: separator visible: buildplateInformation.visible - width: parent.width - 2 * parent.padding - height: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0 - color: textColor + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("wide_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("wide_margin").width + } + height: visible ? Math.round(UM.Theme.getSize("default_lining").height / 2) : 0 + color: UM.Theme.getColor("lining") } Item { id: buildplateInformation - width: parent.width - 2 * parent.padding - height: childrenRect.height - visible: configuration.buildplateConfiguration != "" - UM.RecolorImage { - id: buildplateIcon - anchors.left: parent.left - width: UM.Theme.getSize("topbar_button_icon").width - height: UM.Theme.getSize("topbar_button_icon").height - sourceSize.width: width - sourceSize.height: height - source: UM.Theme.getIcon("buildplate") - color: textColor + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("wide_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("wide_margin").width } + height: childrenRect.height + visible: configuration.buildplateConfiguration != "" && false //Buildplate is disabled as long as we have no printers that properly support buildplate swapping (so we can't test). - Label + // Show the type of buildplate. The first letter is capitalized + Cura.IconWithText { id: buildplateLabel - anchors.left: buildplateIcon.right - anchors.verticalCenter: buildplateIcon.verticalCenter - anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").height / 2) - text: configuration.buildplateConfiguration - renderType: Text.NativeRendering - color: textColor - } - } - } - - MouseArea - { - id: mouse - anchors.fill: parent - onClicked: activateConfiguration() - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onEntered: - { - parent.border.color = UM.Theme.getColor("configuration_item_border_hover") - if (configurationItem.selected == false) - { - configurationItem.color = UM.Theme.getColor("sidebar_lining") - } - } - onExited: - { - updateBorderColor() - if (configurationItem.selected == false) - { - configurationItem.color = UM.Theme.getColor("configuration_item") + source: UM.Theme.getIcon("buildplate") + text: configuration.buildplateConfiguration.charAt(0).toUpperCase() + configuration.buildplateConfiguration.substr(1) + anchors.left: parent.left } } } @@ -126,24 +203,22 @@ Rectangle Connections { target: Cura.MachineManager - onCurrentConfigurationChanged: { - configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) - updateBorderColor() + onCurrentConfigurationChanged: + { + configurationItem.checked = Cura.MachineManager.matchesConfiguration(configuration) } } Component.onCompleted: { - configurationItem.selected = Cura.MachineManager.matchesConfiguration(configuration) - updateBorderColor() + configurationItem.checked = Cura.MachineManager.matchesConfiguration(configuration) } - onVisibleChanged: + onClicked: { - if(visible) + if(isValidMaterial) { - // I cannot trigger function updateBorderColor() after visibility change - color = selected ? UM.Theme.getColor("configuration_item_active") : UM.Theme.getColor("configuration_item") + Cura.MachineManager.applyRemoteConfiguration(configuration); } } -} \ No newline at end of file +} diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 7aaf87b4df..15d882fdf5 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -2,85 +2,121 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.3 import UM 1.2 as UM import Cura 1.0 as Cura -Column +Item { id: base property var outputDevice: null - property var computedHeight: container.height + configurationListHeading.height + 3 * padding - height: childrenRect.height + 2 * padding - padding: UM.Theme.getSize("default_margin").width - spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) + height: childrenRect.height function forceModelUpdate() { - // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI + // FIXME For now the model has to be removed and then created again, otherwise changes in the printer don't automatically update the UI configurationList.model = [] - if(outputDevice) + if (outputDevice) { configurationList.model = outputDevice.uniqueConfigurations } } - Label + // This component will appear when there are no configurations (e.g. when losing connection or when they are being loaded) + Item { - id: configurationListHeading - text: catalog.i18nc("@label:header configurations", "Available configurations") - font: UM.Theme.getFont("large") - width: parent.width - 2 * parent.padding - color: UM.Theme.getColor("configuration_item_text") - } + width: parent.width + visible: configurationList.model.length == 0 + height: label.height + UM.Theme.getSize("wide_margin").height + anchors.top: parent.top + anchors.topMargin: UM.Theme.getSize("default_margin").height - Component - { - id: sectionHeading - Rectangle + UM.RecolorImage { - height: childrenRect.height + UM.Theme.getSize("default_margin").height - Label - { - text: section - font: UM.Theme.getFont("default_bold") - color: UM.Theme.getColor("configuration_item_text") - } + id: icon + + anchors.left: parent.left + anchors.verticalCenter: label.verticalCenter + + source: UM.Theme.getIcon("warning") + color: UM.Theme.getColor("warning") + width: UM.Theme.getSize("section_icon").width + height: width + } + + Label + { + id: label + anchors.left: icon.right + anchors.right: parent.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + // There are two cases that we want to diferenciate, one is when Cura is loading the configurations and the + // other when the connection was lost + text: Cura.MachineManager.printerConnected ? + catalog.i18nc("@label", "Loading available configurations from the printer...") : + catalog.i18nc("@label", "The configurations are not available because the printer is disconnected.") + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + wrapMode: Text.WordWrap } } ScrollView { id: container - width: parent.width - parent.padding - height: Math.min(configurationList.contentHeight, 350 * screenScaleFactor) + width: parent.width + readonly property int maximumHeight: 350 * screenScaleFactor + height: Math.round(Math.min(configurationList.height, maximumHeight)) + contentHeight: configurationList.height + clip: true - style: UM.Theme.styles.scrollview - __wheelAreaScrollSpeed: 75 // Scroll three lines in one scroll event + ScrollBar.vertical.policy: (configurationList.height > maximumHeight) ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff //The AsNeeded policy also hides it when the cursor is away, and we don't want that. + ScrollBar.vertical.background: Rectangle + { + implicitWidth: UM.Theme.getSize("scrollbar").width + radius: width / 2 + color: UM.Theme.getColor("scrollbar_background") + } + ScrollBar.vertical.contentItem: Rectangle + { + implicitWidth: UM.Theme.getSize("scrollbar").width + radius: width / 2 + color: UM.Theme.getColor(parent.pressed ? "scrollbar_handle_down" : parent.hovered ? "scrollbar_handle_hover" : "scrollbar_handle") + } + + ButtonGroup + { + buttons: configurationList.children + } ListView { id: configurationList - spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) - width: container.width - contentHeight: childrenRect.height + spacing: UM.Theme.getSize("narrow_margin").height + width: container.width - ((height > container.maximumHeight) ? container.ScrollBar.vertical.background.width : 0) //Make room for scroll bar if there is any. + height: childrenRect.height section.property: "modelData.printerType" section.criteria: ViewSection.FullString - section.delegate: sectionHeading + section.delegate: Item + { + height: printerTypeLabel.height + UM.Theme.getSize("wide_margin").height //Causes a default margin above the label and a default margin below the label. + Cura.PrinterTypeLabel + { + id: printerTypeLabel + text: Cura.MachineManager.getAbbreviatedMachineName(section) + anchors.verticalCenter: parent.verticalCenter //One default margin above and one below. + } + } model: (outputDevice != null) ? outputDevice.uniqueConfigurations : [] + delegate: ConfigurationItem { - width: parent.width - UM.Theme.getSize("default_margin").width + width: parent.width configuration: modelData - onActivateConfiguration: - { - switchPopupState() - Cura.MachineManager.applyRemoteConfiguration(configuration) - } } } } @@ -102,4 +138,4 @@ Column forceModelUpdate() } } -} \ No newline at end of file +} diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationMenu.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationMenu.qml new file mode 100644 index 0000000000..86cb7f9acf --- /dev/null +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationMenu.qml @@ -0,0 +1,290 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Controls.Styles 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + + +/** + * Menu that allows you to select the configuration of the current printer, such + * as the nozzle sizes and materials in each extruder. + */ +Cura.ExpandablePopup +{ + id: base + + property var extrudersModel: CuraApplication.getExtrudersModel() + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + enum ConfigurationMethod + { + Auto, + Custom + } + + contentPadding: UM.Theme.getSize("default_lining").width + enabled: Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants || Cura.MachineManager.hasVariantBuildplates; //Only let it drop down if there is any configuration that you could change. + + headerItem: Item + { + // Horizontal list that shows the extruders and their materials + ListView + { + id: extrudersList + + orientation: ListView.Horizontal + anchors.fill: parent + model: extrudersModel + visible: Cura.MachineManager.hasMaterials + + delegate: Item + { + height: parent.height + width: Math.round(ListView.view.width / extrudersModel.count) + + // Extruder icon. Shows extruder index and has the same color as the active material. + Cura.ExtruderIcon + { + id: extruderIcon + materialColor: model.color + extruderEnabled: model.enabled + height: parent.height + width: height + } + + // Label for the brand of the material + Label + { + id: brandNameLabel + + text: model.material_brand + elide: Text.ElideRight + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text_inactive") + renderType: Text.NativeRendering + + anchors + { + left: extruderIcon.right + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + } + } + + // Label that shows the name of the material + Label + { + text: model.material + elide: Text.ElideRight + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text") + renderType: Text.NativeRendering + + anchors + { + left: extruderIcon.right + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + top: brandNameLabel.bottom + } + } + } + } + + //Placeholder text if there is a configuration to select but no materials (so we can't show the materials per extruder). + Label + { + text: catalog.i18nc("@label", "Select configuration") + elide: Text.ElideRight + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text") + renderType: Text.NativeRendering + + visible: !Cura.MachineManager.hasMaterials && (Cura.MachineManager.hasVariants || Cura.MachineManager.hasVariantBuildplates) + + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + verticalCenter: parent.verticalCenter + } + } + } + + contentItem: Column + { + id: popupItem + width: UM.Theme.getSize("configuration_selector").width + height: implicitHeight // Required because ExpandableComponent will try to use this to determine the size of the background of the pop-up. + padding: UM.Theme.getSize("default_margin").height + spacing: UM.Theme.getSize("default_margin").height + + property bool is_connected: false // If current machine is connected to a printer. Only evaluated upon making popup visible. + property int configuration_method: ConfigurationMenu.ConfigurationMethod.Custom // Type of configuration being used. Only evaluated upon making popup visible. + property int manual_selected_method: -1 // It stores the configuration method selected by the user. By default the selected method is + + onVisibleChanged: + { + is_connected = Cura.MachineManager.activeMachineHasRemoteConnection && Cura.MachineManager.printerConnected && Cura.MachineManager.printerOutputDevices[0].uniqueConfigurations.length > 0 //Re-evaluate. + + // If the printer is not connected or does not have configurations, we switch always to the custom mode. If is connected instead, the auto mode + // or the previous state is selected + configuration_method = is_connected ? (manual_selected_method == -1 ? ConfigurationMenu.ConfigurationMethod.Auto : manual_selected_method) : ConfigurationMenu.ConfigurationMethod.Custom + } + + Item + { + width: parent.width - 2 * parent.padding + height: + { + var height = 0 + if (autoConfiguration.visible) + { + height += autoConfiguration.height + } + if (customConfiguration.visible) + { + height += customConfiguration.height + } + return height + } + + AutoConfiguration + { + id: autoConfiguration + visible: popupItem.configuration_method == ConfigurationMenu.ConfigurationMethod.Auto + } + + CustomConfiguration + { + id: customConfiguration + visible: popupItem.configuration_method == ConfigurationMenu.ConfigurationMethod.Custom + } + } + + Item + { + height: visible ? childrenRect.height: 0 + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("default_margin").width + width: childrenRect.width + UM.Theme.getSize("default_margin").width + visible: popupItem.configuration_method == ConfigurationMenu.ConfigurationMethod.Custom + UM.RecolorImage + { + id: externalLinkIcon + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("default_margin").width + height: materialInfoLabel.height + width: height + sourceSize.height: width + color: UM.Theme.getColor("text_link") + source: UM.Theme.getIcon("external_link") + } + + Label + { + id: materialInfoLabel + wrapMode: Text.WordWrap + text: catalog.i18nc("@label", "See the material compatibility chart") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text_link") + linkColor: UM.Theme.getColor("text_link") + anchors.left: externalLinkIcon.right + anchors.leftMargin: UM.Theme.getSize("narrow_margin").width + renderType: Text.NativeRendering + + MouseArea + { + anchors.fill: parent + hoverEnabled: true + onClicked: + { + // open the material URL with web browser + var url = "https://ultimaker.com/incoming-links/cura/material-compatibilty" + Qt.openUrlExternally(url) + } + onEntered: + { + materialInfoLabel.font.underline = true + } + onExited: + { + materialInfoLabel.font.underline = false + } + } + } + } + + Rectangle + { + id: separator + visible: buttonBar.visible + x: -parent.padding + + width: parent.width + height: UM.Theme.getSize("default_lining").height + + color: UM.Theme.getColor("lining") + } + + //Allow switching between custom and auto. + Item + { + id: buttonBar + visible: popupItem.is_connected //Switching only makes sense if the "auto" part is possible. + + width: parent.width - 2 * parent.padding + height: childrenRect.height + + Cura.SecondaryButton + { + id: goToCustom + visible: popupItem.configuration_method == ConfigurationMenu.ConfigurationMethod.Auto + text: catalog.i18nc("@label", "Custom") + + anchors.right: parent.right + + iconSource: UM.Theme.getIcon("arrow_right") + isIconOnRightSide: true + + onClicked: + { + popupItem.configuration_method = ConfigurationMenu.ConfigurationMethod.Custom + popupItem.manual_selected_method = popupItem.configuration_method + } + } + + Cura.SecondaryButton + { + id: goToAuto + visible: popupItem.configuration_method == ConfigurationMenu.ConfigurationMethod.Custom + text: catalog.i18nc("@label", "Configurations") + + iconSource: UM.Theme.getIcon("arrow_left") + + onClicked: + { + popupItem.configuration_method = ConfigurationMenu.ConfigurationMethod.Auto + popupItem.manual_selected_method = popupItem.configuration_method + } + } + } + } + + Connections + { + target: Cura.MachineManager + onGlobalContainerChanged: popupItem.manual_selected_method = -1 // When switching printers, reset the value of the manual selected method + } +} diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml deleted file mode 100644 index d7ee2c68ee..0000000000 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationSelection.qml +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Controls.Styles 1.4 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -Item -{ - id: configurationSelector - property var connectedDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null - property var panelWidth: control.width - - function switchPopupState() - { - popup.visible ? popup.close() : popup.open() - } - - SyncButton - { - id: syncButton - onClicked: switchPopupState() - outputDevice: connectedDevice - } - - Popup - { - // TODO Change once updating to Qt5.10 - The 'opened' property is in 5.10 but the behavior is now implemented with the visible property - id: popup - clip: true - closePolicy: Popup.CloseOnPressOutsideParent - y: configurationSelector.height - UM.Theme.getSize("default_lining").height - x: configurationSelector.width - width - width: panelWidth - visible: false - padding: UM.Theme.getSize("default_lining").width - transformOrigin: Popup.Top - contentItem: ConfigurationListView - { - id: configList - width: panelWidth - 2 * popup.padding - outputDevice: connectedDevice - } - background: Rectangle - { - color: UM.Theme.getColor("setting_control") - border.color: UM.Theme.getColor("setting_control_border") - } - exit: Transition - { - // This applies a default NumberAnimation to any changes a state change makes to x or y properties - NumberAnimation { property: "visible"; duration: 75; } - } - enter: Transition - { - // This applies a default NumberAnimation to any changes a state change makes to x or y properties - NumberAnimation { property: "visible"; duration: 75; } - } - onClosed: visible = false - onOpened: visible = true - } -} \ No newline at end of file diff --git a/resources/qml/Menus/ConfigurationMenu/CustomConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/CustomConfiguration.qml new file mode 100644 index 0000000000..5cecda4e5c --- /dev/null +++ b/resources/qml/Menus/ConfigurationMenu/CustomConfiguration.qml @@ -0,0 +1,293 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.6 +import QtQuick.Controls 2.0 +import QtQuick.Controls 1.1 as OldControls + +import Cura 1.0 as Cura +import UM 1.3 as UM + +Item +{ + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + width: parent.width + height: childrenRect.height + + Label + { + id: header + text: catalog.i18nc("@header", "Custom") + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("small_button_text") + height: contentHeight + renderType: Text.NativeRendering + + anchors + { + top: parent.top + left: parent.left + right: parent.right + } + } + + //Printer type selector. + Item + { + id: printerTypeSelectorRow + visible: + { + return Cura.MachineManager.printerOutputDevices.length >= 1 //If connected... + && Cura.MachineManager.printerOutputDevices[0].connectedPrintersTypeCount != null //...and we have configuration information... + && Cura.MachineManager.printerOutputDevices[0].connectedPrintersTypeCount.length > 1; //...and there is more than one type of printer in the configuration list. + } + height: visible ? childrenRect.height : 0 + + anchors + { + left: parent.left + right: parent.right + top: header.bottom + topMargin: visible ? UM.Theme.getSize("default_margin").height : 0 + } + + Label + { + text: catalog.i18nc("@label", "Printer") + width: Math.round(parent.width * 0.3) - UM.Theme.getSize("default_margin").width + height: contentHeight + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + anchors.verticalCenter: printerTypeSelector.verticalCenter + anchors.left: parent.left + } + + OldControls.ToolButton + { + id: printerTypeSelector + text: Cura.MachineManager.activeMachineDefinitionName + tooltip: Cura.MachineManager.activeMachineDefinitionName + height: UM.Theme.getSize("print_setup_big_item").height + width: Math.round(parent.width * 0.7) + UM.Theme.getSize("default_margin").width + anchors.right: parent.right + style: UM.Theme.styles.print_setup_header_button + + menu: Cura.PrinterTypeMenu { } + } + } + + UM.TabRow + { + id: tabBar + anchors.top: printerTypeSelectorRow.bottom + anchors.topMargin: UM.Theme.getSize("default_margin").height + visible: extrudersModel.count > 1 + + Repeater + { + id: repeater + model: extrudersModel + delegate: UM.TabRowButton + { + contentItem: Item + { + Cura.ExtruderIcon + { + anchors.horizontalCenter: parent.horizontalCenter + materialColor: model.color + extruderEnabled: model.enabled + width: parent.height + height: parent.height + } + } + onClicked: + { + Cura.ExtruderManager.setActiveExtruderIndex(tabBar.currentIndex) + } + } + } + + //When active extruder changes for some other reason, switch tabs. + //Don't directly link currentIndex to Cura.ExtruderManager.activeExtruderIndex! + //This causes a segfault in Qt 5.11. Something with VisualItemModel removing index -1. We have to use setCurrentIndex instead. + Connections + { + target: Cura.ExtruderManager + onActiveExtruderChanged: + { + tabBar.setCurrentIndex(Cura.ExtruderManager.activeExtruderIndex); + } + } + + //When the model of the extruders is rebuilt, the list of extruders is briefly emptied and rebuilt. + //This causes the currentIndex of the tab to be in an invalid position which resets it to 0. + //Therefore we need to change it back to what it was: The active extruder index. + Connections + { + target: repeater.model + onModelChanged: + { + tabBar.setCurrentIndex(Cura.ExtruderManager.activeExtruderIndex) + } + } + } + + Rectangle + { + width: parent.width + height: childrenRect.height + anchors.top: tabBar.bottom + + radius: tabBar.visible ? UM.Theme.getSize("default_radius").width : 0 + border.width: tabBar.visible ? UM.Theme.getSize("default_lining").width : 0 + border.color: UM.Theme.getColor("lining") + color: UM.Theme.getColor("main_background") + + //Remove rounding and lining at the top. + Rectangle + { + width: parent.width + height: parent.radius + anchors.top: parent.top + color: UM.Theme.getColor("lining") + visible: tabBar.visible + Rectangle + { + anchors + { + left: parent.left + leftMargin: parent.parent.border.width + right: parent.right + rightMargin: parent.parent.border.width + top: parent.top + } + height: parent.parent.radius + color: parent.parent.color + } + } + + Column + { + id: selectors + padding: UM.Theme.getSize("default_margin").width + spacing: UM.Theme.getSize("default_margin").height + + property var model: extrudersModel.items[tabBar.currentIndex] + + readonly property real paddedWidth: parent.width - padding * 2 + property real textWidth: Math.round(paddedWidth * 0.3) + property real controlWidth: paddedWidth - textWidth + + Row + { + height: UM.Theme.getSize("print_setup_item").height + visible: extrudersModel.count > 1 // If there is only one extruder, there is no point to enable/disable that. + + Label + { + text: catalog.i18nc("@label", "Enabled") + verticalAlignment: Text.AlignVCenter + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + height: parent.height + width: selectors.textWidth + renderType: Text.NativeRendering + } + + OldControls.CheckBox + { + checked: Cura.MachineManager.activeStack != null ? Cura.MachineManager.activeStack.isEnabled : false + enabled: !checked || Cura.MachineManager.numberExtrudersEnabled > 1 //Disable if it's the last enabled extruder. + height: UM.Theme.getSize("setting_control").height + style: UM.Theme.styles.checkbox + + /* Use a MouseArea to process the click on this checkbox. + This is necessary because actually clicking the checkbox + causes the "checked" property to be overwritten. After + it's been overwritten, the original link that made it + depend on the active extruder stack is broken. */ + MouseArea + { + anchors.fill: parent + onClicked: Cura.MachineManager.setExtruderEnabled(Cura.ExtruderManager.activeExtruderIndex, !parent.checked) + enabled: parent.enabled + } + } + } + + Row + { + height: UM.Theme.getSize("print_setup_big_item").height + visible: Cura.MachineManager.hasMaterials + + Label + { + text: catalog.i18nc("@label", "Material") + verticalAlignment: Text.AlignVCenter + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + height: parent.height + width: selectors.textWidth + renderType: Text.NativeRendering + } + + OldControls.ToolButton + { + id: materialSelection + + property bool valueError: Cura.MachineManager.activeStack != null ? Cura.ContainerManager.getContainerMetaDataEntry(Cura.MachineManager.activeStack.material.id, "compatible", "") != "True" : true + property bool valueWarning: !Cura.MachineManager.isActiveQualitySupported + + text: Cura.MachineManager.activeStack != null ? Cura.MachineManager.activeStack.material.name : "" + tooltip: text + + height: UM.Theme.getSize("print_setup_big_item").height + width: selectors.controlWidth + + style: UM.Theme.styles.print_setup_header_button + activeFocusOnPress: true + menu: Cura.MaterialMenu + { + extruderIndex: Cura.ExtruderManager.activeExtruderIndex + } + } + } + + Row + { + height: UM.Theme.getSize("print_setup_big_item").height + visible: Cura.MachineManager.hasVariants + + Label + { + text: Cura.MachineManager.activeDefinitionVariantsName + verticalAlignment: Text.AlignVCenter + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + height: parent.height + width: selectors.textWidth + renderType: Text.NativeRendering + } + + OldControls.ToolButton + { + id: variantSelection + text: Cura.MachineManager.activeVariantName + tooltip: Cura.MachineManager.activeVariantName + + height: UM.Theme.getSize("print_setup_big_item").height + width: selectors.controlWidth + style: UM.Theme.styles.print_setup_header_button + activeFocusOnPress: true; + + menu: Cura.NozzleMenu { extruderIndex: Cura.ExtruderManager.activeExtruderIndex } + } + } + } + } +} diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml index 97b5bee745..db6a97aa65 100644 --- a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -5,87 +5,50 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 import UM 1.2 as UM +import Cura 1.0 as Cura - -Column +Row { id: extruderInfo property var printCoreConfiguration - property var mainColor: "black" - spacing: Math.round(UM.Theme.getSize("default_margin").height / 2) - height: childrenRect.height + height: information.height + spacing: UM.Theme.getSize("default_margin").width - Item + //Extruder icon. + Cura.ExtruderIcon { - id: extruder - width: parent.width - height: childrenRect.height + materialColor: printCoreConfiguration.material.color + anchors.verticalCenter: parent.verticalCenter + extruderEnabled: printCoreConfiguration.material.brand !== "" && printCoreConfiguration.hotendID !== "" + } + Column + { + id: information Label { - id: extruderLabel - text: catalog.i18nc("@label:extruder label", "Extruder") + text: printCoreConfiguration.material.brand ? printCoreConfiguration.material.brand : " " //Use space so that the height is still correct. renderType: Text.NativeRendering elide: Text.ElideRight - anchors.left: parent.left font: UM.Theme.getFont("default") - color: mainColor + color: UM.Theme.getColor("text_inactive") } - - // Rounded item to show the extruder number - Item + Label { - id: extruderIconItem - anchors.verticalCenter: extruderLabel.verticalCenter - anchors.left: extruderLabel.right - anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").width / 2) - - width: UM.Theme.getSize("section_icon").width - height: UM.Theme.getSize("section_icon").height - - UM.RecolorImage { - id: mainCircle - anchors.fill: parent - - anchors.centerIn: parent - sourceSize.width: parent.width - sourceSize.height: parent.height - source: UM.Theme.getIcon("extruder_button") - color: mainColor - } - - Label - { - id: extruderNumberText - anchors.centerIn: parent - text: printCoreConfiguration.position + 1 - renderType: Text.NativeRendering - font: UM.Theme.getFont("default") - color: mainColor - } + text: printCoreConfiguration.material.brand ? printCoreConfiguration.material.name : " " //Use space so that the height is still correct. + renderType: Text.NativeRendering + elide: Text.ElideRight + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text") + } + Label + { + text: printCoreConfiguration.hotendID ? printCoreConfiguration.hotendID : " " //Use space so that the height is still correct. + renderType: Text.NativeRendering + elide: Text.ElideRight + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text_inactive") } - } - - Label - { - id: materialLabel - text: printCoreConfiguration.material.name - renderType: Text.NativeRendering - elide: Text.ElideRight - width: parent.width - font: UM.Theme.getFont("default_bold") - color: mainColor - } - - Label - { - id: printCoreTypeLabel - text: printCoreConfiguration.hotendID - renderType: Text.NativeRendering - elide: Text.ElideRight - width: parent.width - font: UM.Theme.getFont("default") - color: mainColor } } diff --git a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml b/resources/qml/Menus/ConfigurationMenu/SyncButton.qml deleted file mode 100644 index 3099d684c1..0000000000 --- a/resources/qml/Menus/ConfigurationMenu/SyncButton.qml +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -Button -{ - id: base - property var outputDevice: null - property var matched: updateOnSync() - text: matched == true ? catalog.i18nc("@label:extruder label", "Yes") : catalog.i18nc("@label:extruder label", "No") - width: parent.width - height: parent.height - - function updateOnSync() - { - if (outputDevice != undefined) - { - for (var index in outputDevice.uniqueConfigurations) - { - var configuration = outputDevice.uniqueConfigurations[index] - if (Cura.MachineManager.matchesConfiguration(configuration)) - { - base.matched = true; - return; - } - } - } - base.matched = false; - } - - style: ButtonStyle - { - background: Rectangle - { - color: - { - if(control.pressed) - { - return UM.Theme.getColor("sidebar_header_active"); - } - else if(control.hovered) - { - return UM.Theme.getColor("sidebar_header_hover"); - } - else - { - return UM.Theme.getColor("sidebar_header_bar"); - } - } - Behavior on color { ColorAnimation { duration: 50; } } - - UM.RecolorImage - { - id: downArrow - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("default_margin").width - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: height - color: UM.Theme.getColor("text_emphasis") - source: UM.Theme.getIcon("arrow_bottom") - } - UM.RecolorImage - { - id: sidebarComboBoxLabel - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.verticalCenter: parent.verticalCenter; - - width: UM.Theme.getSize("printer_sync_icon").width - height: UM.Theme.getSize("printer_sync_icon").height - - color: control.matched ? UM.Theme.getColor("printer_config_matched") : UM.Theme.getColor("printer_config_mismatch") - source: UM.Theme.getIcon("tab_status_connected") - sourceSize.width: width - sourceSize.height: height - } - } - label: Label {} - } - - Connections - { - target: outputDevice - onUniqueConfigurationsChanged: updateOnSync() - } - - Connections - { - target: Cura.MachineManager - onCurrentConfigurationChanged: updateOnSync() - onOutputDevicesChanged: updateOnSync() - } -} \ No newline at end of file diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index 1ea402d815..cb10d50ce8 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -27,7 +27,7 @@ Menu MenuItem { id: extruderHeader; text: catalog.i18ncp("@label", "Print Selected Model With:", "Print Selected Models With:", UM.Selection.selectionCount); enabled: false; visible: base.shouldShowExtruders } Instantiator { - model: Cura.ExtrudersModel { id: extrudersModel } + model: CuraApplication.getExtrudersModel() MenuItem { text: "%1: %2 - %3".arg(model.name).arg(model.material).arg(model.variant) visible: base.shouldShowExtruders diff --git a/resources/qml/Menus/FileMenu.qml b/resources/qml/Menus/FileMenu.qml new file mode 100644 index 0000000000..955ac89693 --- /dev/null +++ b/resources/qml/Menus/FileMenu.qml @@ -0,0 +1,81 @@ +// 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 UM 1.2 as UM +import Cura 1.0 as Cura + +Menu +{ + id: base + title: catalog.i18nc("@title:menu menubar:toplevel", "&File") + + MenuItem + { + id: newProjectMenu + action: Cura.Actions.newProject + } + + MenuItem + { + id: openMenu + action: Cura.Actions.open + } + + RecentFilesMenu { } + + MenuItem + { + id: saveWorkspaceMenu + text: catalog.i18nc("@title:menu menubar:file", "&Save...") + onTriggered: + { + var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml" }; + if(UM.Preferences.getValue("cura/dialog_on_project_save")) + { + saveWorkspaceDialog.args = args + saveWorkspaceDialog.open() + } + else + { + UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, args) + } + } + } + + MenuSeparator { } + + MenuItem + { + id: saveAsMenu + text: catalog.i18nc("@title:menu menubar:file", "&Export...") + onTriggered: + { + var localDeviceId = "local_file" + UM.OutputDeviceManager.requestWriteToDevice(localDeviceId, PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"}) + } + } + + MenuItem + { + id: exportSelectionMenu + text: catalog.i18nc("@action:inmenu menubar:file", "Export Selection...") + enabled: UM.Selection.hasSelection + iconName: "document-save-as" + onTriggered: UM.OutputDeviceManager.requestWriteSelectionToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"}) + } + + MenuSeparator { } + + MenuItem + { + id: reloadAllMenu + action: Cura.Actions.reloadAll + } + + MenuSeparator { } + + MenuItem { action: Cura.Actions.quit } +} \ No newline at end of file diff --git a/resources/qml/Menus/LocalPrinterMenu.qml b/resources/qml/Menus/LocalPrinterMenu.qml index 0bdd4f33b9..4da1de2abf 100644 --- a/resources/qml/Menus/LocalPrinterMenu.qml +++ b/resources/qml/Menus/LocalPrinterMenu.qml @@ -7,16 +7,18 @@ import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura -Instantiator { - model: UM.ContainerStacksModel { - filter: {"type": "machine", "um_network_key": null} - } - MenuItem { - text: model.name; - checkable: true; +Instantiator +{ + model: Cura.GlobalStacksModel {} + + MenuItem + { + text: model.name + checkable: true checked: Cura.MachineManager.activeMachineId == model.id - exclusiveGroup: group; - onTriggered: Cura.MachineManager.setActiveMachine(model.id); + exclusiveGroup: group + visible: !model.hasRemoteConnection + onTriggered: Cura.MachineManager.setActiveMachine(model.id) } onObjectAdded: menu.insertItem(index, object) onObjectRemoved: menu.removeItem(object) diff --git a/resources/qml/Menus/NetworkPrinterMenu.qml b/resources/qml/Menus/NetworkPrinterMenu.qml index 07a22202e4..41f3054e92 100644 --- a/resources/qml/Menus/NetworkPrinterMenu.qml +++ b/resources/qml/Menus/NetworkPrinterMenu.qml @@ -7,18 +7,25 @@ import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura -Instantiator { - model: UM.ContainerStacksModel { - filter: {"type": "machine", "um_network_key": "*", "hidden": "False"} - } - MenuItem { - // TODO: Use printer_group icon when it's a cluster. Not use it for now since it doesn't look as expected -// iconSource: UM.Theme.getIcon("printer_single") - text: model.metadata["connect_group_name"] - checkable: true; - checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"] - exclusiveGroup: group; - onTriggered: Cura.MachineManager.setActiveMachine(model.id); +Instantiator +{ + model: Cura.GlobalStacksModel {} + MenuItem + { + property string connectGroupName: + { + if("connect_group_name" in model.metadata) + { + return model.metadata["connect_group_name"] + } + return "" + } + text: connectGroupName + checkable: true + visible: model.hasRemoteConnection + checked: Cura.MachineManager.activeMachineNetworkGroupName == connectGroupName + exclusiveGroup: group + onTriggered: Cura.MachineManager.setActiveMachine(model.id) } onObjectAdded: menu.insertItem(index, object) onObjectRemoved: menu.removeItem(object) diff --git a/resources/qml/Menus/PrinterStatusIcon.qml b/resources/qml/Menus/PrinterStatusIcon.qml deleted file mode 100644 index 6ff6b07af8..0000000000 --- a/resources/qml/Menus/PrinterStatusIcon.qml +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2017 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.2 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -Item -{ - property var status: "disconnected" - width: childrenRect.width - height: childrenRect.height - UM.RecolorImage - { - id: statusIcon - width: UM.Theme.getSize("printer_status_icon").width - height: UM.Theme.getSize("printer_status_icon").height - sourceSize.width: width - sourceSize.height: width - color: UM.Theme.getColor("tab_status_" + parent.status) - source: UM.Theme.getIcon(parent.status) - } -} - - - diff --git a/resources/qml/Menus/ProfileMenu.qml b/resources/qml/Menus/ProfileMenu.qml index ffd3c556b6..68260f2502 100644 --- a/resources/qml/Menus/ProfileMenu.qml +++ b/resources/qml/Menus/ProfileMenu.qml @@ -17,24 +17,27 @@ Menu MenuItem { - text: (model.layer_height != "") ? model.name + " - " + model.layer_height + model.layer_height_unit : model.name + text: + { + var full_text = (model.layer_height != "") ? model.name + " - " + model.layer_height + model.layer_height_unit : model.name + full_text += model.is_experimental ? " - " + catalog.i18nc("@label", "Experimental") : "" + return full_text + } checkable: true checked: Cura.MachineManager.activeQualityOrQualityChangesName == model.name exclusiveGroup: group - onTriggered: { - Cura.MachineManager.setQualityGroup(model.quality_group) - } + onTriggered: Cura.MachineManager.setQualityGroup(model.quality_group) visible: model.available } - onObjectAdded: menu.insertItem(index, object); - onObjectRemoved: menu.removeItem(object); + onObjectAdded: menu.insertItem(index, object) + onObjectRemoved: menu.removeItem(object) } MenuSeparator { id: customSeparator - visible: Cura.CustomQualityProfilesDropDownMenuModel.rowCount > 0 + visible: Cura.CustomQualityProfilesDropDownMenuModel.count > 0 } Instantiator @@ -45,7 +48,7 @@ Menu Connections { target: Cura.CustomQualityProfilesDropDownMenuModel - onModelReset: customSeparator.visible = Cura.CustomQualityProfilesDropDownMenuModel.rowCount() > 0 + onModelReset: customSeparator.visible = Cura.CustomQualityProfilesDropDownMenuModel.count > 0 } MenuItem @@ -59,12 +62,12 @@ Menu onObjectAdded: { - customSeparator.visible = model.rowCount() > 0; + customSeparator.visible = model.count > 0; menu.insertItem(index, object); } onObjectRemoved: { - customSeparator.visible = model.rowCount() > 0; + customSeparator.visible = model.count > 0; menu.removeItem(object); } } diff --git a/resources/qml/Menus/RecentFilesMenu.qml b/resources/qml/Menus/RecentFilesMenu.qml index 12f53fb517..0f1f67b6fa 100644 --- a/resources/qml/Menus/RecentFilesMenu.qml +++ b/resources/qml/Menus/RecentFilesMenu.qml @@ -7,6 +7,8 @@ import QtQuick.Controls 1.1 import UM 1.3 as UM import Cura 1.0 as Cura +import "../Dialogs" + Menu { id: menu diff --git a/resources/qml/Menus/SettingsMenu.qml b/resources/qml/Menus/SettingsMenu.qml new file mode 100644 index 0000000000..4ea3a4d71a --- /dev/null +++ b/resources/qml/Menus/SettingsMenu.qml @@ -0,0 +1,70 @@ +// 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 UM 1.2 as UM +import Cura 1.0 as Cura + +Menu +{ + id: base + title: catalog.i18nc("@title:menu menubar:toplevel", "&Settings") + + PrinterMenu { title: catalog.i18nc("@title:menu menubar:settings", "&Printer") } + + Instantiator + { + model: Cura.MachineManager.activeMachine.extruderList + + Menu + { + title: modelData.name + + NozzleMenu { title: Cura.MachineManager.activeDefinitionVariantsName; visible: Cura.MachineManager.hasVariants; extruderIndex: index } + MaterialMenu { title: catalog.i18nc("@title:menu", "&Material"); visible: Cura.MachineManager.hasMaterials; extruderIndex: index } + + MenuSeparator + { + visible: Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials + } + + MenuItem + { + text: catalog.i18nc("@action:inmenu", "Set as Active Extruder") + onTriggered: Cura.MachineManager.setExtruderIndex(model.index) + } + + MenuItem + { + text: catalog.i18nc("@action:inmenu", "Enable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) + visible: !Cura.MachineManager.getExtruder(model.index).isEnabled + } + + MenuItem + { + text: catalog.i18nc("@action:inmenu", "Disable Extruder") + onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) + visible: Cura.MachineManager.getExtruder(model.index).isEnabled + enabled: Cura.MachineManager.numberExtrudersEnabled > 1 + } + + } + onObjectAdded: base.insertItem(index, object) + onObjectRemoved: base.removeItem(object) + } + + // TODO Only show in dev mode. Remove check when feature ready + BuildplateMenu + { + title: catalog.i18nc("@title:menu", "&Build plate") + visible: CuraSDKVersion == "dev" && Cura.MachineManager.hasVariantBuildplates + } + ProfileMenu { title: catalog.i18nc("@title:settings", "&Profile") } + + MenuSeparator { } + + MenuItem { action: Cura.Actions.configureSettingVisibility } +} \ No newline at end of file diff --git a/resources/qml/Menus/ViewMenu.qml b/resources/qml/Menus/ViewMenu.qml index 12d4ffd7dd..217975c803 100644 --- a/resources/qml/Menus/ViewMenu.qml +++ b/resources/qml/Menus/ViewMenu.qml @@ -11,32 +11,10 @@ Menu { title: catalog.i18nc("@title:menu menubar:toplevel", "&View") id: base + enabled: !PrintInformation.preSliced property var multiBuildPlateModel: CuraApplication.getMultiBuildPlateModel() - // main views - Instantiator - { - model: UM.ViewModel{} - MenuItem - { - text: model.name - checkable: true - checked: model.active - exclusiveGroup: group - onTriggered: UM.Controller.setActiveView(model.id) - enabled: !PrintInformation.preSliced - } - onObjectAdded: base.insertItem(index, object) - onObjectRemoved: base.removeItem(object) - } - ExclusiveGroup - { - id: group - } - - MenuSeparator {} - Menu { title: catalog.i18nc("@action:inmenu menubar:view","&Camera position"); @@ -80,12 +58,6 @@ Menu MenuSeparator {} - MenuItem - { - action: Cura.Actions.expandSidebar - } - - MenuSeparator {} MenuItem { action: Cura.Actions.toggleFullScreen diff --git a/resources/qml/MonitorButton.qml b/resources/qml/MonitorButton.qml index aa40de11e4..99640b1059 100644 --- a/resources/qml/MonitorButton.qml +++ b/resources/qml/MonitorButton.qml @@ -13,9 +13,9 @@ import Cura 1.0 as Cura Item { id: base; - UM.I18nCatalog { id: catalog; name:"cura"} + UM.I18nCatalog { id: catalog; name: "cura"} - height: childrenRect.height + UM.Theme.getSize("sidebar_margin").height + height: childrenRect.height + UM.Theme.getSize("thick_margin").height property bool printerConnected: Cura.MachineManager.printerConnected property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands @@ -162,13 +162,13 @@ Item Label { id: statusLabel - width: parent.width - 2 * UM.Theme.getSize("sidebar_margin").width + width: parent.width - 2 * UM.Theme.getSize("thick_margin").width anchors.top: parent.top anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width + anchors.leftMargin: UM.Theme.getSize("thick_margin").width color: base.statusColor - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") text: statusText } @@ -179,7 +179,7 @@ Item anchors.right: progressBar.right color: base.statusColor - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") text: Math.round(progress) + "%" visible: showProgress } @@ -224,12 +224,12 @@ Item property string backgroundColor: UM.Theme.getColor("progressbar_background"); property string controlColor: base.statusColor; - width: parent.width - 2 * UM.Theme.getSize("sidebar_margin").width; + width: parent.width - 2 * UM.Theme.getSize("thick_margin").width; height: UM.Theme.getSize("progressbar").height; anchors.top: statusLabel.bottom; - anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height / 4); + anchors.topMargin: Math.round(UM.Theme.getSize("thick_margin").height / 4); anchors.left: parent.left; - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width; + anchors.leftMargin: UM.Theme.getSize("thick_margin").width; } Row @@ -237,9 +237,9 @@ Item id: buttonsRow height: abortButton.height anchors.top: progressBar.bottom - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height + anchors.topMargin: UM.Theme.getSize("thick_margin").height anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width + anchors.rightMargin: UM.Theme.getSize("thick_margin").width spacing: UM.Theme.getSize("default_margin").width Row @@ -309,7 +309,7 @@ Item } } - style: UM.Theme.styles.sidebar_action_button + style: UM.Theme.styles.print_setup_action_button } Button @@ -325,7 +325,7 @@ Item text: catalog.i18nc("@label", "Abort Print") onClicked: confirmationDialog.visible = true - style: UM.Theme.styles.sidebar_action_button + style: UM.Theme.styles.print_setup_action_button } MessageDialog diff --git a/resources/qml/MonitorSidebar.qml b/resources/qml/MonitorSidebar.qml deleted file mode 100644 index 80bd5c1a2e..0000000000 --- a/resources/qml/MonitorSidebar.qml +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) 2017 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 - -import UM 1.2 as UM -import Cura 1.0 as Cura -import "Menus" -import "Menus/ConfigurationMenu" - -Rectangle -{ - id: base - - property int currentModeIndex - property bool hideSettings: PrintInformation.preSliced - property bool hideView: Cura.MachineManager.activeMachineName == "" - - // Is there an output device for this printer? - property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" - property bool printerConnected: Cura.MachineManager.printerConnected - property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands - property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null - - property variant printDuration: PrintInformation.currentPrintTime - property variant printMaterialLengths: PrintInformation.materialLengths - property variant printMaterialWeights: PrintInformation.materialWeights - property variant printMaterialCosts: PrintInformation.materialCosts - property variant printMaterialNames: PrintInformation.materialNames - - color: UM.Theme.getColor("sidebar") - UM.I18nCatalog { id: catalog; name:"cura"} - - Timer { - id: tooltipDelayTimer - interval: 500 - repeat: false - property var item - property string text - - onTriggered: - { - base.showTooltip(base, {x: 0, y: item.y}, text); - } - } - - function showTooltip(item, position, text) - { - tooltip.text = text; - position = item.mapToItem(base, position.x - UM.Theme.getSize("default_arrow").width, position.y); - tooltip.show(position); - } - - function hideTooltip() - { - tooltip.hide(); - } - - function strPadLeft(string, pad, length) { - return (new Array(length + 1).join(pad) + string).slice(-length); - } - - function getPrettyTime(time) - { - var hours = Math.floor(time / 3600) - time -= hours * 3600 - var minutes = Math.floor(time / 60); - time -= minutes * 60 - var seconds = Math.floor(time); - - var finalTime = strPadLeft(hours, "0", 2) + ':' + strPadLeft(minutes,'0',2)+ ':' + strPadLeft(seconds,'0',2); - return finalTime; - } - - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.AllButtons - - onWheel: - { - wheel.accepted = true; - } - } - - MachineSelection - { - id: machineSelection - width: base.width - configSelection.width - separator.width - height: UM.Theme.getSize("sidebar_header").height - anchors.top: base.top - anchors.left: parent.left - } - - Rectangle - { - id: separator - visible: configSelection.visible - width: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0 - height: UM.Theme.getSize("sidebar_header").height - color: UM.Theme.getColor("sidebar_lining_thin") - anchors.left: machineSelection.right - } - - ConfigurationSelection - { - id: configSelection - visible: isNetworkPrinter && printerConnected - width: visible ? Math.round(base.width * 0.15) : 0 - height: UM.Theme.getSize("sidebar_header").height - anchors.top: base.top - anchors.right: parent.right - panelWidth: base.width - } - - Loader - { - id: controlItem - anchors.bottom: footerSeparator.top - anchors.top: machineSelection.bottom - anchors.left: base.left - anchors.right: base.right - sourceComponent: - { - if(connectedPrinter != null) - { - if(connectedPrinter.controlItem != null) - { - return connectedPrinter.controlItem - } - } - return null - } - } - - Loader - { - anchors.bottom: footerSeparator.top - anchors.top: machineSelection.bottom - anchors.left: base.left - anchors.right: base.right - source: - { - if(controlItem.sourceComponent == null) - { - return "PrintMonitor.qml" - } - else - { - return "" - } - } - } - - Rectangle - { - id: footerSeparator - width: parent.width - height: UM.Theme.getSize("sidebar_lining").height - color: UM.Theme.getColor("sidebar_lining") - anchors.bottom: monitorButton.top - anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height - } - - // MonitorButton is actually the bottom footer panel. - MonitorButton - { - id: monitorButton - implicitWidth: base.width - anchors.bottom: parent.bottom - } - - SidebarTooltip - { - id: tooltip - } - - UM.SettingPropertyProvider - { - id: machineExtruderCount - - containerStack: Cura.MachineManager.activeMachine - key: "machine_extruder_count" - watchedProperties: [ "value" ] - storeIndex: 0 - } - - UM.SettingPropertyProvider - { - id: machineHeatedBed - - containerStack: Cura.MachineManager.activeMachine - key: "machine_heated_bed" - watchedProperties: [ "value" ] - storeIndex: 0 - } - - // Make the ConfigurationSelector react when the global container changes, otherwise if Cura is not connected to the printer, - // switching printers make no reaction - Connections - { - target: Cura.MachineManager - onGlobalContainerChanged: - { - base.isNetworkPrinter = Cura.MachineManager.activeMachineNetworkKey != "" - base.printerConnected = Cura.MachineManager.printerOutputDevices.length != 0 - } - } -} diff --git a/resources/qml/ObjectsList.qml b/resources/qml/ObjectsList.qml index 8c8eaa16ae..fd5175fce2 100644 --- a/resources/qml/ObjectsList.qml +++ b/resources/qml/ObjectsList.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 @@ -55,7 +55,6 @@ Rectangle { width: control.width height: control.height - sourceSize.width: width sourceSize.height: width color: UM.Theme.getColor("setting_control_text") source: collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom") @@ -225,7 +224,7 @@ Rectangle { id: arrangeAllBuildPlatesButton; text: catalog.i18nc("@action:button","Arrange to all build plates"); - style: UM.Theme.styles.sidebar_action_button + style: UM.Theme.styles.print_setup_action_button height: UM.Theme.getSize("objects_menu_button").height; tooltip: ''; anchors @@ -245,7 +244,7 @@ Rectangle { id: arrangeBuildPlateButton; text: catalog.i18nc("@action:button","Arrange current build plate"); - style: UM.Theme.styles.sidebar_action_button + style: UM.Theme.styles.print_setup_action_button height: UM.Theme.getSize("objects_menu_button").height; tooltip: ''; anchors diff --git a/resources/qml/Preferences/GeneralPage.qml b/resources/qml/Preferences/GeneralPage.qml index bba2cf764a..5ff5f567ea 100644 --- a/resources/qml/Preferences/GeneralPage.qml +++ b/resources/qml/Preferences/GeneralPage.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.1 @@ -134,7 +134,7 @@ UM.PreferencesPage UM.PluginsModel { id: plugins } //: Language selection label - UM.I18nCatalog{id: catalog; name:"cura"} + UM.I18nCatalog{id: catalog; name: "cura"} Label { @@ -151,7 +151,6 @@ UM.PreferencesPage { id: languageLabel text: catalog.i18nc("@label","Language:") - anchors.verticalCenter: languageComboBox.verticalCenter } ComboBox @@ -219,7 +218,6 @@ UM.PreferencesPage { id: currencyLabel text: catalog.i18nc("@label","Currency:") - anchors.verticalCenter: currencyField.verticalCenter } TextField @@ -233,7 +231,6 @@ UM.PreferencesPage { id: themeLabel text: catalog.i18nc("@label","Theme:") - anchors.verticalCenter: themeComboBox.verticalCenter } ComboBox diff --git a/resources/qml/Preferences/MachinesPage.qml b/resources/qml/Preferences/MachinesPage.qml index 4dc5465dc6..f9c1a9b0a0 100644 --- a/resources/qml/Preferences/MachinesPage.qml +++ b/resources/qml/Preferences/MachinesPage.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 @@ -21,8 +21,10 @@ UM.ManagementPage function activeMachineIndex() { - for(var i = 0; i < model.rowCount(); i++) { - if (model.getItem(i).id == Cura.MachineManager.activeMachineId) { + for(var i = 0; i < model.count; i++) + { + if (model.getItem(i).id == Cura.MachineManager.activeMachineId) + { return i; } } @@ -47,7 +49,7 @@ UM.ManagementPage { text: catalog.i18nc("@action:button", "Remove"); iconName: "list-remove"; - enabled: base.currentItem != null && model.rowCount() > 1 + enabled: base.currentItem != null && model.count > 1 onClicked: confirmDialog.open(); }, Button @@ -68,7 +70,7 @@ UM.ManagementPage { id: machineName text: base.currentItem && base.currentItem.name ? base.currentItem.name : "" - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") width: parent.width elide: Text.ElideRight } @@ -89,7 +91,7 @@ UM.ManagementPage Item { - width: childrenRect.width + 2 * screenScaleFactor + width: Math.round(childrenRect.width + 2 * screenScaleFactor) height: childrenRect.height Button { @@ -124,132 +126,15 @@ UM.ManagementPage } } - Grid - { - id: machineInfo - - anchors.top: machineActions.visible ? machineActions.bottom : machineActions.anchors.top - anchors.topMargin: UM.Theme.getSize("default_margin").height - anchors.left: parent.left - anchors.right: parent.right - spacing: UM.Theme.getSize("default_margin").height - rowSpacing: UM.Theme.getSize("default_lining").height - columns: 2 - - visible: base.currentItem - - property bool printerConnected: Cura.MachineManager.printerConnected - property var connectedPrinter: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null - property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands - property var printJob: connectedPrinter != null ? connectedPrinter.activePrintJob: null - Label - { - text: catalog.i18nc("@label", "Printer type:") - visible: base.currentItem && "definition_name" in base.currentItem.metadata - } - Label - { - text: (base.currentItem && "definition_name" in base.currentItem.metadata) ? base.currentItem.metadata.definition_name : "" - } - Label - { - text: catalog.i18nc("@label", "Connection:") - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId - } - Label - { - width: (parent.width * 0.7) | 0 - text: machineInfo.printerConnected ? machineInfo.connectedPrinter.connectionText : catalog.i18nc("@info:status", "The printer is not connected.") - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId - wrapMode: Text.WordWrap - } - Label - { - text: catalog.i18nc("@label", "State:") - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId && machineInfo.printerAcceptsCommands - } - Label { - width: (parent.width * 0.7) | 0 - text: - { - if(!machineInfo.printerConnected || !machineInfo.printerAcceptsCommands) { - return ""; - } - - if (machineInfo.printJob == null) - { - return catalog.i18nc("@label:MonitorStatus", "Waiting for a printjob"); - } - - switch(machineInfo.printJob.state) - { - case "printing": - return catalog.i18nc("@label:MonitorStatus", "Printing..."); - case "paused": - return catalog.i18nc("@label:MonitorStatus", "Paused"); - case "pre_print": - return catalog.i18nc("@label:MonitorStatus", "Preparing..."); - case "wait_cleanup": - return catalog.i18nc("@label:MonitorStatus", "Waiting for someone to clear the build plate"); - case "error": - return printerOutputDevice.errorText; - case "maintenance": - return catalog.i18nc("@label:MonitorStatus", "In maintenance. Please check the printer"); - case "abort": // note sure if this jobState actually occurs in the wild - return catalog.i18nc("@label:MonitorStatus", "Aborting print..."); - - } - return "" - } - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId && machineInfo.printerAcceptsCommands - wrapMode: Text.WordWrap - } - } - - Column { - id: additionalComponentsColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: machineInfo.visible ? machineInfo.bottom : machineInfo.anchors.top - anchors.topMargin: UM.Theme.getSize("default_margin").width - - spacing: UM.Theme.getSize("default_margin").width - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId - - Component.onCompleted: - { - for (var component in CuraApplication.additionalComponents["machinesDetailPane"]) { - CuraApplication.additionalComponents["machinesDetailPane"][component].parent = additionalComponentsColumn - } - } - } - - Component.onCompleted: { - addAdditionalComponents("machinesDetailPane") - } - - Connections { - target: CuraApplication - onAdditionalComponentsChanged: addAdditionalComponents - } - - function addAdditionalComponents (areaId) { - if(areaId == "machinesDetailPane") { - for (var component in CuraApplication.additionalComponents["machinesDetailPane"]) { - CuraApplication.additionalComponents["machinesDetailPane"][component].parent = additionalComponentsColumn - } - } - } - UM.I18nCatalog { id: catalog; name: "cura"; } UM.ConfirmRemoveDialog { - id: confirmDialog; - object: base.currentItem && base.currentItem.name ? base.currentItem.name : ""; + id: confirmDialog + object: base.currentItem && base.currentItem.name ? base.currentItem.name : "" onYes: { - Cura.MachineManager.removeMachine(base.currentItem.id); + Cura.MachineManager.removeMachine(base.currentItem.id) if(!base.currentItem) { objectList.currentIndex = activeMachineIndex() diff --git a/resources/qml/Preferences/Materials/MaterialsBrandSection.qml b/resources/qml/Preferences/Materials/MaterialsBrandSection.qml index c8f391dfb0..c976233805 100644 --- a/resources/qml/Preferences/Materials/MaterialsBrandSection.qml +++ b/resources/qml/Preferences/Materials/MaterialsBrandSection.qml @@ -1,5 +1,5 @@ // Copyright (c) 2018 Ultimaker B.V. -// Uranium is released under the terms of the LGPLv3 or higher. +// Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 import QtQuick.Controls 1.4 @@ -10,7 +10,7 @@ import QtQuick.Dialogs 1.2 import UM 1.2 as UM import Cura 1.0 as Cura -Rectangle +Item { id: brand_section @@ -55,7 +55,8 @@ Rectangle text: "" implicitWidth: UM.Theme.getSize("favorites_button").width implicitHeight: UM.Theme.getSize("favorites_button").height - UM.RecolorImage { + UM.RecolorImage + { anchors { verticalCenter: parent.verticalCenter @@ -63,18 +64,12 @@ Rectangle } width: UM.Theme.getSize("standard_arrow").width height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: height color: "black" source: brand_section.expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left") } style: ButtonStyle { - background: Rectangle - { - anchors.fill: parent - color: "transparent" - } + background: Item { } } } } diff --git a/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml b/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml index 92970f40e2..eb4a63250f 100644 --- a/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml +++ b/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml @@ -65,7 +65,7 @@ Item Label { text: materialProperties.name - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") } } diff --git a/resources/qml/Preferences/Materials/MaterialsList.qml b/resources/qml/Preferences/Materials/MaterialsList.qml index 00bead9650..61f92db84c 100644 --- a/resources/qml/Preferences/Materials/MaterialsList.qml +++ b/resources/qml/Preferences/Materials/MaterialsList.qml @@ -57,7 +57,7 @@ Item var currentItemId = base.currentItem == null ? "" : base.currentItem.root_material_id search_root_id = currentItemId } - for (var material_idx = 0; material_idx < genericMaterialsModel.rowCount(); material_idx++) + for (var material_idx = 0; material_idx < genericMaterialsModel.count; material_idx++) { var material = genericMaterialsModel.getItem(material_idx) if (material.root_material_id == search_root_id) @@ -72,15 +72,15 @@ Item return true } } - for (var brand_idx = 0; brand_idx < materialsModel.rowCount(); brand_idx++) + for (var brand_idx = 0; brand_idx < materialsModel.count; brand_idx++) { var brand = materialsModel.getItem(brand_idx) var types_model = brand.material_types - for (var type_idx = 0; type_idx < types_model.rowCount(); type_idx++) + for (var type_idx = 0; type_idx < types_model.count; type_idx++) { var type = types_model.getItem(type_idx) var colors_model = type.colors - for (var material_idx = 0; material_idx < colors_model.rowCount(); material_idx++) + for (var material_idx = 0; material_idx < colors_model.count; material_idx++) { var material = colors_model.getItem(material_idx) if (material.root_material_id == search_root_id) diff --git a/resources/qml/Preferences/Materials/MaterialsSlot.qml b/resources/qml/Preferences/Materials/MaterialsSlot.qml index a5af17f47a..2f4847103b 100644 --- a/resources/qml/Preferences/Materials/MaterialsSlot.qml +++ b/resources/qml/Preferences/Materials/MaterialsSlot.qml @@ -1,5 +1,5 @@ // Copyright (c) 2018 Ultimaker B.V. -// Uranium is released under the terms of the LGPLv3 or higher. +// Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 import QtQuick.Controls 1.4 @@ -15,7 +15,7 @@ Rectangle id: materialSlot property var material: null property var hovered: false - property var is_favorite: material != null ? material.is_favorite : false + property var is_favorite: material != null && material.is_favorite height: UM.Theme.getSize("favorites_row").height width: parent.width @@ -70,24 +70,20 @@ Rectangle } onClicked: { - if (materialSlot.is_favorite) { + if (materialSlot.is_favorite) + { base.materialManager.removeFavorite(material.root_material_id) - materialSlot.is_favorite = false return } base.materialManager.addFavorite(material.root_material_id) - materialSlot.is_favorite = true return } style: ButtonStyle { - background: Rectangle - { - anchors.fill: parent - color: "transparent" - } + background: Item { } } - UM.RecolorImage { + UM.RecolorImage + { anchors { verticalCenter: favorite_button.verticalCenter @@ -95,8 +91,6 @@ Rectangle } width: UM.Theme.getSize("favorites_button_icon").width height: UM.Theme.getSize("favorites_button_icon").height - sourceSize.width: width - sourceSize.height: height color: { if (favorite_button.hovered) diff --git a/resources/qml/Preferences/Materials/MaterialsTypeSection.qml b/resources/qml/Preferences/Materials/MaterialsTypeSection.qml index f62fc4ee16..8f34217cce 100644 --- a/resources/qml/Preferences/Materials/MaterialsTypeSection.qml +++ b/resources/qml/Preferences/Materials/MaterialsTypeSection.qml @@ -10,7 +10,7 @@ import QtQuick.Dialogs 1.2 import UM 1.2 as UM import Cura 1.0 as Cura -Rectangle +Item { id: material_type_section property var materialType @@ -74,8 +74,6 @@ Rectangle } width: UM.Theme.getSize("standard_arrow").width height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: height color: "black" source: material_type_section.expanded ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left") } diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index ba0c2848a5..f23a04d800 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -16,7 +16,7 @@ Item property QtObject qualityManager: CuraApplication.getQualityManager() property var resetEnabled: false // Keep PreferencesDialog happy - property var extrudersModel: Cura.ExtrudersModel {} + property var extrudersModel: CuraApplication.getExtrudersModel() UM.I18nCatalog { id: catalog; name: "cura"; } @@ -188,21 +188,27 @@ Item Connections { target: qualitiesModel - onItemsChanged: { + onItemsChanged: + { var toSelectItemName = base.currentItem == null ? "" : base.currentItem.name; - if (newQualityNameToSelect != "") { + if (newQualityNameToSelect != "") + { toSelectItemName = newQualityNameToSelect; } var newIdx = -1; // Default to nothing if nothing can be found - if (toSelectItemName != "") { + if (toSelectItemName != "") + { // Select the required quality name if given - for (var idx = 0; idx < qualitiesModel.rowCount(); ++idx) { + for (var idx = 0; idx < qualitiesModel.count; ++idx) + { var item = qualitiesModel.getItem(idx); - if (item.name == toSelectItemName) { + if (item.name == toSelectItemName) + { // Switch to the newly created profile if needed newIdx = idx; - if (base.toActivateNewQuality) { + if (base.toActivateNewQuality) + { // Activate this custom quality if required Cura.MachineManager.setQualityChangesGroup(item.quality_changes_group); } @@ -370,6 +376,7 @@ Item width: true ? (parent.width * 0.4) | 0 : parent.width frameVisible: true + clip: true ListView { @@ -382,9 +389,11 @@ Item var selectedItemName = Cura.MachineManager.activeQualityOrQualityChangesName; // Select the required quality name if given - for (var idx = 0; idx < qualitiesModel.rowCount(); idx++) { + for (var idx = 0; idx < qualitiesModel.count; idx++) + { var item = qualitiesModel.getItem(idx); - if (item.name == selectedItemName) { + if (item.name == selectedItemName) + { currentIndex = idx; break; } @@ -400,7 +409,7 @@ Item { anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_lining").width - text: section == "true" ? catalog.i18nc("@label", "Protected profiles") : catalog.i18nc("@label", "Custom profiles") + text: section == "true" ? catalog.i18nc("@label", "Default profiles") : catalog.i18nc("@label", "Custom profiles") font.bold: true } } @@ -463,7 +472,7 @@ Item Label { text: base.currentItemName - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") } } diff --git a/resources/qml/Preferences/SettingVisibilityPage.qml b/resources/qml/Preferences/SettingVisibilityPage.qml index 8896d0611e..3f7571a170 100644 --- a/resources/qml/Preferences/SettingVisibilityPage.qml +++ b/resources/qml/Preferences/SettingVisibilityPage.qml @@ -25,11 +25,7 @@ UM.PreferencesPage function reset() { - UM.Preferences.resetPreference("general/visible_settings") - - // After calling this function update Setting visibility preset combobox. - // Reset should set default setting preset ("Basic") - visibilityPreset.currentIndex = 1 + settingVisibilityPresetsModel.setActivePreset("basic") } resetEnabled: true; @@ -54,7 +50,7 @@ UM.PreferencesPage { return Qt.Unchecked } - else if(definitionsModel.visibleCount == definitionsModel.rowCount(null)) + else if(definitionsModel.visibleCount == definitionsModel.count) { return Qt.Checked } @@ -115,21 +111,22 @@ UM.PreferencesPage currentIndex: { + var idx = -1; for(var i = 0; i < settingVisibilityPresetsModel.items.length; ++i) { - if(settingVisibilityPresetsModel.items[i].id == settingVisibilityPresetsModel.activePreset) + if(settingVisibilityPresetsModel.items[i].presetId == settingVisibilityPresetsModel.activePreset) { - currentIndex = i; - return; + idx = i; + break; } } - return -1 + return idx; } onActivated: { - var preset_id = settingVisibilityPresetsModel.items[index].id; - settingVisibilityPresetsModel.setActivePreset(preset_id); + var preset_id = settingVisibilityPresetsModel.items[index].presetId + settingVisibilityPresetsModel.setActivePreset(preset_id) } } diff --git a/resources/qml/PrepareSidebar.qml b/resources/qml/PrepareSidebar.qml deleted file mode 100644 index fe0fb033f7..0000000000 --- a/resources/qml/PrepareSidebar.qml +++ /dev/null @@ -1,616 +0,0 @@ -// Copyright (c) 2017 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.3 - -import UM 1.2 as UM -import Cura 1.0 as Cura -import "Menus" -import "Menus/ConfigurationMenu" - -Rectangle -{ - id: base - - property int currentModeIndex: -1 - property bool hideSettings: PrintInformation.preSliced - property bool hideView: Cura.MachineManager.activeMachineName == "" - - // Is there an output device for this printer? - property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != "" - property bool printerConnected: Cura.MachineManager.printerConnected - property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands - property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null - - property variant printDuration: PrintInformation.currentPrintTime - property variant printMaterialLengths: PrintInformation.materialLengths - property variant printMaterialWeights: PrintInformation.materialWeights - property variant printMaterialCosts: PrintInformation.materialCosts - property variant printMaterialNames: PrintInformation.materialNames - - color: UM.Theme.getColor("sidebar") - UM.I18nCatalog { id: catalog; name:"cura"} - - Timer { - id: tooltipDelayTimer - interval: 500 - repeat: false - property var item - property string text - - onTriggered: - { - base.showTooltip(base, {x: 0, y: item.y}, text); - } - } - - function showTooltip(item, position, text) - { - tooltip.text = text; - position = item.mapToItem(base, position.x - UM.Theme.getSize("default_arrow").width, position.y); - tooltip.show(position); - } - - function hideTooltip() - { - tooltip.hide(); - } - - function strPadLeft(string, pad, length) { - return (new Array(length + 1).join(pad) + string).slice(-length); - } - - function getPrettyTime(time) - { - var hours = Math.floor(time / 3600) - time -= hours * 3600 - var minutes = Math.floor(time / 60); - time -= minutes * 60 - var seconds = Math.floor(time); - - var finalTime = strPadLeft(hours, "0", 2) + ':' + strPadLeft(minutes,'0',2)+ ':' + strPadLeft(seconds,'0',2); - return finalTime; - } - - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.AllButtons - - onWheel: - { - wheel.accepted = true; - } - } - - MachineSelection - { - id: machineSelection - width: base.width - configSelection.width - separator.width - height: UM.Theme.getSize("sidebar_header").height - anchors.top: base.top - anchors.left: parent.left - } - - Rectangle - { - id: separator - visible: configSelection.visible - width: visible ? Math.round(UM.Theme.getSize("sidebar_lining_thin").height / 2) : 0 - height: UM.Theme.getSize("sidebar_header").height - color: UM.Theme.getColor("sidebar_lining_thin") - anchors.left: machineSelection.right - } - - ConfigurationSelection - { - id: configSelection - visible: isNetworkPrinter && printerConnected - width: visible ? Math.round(base.width * 0.15) : 0 - height: UM.Theme.getSize("sidebar_header").height - anchors.top: base.top - anchors.right: parent.right - panelWidth: base.width - } - - SidebarHeader { - id: header - width: parent.width - visible: !hideSettings && (machineExtruderCount.properties.value > 1 || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants) - anchors.top: machineSelection.bottom - - onShowTooltip: base.showTooltip(item, location, text) - onHideTooltip: base.hideTooltip() - } - - Rectangle { - id: headerSeparator - width: parent.width - visible: settingsModeSelection.visible && header.visible - height: visible ? UM.Theme.getSize("sidebar_lining").height : 0 - color: UM.Theme.getColor("sidebar_lining") - anchors.top: header.bottom - anchors.topMargin: visible ? UM.Theme.getSize("sidebar_margin").height : 0 - } - - onCurrentModeIndexChanged: - { - UM.Preferences.setValue("cura/active_mode", currentModeIndex); - if(modesListModel.count > base.currentModeIndex) - { - sidebarContents.replace(modesListModel.get(base.currentModeIndex).item, { "replace": true }) - } - } - - Label - { - id: settingsModeLabel - text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox", "Print Setup disabled\nG-code files cannot be modified") - renderType: Text.NativeRendering - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.top: hideSettings ? machineSelection.bottom : headerSeparator.bottom - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - width: Math.round(parent.width * 0.45) - font: UM.Theme.getFont("large") - color: UM.Theme.getColor("text") - visible: !hideView - } - - // Settings mode selection toggle - Rectangle - { - id: settingsModeSelection - color: "transparent" - - width: Math.round(parent.width * 0.55) - height: UM.Theme.getSize("sidebar_header_mode_toggle").height - - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - anchors.top: - { - if (settingsModeLabel.contentWidth >= parent.width - width - UM.Theme.getSize("sidebar_margin").width * 2) - { - return settingsModeLabel.bottom; - } - else - { - return headerSeparator.bottom; - } - } - - visible: !hideSettings && !hideView - - Component - { - id: wizardDelegate - - Button - { - id: control - - height: settingsModeSelection.height - width: Math.round(parent.width / 2) - - anchors.left: parent.left - anchors.leftMargin: model.index * Math.round(settingsModeSelection.width / 2) - anchors.verticalCenter: parent.verticalCenter - - ButtonGroup.group: modeMenuGroup - - checkable: true - checked: base.currentModeIndex == index - onClicked: base.currentModeIndex = index - - onHoveredChanged: - { - if (hovered) - { - tooltipDelayTimer.item = settingsModeSelection - tooltipDelayTimer.text = model.tooltipText - tooltipDelayTimer.start() - } - else - { - tooltipDelayTimer.stop() - base.hideTooltip() - } - } - - background: Rectangle - { - border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width - border.color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_border") : control.hovered ? UM.Theme.getColor("action_button_hovered_border"): UM.Theme.getColor("action_button_border") - - // for some reason, QtQuick decided to use the color of the background property as text color for the contentItem, so here it is - color: (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") - } - - contentItem: Label - { - text: model.text - font: UM.Theme.getFont("default") - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - renderType: Text.NativeRendering - elide: Text.ElideRight - color: - { - if(control.pressed) - { - return UM.Theme.getColor("action_button_active_text"); - } - else if(control.hovered) - { - return UM.Theme.getColor("action_button_hovered_text"); - } - return UM.Theme.getColor("action_button_text"); - } - } - } - } - - ButtonGroup - { - id: modeMenuGroup - } - - ListView - { - id: modesList - model: modesListModel - delegate: wizardDelegate - anchors.top: parent.top - anchors.left: parent.left - width: parent.width - } - } - - StackView - { - id: sidebarContents - - anchors.bottom: footerSeparator.top - anchors.top: settingsModeSelection.bottom - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - anchors.left: base.left - anchors.right: base.right - visible: !hideSettings - - replaceEnter: Transition { - PropertyAnimation { - property: "opacity" - from: 0 - to:1 - duration: 100 - } - } - - replaceExit: Transition { - PropertyAnimation { - property: "opacity" - from: 1 - to:0 - duration: 100 - } - } - } - - Loader - { - anchors.bottom: footerSeparator.top - anchors.top: headerSeparator.bottom - anchors.left: base.left - anchors.right: base.right - source: "SidebarContents.qml" - } - - Rectangle - { - id: footerSeparator - width: parent.width - height: UM.Theme.getSize("sidebar_lining").height - color: UM.Theme.getColor("sidebar_lining") - anchors.bottom: printSpecs.top - anchors.bottomMargin: Math.round(UM.Theme.getSize("sidebar_margin").height * 2 + UM.Theme.getSize("progressbar").height + UM.Theme.getFont("default_bold").pixelSize) - } - - Item - { - id: printSpecs - anchors.left: parent.left - anchors.bottom: parent.bottom - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height - height: timeDetails.height + costSpec.height - width: base.width - (saveButton.buttonRowWidth + UM.Theme.getSize("sidebar_margin").width) - clip: true - - Label - { - id: timeDetails - anchors.left: parent.left - anchors.bottom: costSpec.top - font: UM.Theme.getFont("large") - color: UM.Theme.getColor("text_subtext") - text: (!base.printDuration || !base.printDuration.valid) ? catalog.i18nc("@label Hours and minutes", "00h 00min") : base.printDuration.getDisplayString(UM.DurationFormat.Short) - renderType: Text.NativeRendering - - MouseArea - { - id: timeDetailsMouseArea - anchors.fill: parent - hoverEnabled: true - - onEntered: - { - if(base.printDuration.valid && !base.printDuration.isTotalDurationZero) - { - // All the time information for the different features is achieved - var print_time = PrintInformation.getFeaturePrintTimes(); - var total_seconds = parseInt(base.printDuration.getDisplayString(UM.DurationFormat.Seconds)) - - // A message is created and displayed when the user hover the time label - var tooltip_html = "%1
".arg(catalog.i18nc("@tooltip", "Time specification")); - for(var feature in print_time) - { - if(!print_time[feature].isTotalDurationZero) - { - tooltip_html += "" + - "".arg(print_time[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)) + - "".arg(Math.round(100 * parseInt(print_time[feature].getDisplayString(UM.DurationFormat.Seconds)) / total_seconds)) + - ""; - } - } - tooltip_html += "
" + feature + ":  %1  %1%
"; - - base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), tooltip_html); - } - } - onExited: - { - base.hideTooltip(); - } - } - } - - Label - { - function formatRow(items) - { - var row_html = ""; - for(var item = 0; item < items.length; item++) - { - if (item == 0) - { - row_html += "%1".arg(items[item]); - } - else - { - row_html += "  %1".arg(items[item]); - } - } - row_html += ""; - return row_html; - } - - function getSpecsData() - { - var lengths = []; - var total_length = 0; - var weights = []; - var total_weight = 0; - var costs = []; - var total_cost = 0; - var some_costs_known = false; - var names = []; - if(base.printMaterialLengths) - { - for(var index = 0; index < base.printMaterialLengths.length; index++) - { - if(base.printMaterialLengths[index] > 0) - { - names.push(base.printMaterialNames[index]); - lengths.push(base.printMaterialLengths[index].toFixed(2)); - weights.push(String(Math.round(base.printMaterialWeights[index]))); - var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2); - costs.push(cost); - if(cost > 0) - { - some_costs_known = true; - } - - total_length += base.printMaterialLengths[index]; - total_weight += base.printMaterialWeights[index]; - total_cost += base.printMaterialCosts[index]; - } - } - } - if(lengths.length == 0) - { - lengths = ["0.00"]; - weights = ["0"]; - costs = ["0.00"]; - } - - var tooltip_html = "%1
".arg(catalog.i18nc("@label", "Cost specification")); - for(var index = 0; index < lengths.length; index++) - { - tooltip_html += formatRow([ - "%1:".arg(names[index]), - catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]), - catalog.i18nc("@label g for grams", "%1g").arg(weights[index]), - "%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]), - ]); - } - if(lengths.length > 1) - { - tooltip_html += formatRow([ - catalog.i18nc("@label", "Total:"), - catalog.i18nc("@label m for meter", "%1m").arg(total_length.toFixed(2)), - catalog.i18nc("@label g for grams", "%1g").arg(Math.round(total_weight)), - "%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(total_cost.toFixed(2)), - ]); - } - tooltip_html += "
"; - tooltipText = tooltip_html; - - return tooltipText - } - - id: costSpec - anchors.left: parent.left - anchors.bottom: parent.bottom - font: UM.Theme.getFont("very_small") - renderType: Text.NativeRendering - color: UM.Theme.getColor("text_subtext") - elide: Text.ElideMiddle - width: parent.width - property string tooltipText - text: - { - var lengths = []; - var weights = []; - var costs = []; - var someCostsKnown = false; - if(base.printMaterialLengths) { - for(var index = 0; index < base.printMaterialLengths.length; index++) - { - if(base.printMaterialLengths[index] > 0) - { - lengths.push(base.printMaterialLengths[index].toFixed(2)); - weights.push(String(Math.round(base.printMaterialWeights[index]))); - var cost = base.printMaterialCosts[index] == undefined ? 0 : base.printMaterialCosts[index].toFixed(2); - costs.push(cost); - if(cost > 0) - { - someCostsKnown = true; - } - } - } - } - if(lengths.length == 0) - { - lengths = ["0.00"]; - weights = ["0"]; - costs = ["0.00"]; - } - var result = lengths.join(" + ") + "m / ~ " + weights.join(" + ") + "g"; - if(someCostsKnown) - { - result += " / ~ " + costs.join(" + ") + " " + UM.Preferences.getValue("cura/currency"); - } - return result; - } - MouseArea - { - id: costSpecMouseArea - anchors.fill: parent - hoverEnabled: true - - onEntered: - { - - if(base.printDuration.valid && !base.printDuration.isTotalDurationZero) - { - var show_data = costSpec.getSpecsData() - - base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), show_data); - } - } - onExited: - { - base.hideTooltip(); - } - } - } - } - - // SaveButton is actually the bottom footer panel. - SaveButton - { - id: saveButton - implicitWidth: base.width - anchors.top: footerSeparator.bottom - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - anchors.bottom: parent.bottom - } - - SidebarTooltip - { - id: tooltip - } - - // Setting mode: Recommended or Custom - ListModel - { - id: modesListModel - } - - SidebarSimple - { - id: sidebarSimple - visible: false - - onShowTooltip: base.showTooltip(item, location, text) - onHideTooltip: base.hideTooltip() - } - - SidebarAdvanced - { - id: sidebarAdvanced - visible: false - - onShowTooltip: base.showTooltip(item, location, text) - onHideTooltip: base.hideTooltip() - } - - Component.onCompleted: - { - modesListModel.append({ - text: catalog.i18nc("@title:tab", "Recommended"), - tooltipText: catalog.i18nc("@tooltip", "Recommended Print Setup

Print with the recommended settings for the selected printer, material and quality."), - item: sidebarSimple - }) - modesListModel.append({ - text: catalog.i18nc("@title:tab", "Custom"), - tooltipText: catalog.i18nc("@tooltip", "Custom Print Setup

Print with finegrained control over every last bit of the slicing process."), - item: sidebarAdvanced - }) - - var index = Math.round(UM.Preferences.getValue("cura/active_mode")) - - if(index != null && !isNaN(index)) - { - currentModeIndex = index; - } - else - { - currentModeIndex = 0; - } - } - - UM.SettingPropertyProvider - { - id: machineExtruderCount - - containerStack: Cura.MachineManager.activeMachine - key: "machine_extruder_count" - watchedProperties: [ "value" ] - storeIndex: 0 - } - - UM.SettingPropertyProvider - { - id: machineHeatedBed - - containerStack: Cura.MachineManager.activeMachine - key: "machine_heated_bed" - watchedProperties: [ "value" ] - storeIndex: 0 - } -} diff --git a/resources/qml/PrimaryButton.qml b/resources/qml/PrimaryButton.qml new file mode 100644 index 0000000000..fca63d2cdb --- /dev/null +++ b/resources/qml/PrimaryButton.qml @@ -0,0 +1,20 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 + +import UM 1.4 as UM +import Cura 1.1 as Cura + + +Cura.ActionButton +{ + shadowEnabled: true + shadowColor: enabled ? UM.Theme.getColor("primary_button_shadow"): UM.Theme.getColor("action_button_disabled_shadow") + color: UM.Theme.getColor("primary_button") + textColor: UM.Theme.getColor("primary_button_text") + outlineColor: "transparent" + disabledColor: UM.Theme.getColor("action_button_disabled") + textDisabledColor: UM.Theme.getColor("action_button_disabled_text") + hoverColor: UM.Theme.getColor("primary_button_hover") +} \ No newline at end of file diff --git a/resources/qml/PrintMonitor.qml b/resources/qml/PrintMonitor.qml index 12e95d1e89..d44acf0adb 100644 --- a/resources/qml/PrintMonitor.qml +++ b/resources/qml/PrintMonitor.qml @@ -11,136 +11,176 @@ import Cura 1.0 as Cura import "PrinterOutput" -Column + +Item { - id: printMonitor + id: base + UM.I18nCatalog { id: catalog; name: "cura"} + + function showTooltip(item, position, text) + { + tooltip.text = text; + position = item.mapToItem(base, position.x - UM.Theme.getSize("default_arrow").width, position.y); + tooltip.show(position); + } + + function hideTooltip() + { + tooltip.hide(); + } + + function strPadLeft(string, pad, length) { + return (new Array(length + 1).join(pad) + string).slice(-length); + } + + function getPrettyTime(time) + { + var hours = Math.floor(time / 3600) + time -= hours * 3600 + var minutes = Math.floor(time / 60); + time -= minutes * 60 + var seconds = Math.floor(time); + + var finalTime = strPadLeft(hours, "0", 2) + ":" + strPadLeft(minutes, "0", 2) + ":" + strPadLeft(seconds, "0", 2); + return finalTime; + } + property var connectedDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null property var activePrinter: connectedDevice != null ? connectedDevice.activePrinter : null property var activePrintJob: activePrinter != null ? activePrinter.activePrintJob: null - Cura.ExtrudersModel + PrintSetupTooltip { - id: extrudersModel - simpleNames: true + id: tooltip } - OutputDeviceHeader + Column { - outputDevice: connectedDevice - } + id: printMonitor - Rectangle - { - color: UM.Theme.getColor("sidebar_lining") - width: parent.width - height: childrenRect.height + anchors.fill: parent - Flow + property var extrudersModel: CuraApplication.getExtrudersModel() + + OutputDeviceHeader { - id: extrudersGrid - spacing: UM.Theme.getSize("sidebar_lining_thin").width + outputDevice: connectedDevice + } + + Rectangle + { + color: UM.Theme.getColor("wide_lining") width: parent.width + height: childrenRect.height - Repeater + Flow { - id: extrudersRepeater - model: activePrinter != null ? activePrinter.extruders : null + id: extrudersGrid + spacing: UM.Theme.getSize("thick_lining").width + width: parent.width - ExtruderBox + Repeater { - color: UM.Theme.getColor("sidebar") - width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : Math.round(extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2) - extruderModel: modelData + id: extrudersRepeater + model: activePrinter != null ? activePrinter.extruders : null + + ExtruderBox + { + color: UM.Theme.getColor("main_background") + width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : Math.round(extrudersGrid.width / 2 - UM.Theme.getSize("thick_lining").width / 2) + extruderModel: modelData + } } } } - } - Rectangle - { - color: UM.Theme.getColor("sidebar_lining") - width: parent.width - height: UM.Theme.getSize("sidebar_lining_thin").width - } - - HeatedBedBox - { - visible: { - if(activePrinter != null && activePrinter.bedTemperature != -1) - { - return true - } - return false - } - printerModel: activePrinter - } - - UM.SettingPropertyProvider - { - id: bedTemperature - containerStack: Cura.MachineManager.activeMachine - key: "material_bed_temperature" - watchedProperties: ["value", "minimum_value", "maximum_value", "resolve"] - storeIndex: 0 - - property var resolve: Cura.MachineManager.activeStack != Cura.MachineManager.activeMachine ? properties.resolve : "None" - } - - UM.SettingPropertyProvider - { - id: machineExtruderCount - containerStack: Cura.MachineManager.activeMachine - key: "machine_extruder_count" - watchedProperties: ["value"] - } - - ManualPrinterControl - { - printerModel: activePrinter - visible: activePrinter != null ? activePrinter.canControlManually : false - } - - - MonitorSection - { - label: catalog.i18nc("@label", "Active print") - width: base.width - visible: activePrinter != null - } - - - MonitorItem - { - label: catalog.i18nc("@label", "Job Name") - value: activePrintJob != null ? activePrintJob.name : "" - width: base.width - visible: activePrinter != null - } - - MonitorItem - { - label: catalog.i18nc("@label", "Printing Time") - value: activePrintJob != null ? getPrettyTime(activePrintJob.timeTotal) : "" - width: base.width - visible: activePrinter != null - } - - MonitorItem - { - label: catalog.i18nc("@label", "Estimated time left") - value: activePrintJob != null ? getPrettyTime(activePrintJob.timeTotal - activePrintJob.timeElapsed) : "" - visible: + Rectangle { - if(activePrintJob == null) + color: UM.Theme.getColor("wide_lining") + width: parent.width + height: UM.Theme.getSize("thick_lining").width + } + + HeatedBedBox + { + visible: { + if(activePrinter != null && activePrinter.bedTemperature != -1) + { + return true + } return false } - - return (activePrintJob.state == "printing" || - activePrintJob.state == "resuming" || - activePrintJob.state == "pausing" || - activePrintJob.state == "paused") + printerModel: activePrinter + } + + UM.SettingPropertyProvider + { + id: bedTemperature + containerStack: Cura.MachineManager.activeMachine + key: "material_bed_temperature" + watchedProperties: ["value", "minimum_value", "maximum_value", "resolve"] + storeIndex: 0 + + property var resolve: Cura.MachineManager.activeStack != Cura.MachineManager.activeMachine ? properties.resolve : "None" + } + + UM.SettingPropertyProvider + { + id: machineExtruderCount + containerStack: Cura.MachineManager.activeMachine + key: "machine_extruder_count" + watchedProperties: ["value"] + } + + ManualPrinterControl + { + printerModel: activePrinter + visible: activePrinter != null ? activePrinter.canControlManually : false + } + + + MonitorSection + { + label: catalog.i18nc("@label", "Active print") + width: base.width + visible: activePrinter != null + } + + + MonitorItem + { + label: catalog.i18nc("@label", "Job Name") + value: activePrintJob != null ? activePrintJob.name : "" + width: base.width + visible: activePrinter != null + } + + MonitorItem + { + label: catalog.i18nc("@label", "Printing Time") + value: activePrintJob != null ? getPrettyTime(activePrintJob.timeTotal) : "" + width: base.width + visible: activePrinter != null + } + + MonitorItem + { + label: catalog.i18nc("@label", "Estimated time left") + value: activePrintJob != null ? getPrettyTime(activePrintJob.timeTotal - activePrintJob.timeElapsed) : "" + visible: + { + if(activePrintJob == null) + { + return false + } + + return (activePrintJob.state == "printing" || + activePrintJob.state == "resuming" || + activePrintJob.state == "pausing" || + activePrintJob.state == "paused") + } + width: base.width } - width: base.width } -} +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml new file mode 100644 index 0000000000..98bb5c0405 --- /dev/null +++ b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml @@ -0,0 +1,131 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.3 as UM +import Cura 1.0 as Cura + + +Item +{ + id: customPrintSetup + + property real padding: UM.Theme.getSize("default_margin").width + property bool multipleExtruders: extrudersModel.count > 1 + + property var extrudersModel: CuraApplication.getExtrudersModel() + + // Profile selector row + GlobalProfileSelector + { + id: globalProfileRow + anchors + { + top: parent.top + topMargin: parent.padding + left: parent.left + leftMargin: parent.padding + right: parent.right + rightMargin: parent.padding + } + } + + UM.TabRow + { + id: tabBar + + visible: multipleExtruders // The tab row is only visible when there are more than 1 extruder + + anchors + { + top: globalProfileRow.bottom + topMargin: UM.Theme.getSize("default_margin").height + left: parent.left + leftMargin: parent.padding + right: parent.right + rightMargin: parent.padding + } + + Repeater + { + id: repeater + model: extrudersModel + delegate: UM.TabRowButton + { + contentItem: Item + { + Cura.ExtruderIcon + { + anchors.horizontalCenter: parent.horizontalCenter + materialColor: model.color + extruderEnabled: model.enabled + } + } + onClicked: + { + Cura.ExtruderManager.setActiveExtruderIndex(tabBar.currentIndex) + } + } + } + + //When active extruder changes for some other reason, switch tabs. + //Don't directly link currentIndex to Cura.ExtruderManager.activeExtruderIndex! + //This causes a segfault in Qt 5.11. Something with VisualItemModel removing index -1. We have to use setCurrentIndex instead. + Connections + { + target: Cura.ExtruderManager + onActiveExtruderChanged: + { + tabBar.setCurrentIndex(Cura.ExtruderManager.activeExtruderIndex); + } + } + + //When the model of the extruders is rebuilt, the list of extruders is briefly emptied and rebuilt. + //This causes the currentIndex of the tab to be in an invalid position which resets it to 0. + //Therefore we need to change it back to what it was: The active extruder index. + Connections + { + target: repeater.model + onModelChanged: + { + tabBar.setCurrentIndex(Cura.ExtruderManager.activeExtruderIndex) + } + } + } + + Rectangle + { + anchors + { + top: tabBar.visible ? tabBar.bottom : globalProfileRow.bottom + topMargin: -UM.Theme.getSize("default_lining").width + left: parent.left + leftMargin: parent.padding + right: parent.right + rightMargin: parent.padding + bottom: parent.bottom + } + z: tabBar.z - 1 + // Don't show the border when only one extruder + + border.color: tabBar.visible ? UM.Theme.getColor("lining") : "transparent" + border.width: UM.Theme.getSize("default_lining").width + + color: UM.Theme.getColor("main_background") + Cura.SettingView + { + anchors + { + fill: parent + topMargin: UM.Theme.getSize("default_margin").height + leftMargin: UM.Theme.getSize("default_margin").width + // Small space for the scrollbar + rightMargin: UM.Theme.getSize("narrow_margin").width + // Compensate for the negative margin in the parent + bottomMargin: UM.Theme.getSize("default_lining").width + } + } + } +} diff --git a/resources/qml/PrintSetupSelector/Custom/GlobalProfileSelector.qml b/resources/qml/PrintSetupSelector/Custom/GlobalProfileSelector.qml new file mode 100644 index 0000000000..32c07a52a6 --- /dev/null +++ b/resources/qml/PrintSetupSelector/Custom/GlobalProfileSelector.qml @@ -0,0 +1,100 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Layouts 1.2 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Item +{ + id: globalProfileRow + height: childrenRect.height + + Label + { + id: globalProfileLabel + anchors + { + top: parent.top + bottom: parent.bottom + left: parent.left + right: globalProfileSelection.left + } + text: catalog.i18nc("@label", "Profile") + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text") + verticalAlignment: Text.AlignVCenter + } + + ToolButton + { + id: globalProfileSelection + + text: generateActiveQualityText() + width: UM.Theme.getSize("print_setup_big_item").width + height: UM.Theme.getSize("print_setup_big_item").height + anchors + { + top: parent.top + right: parent.right + } + tooltip: Cura.MachineManager.activeQualityOrQualityChangesName + style: UM.Theme.styles.print_setup_header_button + activeFocusOnPress: true + menu: Cura.ProfileMenu { } + + function generateActiveQualityText() + { + var result = Cura.MachineManager.activeQualityOrQualityChangesName + if (Cura.MachineManager.isActiveQualityExperimental) + { + result += " (Experimental)" + } + + if (Cura.MachineManager.isActiveQualitySupported) + { + if (Cura.MachineManager.activeQualityLayerHeight > 0) + { + result += " " + result += " - " + result += Cura.MachineManager.activeQualityLayerHeight + "mm" + result += "" + } + } + + return result + } + + UM.SimpleButton + { + id: customisedSettings + + visible: Cura.MachineManager.hasUserSettings + width: UM.Theme.getSize("print_setup_icon").width + height: UM.Theme.getSize("print_setup_icon").height + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: Math.round(UM.Theme.getSize("setting_preferences_button_margin").width - UM.Theme.getSize("thick_margin").width) + + color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button"); + iconSource: UM.Theme.getIcon("star") + + onClicked: + { + forceActiveFocus(); + Cura.Actions.manageProfiles.trigger() + } + onEntered: + { + var content = catalog.i18nc("@tooltip","Some setting/override values are different from the values stored in the profile.\n\nClick to open the profile manager.") + base.showTooltip(globalProfileRow, Qt.point(-UM.Theme.getSize("default_margin").width, 0), content) + } + onExited: base.hideTooltip() + } + } +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/PrintSetupSelector.qml b/resources/qml/PrintSetupSelector/PrintSetupSelector.qml new file mode 100644 index 0000000000..48ac07679d --- /dev/null +++ b/resources/qml/PrintSetupSelector/PrintSetupSelector.qml @@ -0,0 +1,35 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +import UM 1.3 as UM +import Cura 1.0 as Cura + +Cura.ExpandableComponent +{ + id: printSetupSelector + + property bool preSlicedData: PrintInformation.preSliced + + contentPadding: UM.Theme.getSize("default_lining").width + contentHeaderTitle: catalog.i18nc("@label", "Print settings") + enabled: !preSlicedData + disabledText: catalog.i18nc("@label shown when we load a Gcode file", "Print setup disabled. G code file can not be modified.") + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + headerItem: PrintSetupSelectorHeader {} + + property var extrudersModel: CuraApplication.getExtrudersModel() + + contentItem: PrintSetupSelectorContents {} + + onExpandedChanged: UM.Preferences.setValue("view/settings_visible", expanded) + Component.onCompleted: expanded = UM.Preferences.getValue("view/settings_visible") +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml b/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml new file mode 100644 index 0000000000..7c82a7324d --- /dev/null +++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml @@ -0,0 +1,197 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.3 as UM +import Cura 1.0 as Cura + +import "Recommended" +import "Custom" + +Item +{ + id: content + + width: UM.Theme.getSize("print_setup_widget").width - 2 * UM.Theme.getSize("default_margin").width + height: contents.height + buttonRow.height + + enum Mode + { + Recommended = 0, + Custom = 1 + } + + // Set the current mode index to the value that is stored in the preferences or Recommended mode otherwise. + property int currentModeIndex: + { + var index = Math.round(UM.Preferences.getValue("cura/active_mode")) + + if (index != null && !isNaN(index)) + { + return index + } + return PrintSetupSelectorContents.Mode.Recommended + } + onCurrentModeIndexChanged: UM.Preferences.setValue("cura/active_mode", currentModeIndex) + + Item + { + id: contents + // Use the visible property instead of checking the currentModeIndex. That creates a binding that + // evaluates the new height every time the visible property changes. + height: recommendedPrintSetup.visible ? recommendedPrintSetup.height : customPrintSetup.height + + anchors + { + top: parent.top + left: parent.left + right: parent.right + } + + RecommendedPrintSetup + { + id: recommendedPrintSetup + anchors + { + left: parent.left + right: parent.right + top: parent.top + } + visible: currentModeIndex == PrintSetupSelectorContents.Mode.Recommended + } + + CustomPrintSetup + { + id: customPrintSetup + anchors + { + left: parent.left + right: parent.right + top: parent.top + } + height: UM.Preferences.getValue("view/settings_list_height") - UM.Theme.getSize("default_margin").height + Connections + { + target: UM.Preferences + onPreferenceChanged: + { + customPrintSetup.height = + Math.min + ( + UM.Preferences.getValue("view/settings_list_height"), + base.height - (customPrintSetup.mapToItem(null, 0, 0).y + buttonRow.height + UM.Theme.getSize("default_margin").height) + ); + } + } + visible: currentModeIndex == PrintSetupSelectorContents.Mode.Custom + } + } + + Rectangle + { + id: buttonsSeparator + + // The buttonsSeparator is inside the contents. This is to avoid a double line in the bottom + anchors.bottom: contents.bottom + width: parent.width + height: UM.Theme.getSize("default_lining").height + color: UM.Theme.getColor("lining") + } + + Item + { + id: buttonRow + property real padding: UM.Theme.getSize("default_margin").width + height: childrenRect.height + 2 * padding + + anchors + { + bottom: parent.bottom + left: parent.left + right: parent.right + } + + Cura.SecondaryButton + { + id: recommendedButton + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: parent.padding + leftPadding: UM.Theme.getSize("default_margin").width + rightPadding: UM.Theme.getSize("default_margin").width + text: catalog.i18nc("@button", "Recommended") + iconSource: UM.Theme.getIcon("arrow_left") + visible: currentModeIndex == PrintSetupSelectorContents.Mode.Custom + onClicked: currentModeIndex = PrintSetupSelectorContents.Mode.Recommended + } + + Cura.SecondaryButton + { + anchors.top: parent.top + anchors.right: parent.right + anchors.margins: UM.Theme.getSize("default_margin").width + leftPadding: UM.Theme.getSize("default_margin").width + rightPadding: UM.Theme.getSize("default_margin").width + text: catalog.i18nc("@button", "Custom") + iconSource: UM.Theme.getIcon("arrow_right") + isIconOnRightSide: true + visible: currentModeIndex == PrintSetupSelectorContents.Mode.Recommended + onClicked: currentModeIndex = PrintSetupSelectorContents.Mode.Custom + } + + //Invisible area at the bottom with which you can resize the panel. + MouseArea + { + anchors + { + left: parent.left + right: parent.right + bottom: parent.bottom + top: recommendedButton.bottom + topMargin: UM.Theme.getSize("default_lining").height + } + cursorShape: Qt.SplitVCursor + visible: currentModeIndex == PrintSetupSelectorContents.Mode.Custom + drag + { + target: parent + axis: Drag.YAxis + } + onMouseYChanged: + { + if(drag.active) + { + // position of mouse relative to dropdown align vertical centre of mouse area to cursor + // v------------------------------v v------------v + var h = mouseY + buttonRow.y + content.y - height / 2 | 0; + if(h < 200 * screenScaleFactor) //Enforce a minimum size. + { + h = 200 * screenScaleFactor; + } + + //Absolute mouse Y position in the window, to prevent it from going outside the window. + var mouse_absolute_y = mapToGlobal(mouseX, mouseY).y - UM.Preferences.getValue("general/window_top"); + if(mouse_absolute_y > base.height) + { + h -= mouse_absolute_y - base.height; + } + + UM.Preferences.setValue("view/settings_list_height", h); + } + } + + UM.RecolorImage + { + width: parent.width * 0.05 + height: parent.height * 0.3 + + anchors.centerIn: parent + + source: UM.Theme.getIcon("grip_lines") + color: UM.Theme.getColor("lining") + } + } + } +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml b/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml new file mode 100644 index 0000000000..96b244d803 --- /dev/null +++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml @@ -0,0 +1,88 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 + +import UM 1.3 as UM +import Cura 1.0 as Cura + +RowLayout +{ + property string enabledText: catalog.i18nc("@label:Should be short", "On") + property string disabledText: catalog.i18nc("@label:Should be short", "Off") + + Cura.IconWithText + { + source: UM.Theme.getIcon("category_layer_height") + text: + { + if (Cura.MachineManager.activeStack) + { + var text = Cura.MachineManager.activeQualityOrQualityChangesName + if (!Cura.MachineManager.hasNotSupportedQuality) + { + text += " " + layerHeight.properties.value + "mm" + text += Cura.MachineManager.isActiveQualityExperimental ? " - " + catalog.i18nc("@label", "Experimental") : "" + } + return text + } + return "" + } + font: UM.Theme.getFont("medium") + + UM.SettingPropertyProvider + { + id: layerHeight + containerStack: Cura.MachineManager.activeStack + key: "layer_height" + watchedProperties: ["value"] + } + } + + Cura.IconWithText + { + source: UM.Theme.getIcon("category_infill") + text: Cura.MachineManager.activeStack ? parseInt(infillDensity.properties.value) + "%" : "0%" + font: UM.Theme.getFont("medium") + + UM.SettingPropertyProvider + { + id: infillDensity + containerStack: Cura.MachineManager.activeStack + key: "infill_sparse_density" + watchedProperties: ["value"] + } + } + + Cura.IconWithText + { + source: UM.Theme.getIcon("category_support") + text: supportEnabled.properties.value == "True" ? enabledText : disabledText + font: UM.Theme.getFont("medium") + + UM.SettingPropertyProvider + { + id: supportEnabled + containerStack: Cura.MachineManager.activeMachine + key: "support_enable" + watchedProperties: ["value"] + } + } + + Cura.IconWithText + { + source: UM.Theme.getIcon("category_adhesion") + text: platformAdhesionType.properties.value != "skirt" && platformAdhesionType.properties.value != "none" ? enabledText : disabledText + font: UM.Theme.getFont("medium") + + UM.SettingPropertyProvider + { + id: platformAdhesionType + containerStack: Cura.MachineManager.activeMachine + key: "adhesion_type" + watchedProperties: [ "value"] + } + } +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedAdhesionSelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedAdhesionSelector.qml new file mode 100644 index 0000000000..941199707c --- /dev/null +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedAdhesionSelector.qml @@ -0,0 +1,101 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + + +// +// Adhesion +// +Item +{ + id: enableAdhesionRow + height: childrenRect.height + + property real labelColumnWidth: Math.round(width / 3) + + Cura.IconWithText + { + id: enableAdhesionRowTitle + anchors.top: parent.top + anchors.left: parent.left + source: UM.Theme.getIcon("category_adhesion") + text: catalog.i18nc("@label", "Adhesion") + font: UM.Theme.getFont("medium") + width: labelColumnWidth + } + + Item + { + id: enableAdhesionContainer + height: enableAdhesionCheckBox.height + + anchors + { + left: enableAdhesionRowTitle.right + right: parent.right + verticalCenter: enableAdhesionRowTitle.verticalCenter + } + + CheckBox + { + id: enableAdhesionCheckBox + anchors.verticalCenter: parent.verticalCenter + + property alias _hovered: adhesionMouseArea.containsMouse + + //: Setting enable printing build-plate adhesion helper checkbox + style: UM.Theme.styles.checkbox + enabled: recommendedPrintSetup.settingsEnabled + + visible: platformAdhesionType.properties.enabled == "True" + checked: platformAdhesionType.properties.value != "skirt" && platformAdhesionType.properties.value != "none" + + MouseArea + { + id: adhesionMouseArea + anchors.fill: parent + hoverEnabled: true + + onClicked: + { + var adhesionType = "skirt" + if (!parent.checked) + { + // Remove the "user" setting to see if the rest of the stack prescribes a brim or a raft + platformAdhesionType.removeFromContainer(0) + adhesionType = platformAdhesionType.properties.value + if(adhesionType == "skirt" || adhesionType == "none") + { + // If the rest of the stack doesn't prescribe an adhesion-type, default to a brim + adhesionType = "brim" + } + } + platformAdhesionType.setPropertyValue("value", adhesionType) + } + + onEntered: + { + base.showTooltip(enableAdhesionCheckBox, Qt.point(-enableAdhesionContainer.x - UM.Theme.getSize("thick_margin").width, 0), + catalog.i18nc("@label", "Enable printing a brim or raft. This will add a flat area around or under your object which is easy to cut off afterwards.")); + } + onExited: base.hideTooltip() + } + } + } + + UM.SettingPropertyProvider + { + id: platformAdhesionType + containerStack: Cura.MachineManager.activeMachine + removeUnusedValue: false //Doesn't work with settings that are resolved. + key: "adhesion_type" + watchedProperties: [ "value", "enabled" ] + storeIndex: 0 + } +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml new file mode 100644 index 0000000000..19f199fea6 --- /dev/null +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml @@ -0,0 +1,255 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + + +// +// Infill +// +Item +{ + id: infillRow + height: childrenRect.height + + property real labelColumnWidth: Math.round(width / 3) + + // Create a binding to update the icon when the infill density changes + Binding + { + target: infillRowTitle + property: "source" + value: + { + var density = parseInt(infillDensity.properties.value) + if (parseInt(infillSteps.properties.value) != 0) + { + return UM.Theme.getIcon("gradual") + } + if (density <= 0) + { + return UM.Theme.getIcon("hollow") + } + if (density < 40) + { + return UM.Theme.getIcon("sparse") + } + if (density < 90) + { + return UM.Theme.getIcon("dense") + } + return UM.Theme.getIcon("solid") + } + } + + // We use a binding to make sure that after manually setting infillSlider.value it is still bound to the property provider + Binding + { + target: infillSlider + property: "value" + value: parseInt(infillDensity.properties.value) + } + + // Here are the elements that are shown in the left column + Cura.IconWithText + { + id: infillRowTitle + anchors.top: parent.top + anchors.left: parent.left + source: UM.Theme.getIcon("category_infill") + text: catalog.i18nc("@label", "Infill") + " (%)" + font: UM.Theme.getFont("medium") + width: labelColumnWidth + } + + Item + { + id: infillSliderContainer + height: childrenRect.height + + anchors + { + left: infillRowTitle.right + right: parent.right + verticalCenter: infillRowTitle.verticalCenter + } + + Slider + { + id: infillSlider + + width: parent.width + height: UM.Theme.getSize("print_setup_slider_handle").height // The handle is the widest element of the slider + + minimumValue: 0 + maximumValue: 100 + stepSize: 1 + tickmarksEnabled: true + + // disable slider when gradual support is enabled + enabled: parseInt(infillSteps.properties.value) == 0 + + // set initial value from stack + value: parseInt(infillDensity.properties.value) + + style: SliderStyle + { + //Draw line + groove: Item + { + Rectangle + { + height: UM.Theme.getSize("print_setup_slider_groove").height + width: control.width - UM.Theme.getSize("print_setup_slider_handle").width + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") + } + } + + handle: Rectangle + { + id: handleButton + color: control.enabled ? UM.Theme.getColor("primary") : UM.Theme.getColor("quality_slider_unavailable") + implicitWidth: UM.Theme.getSize("print_setup_slider_handle").width + implicitHeight: implicitWidth + radius: Math.round(implicitWidth / 2) + } + + tickmarks: Repeater + { + id: repeater + model: control.maximumValue / control.stepSize + 1 + + Rectangle + { + color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") + implicitWidth: UM.Theme.getSize("print_setup_slider_tickmarks").width + implicitHeight: UM.Theme.getSize("print_setup_slider_tickmarks").height + anchors.verticalCenter: parent.verticalCenter + + // Do not use Math.round otherwise the tickmarks won't be aligned + x: ((styleData.handleWidth / 2) - (implicitWidth / 2) + (index * ((repeater.width - styleData.handleWidth) / (repeater.count-1)))) + radius: Math.round(implicitWidth / 2) + visible: (index % 10) == 0 // Only show steps of 10% + + Label + { + text: index + font: UM.Theme.getFont("default") + visible: (index % 20) == 0 // Only show steps of 20% + anchors.horizontalCenter: parent.horizontalCenter + y: UM.Theme.getSize("thin_margin").height + renderType: Text.NativeRendering + color: UM.Theme.getColor("quality_slider_available") + } + } + } + } + + onValueChanged: + { + // Don't round the value if it's already the same + if (parseInt(infillDensity.properties.value) == infillSlider.value) + { + return + } + + // Round the slider value to the nearest multiple of 10 (simulate step size of 10) + var roundedSliderValue = Math.round(infillSlider.value / 10) * 10 + + // Update the slider value to represent the rounded value + infillSlider.value = roundedSliderValue + + // Update value only if the Recomended mode is Active, + // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat + // same operation + var active_mode = UM.Preferences.getValue("cura/active_mode") + + if (active_mode == 0 || active_mode == "simple") + { + Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) + Cura.MachineManager.resetSettingForAllExtruders("infill_line_distance") + } + } + } + } + + // Gradual Support Infill Checkbox + CheckBox + { + id: enableGradualInfillCheckBox + property alias _hovered: enableGradualInfillMouseArea.containsMouse + + anchors.top: infillSliderContainer.bottom + anchors.topMargin: UM.Theme.getSize("wide_margin").height + anchors.left: infillSliderContainer.left + + text: catalog.i18nc("@label", "Gradual infill") + style: UM.Theme.styles.checkbox + enabled: recommendedPrintSetup.settingsEnabled + visible: infillSteps.properties.enabled == "True" + checked: parseInt(infillSteps.properties.value) > 0 + + MouseArea + { + id: enableGradualInfillMouseArea + + anchors.fill: parent + hoverEnabled: true + enabled: true + + property var previousInfillDensity: parseInt(infillDensity.properties.value) + + onClicked: + { + // Set to 90% only when enabling gradual infill + var newInfillDensity; + if (parseInt(infillSteps.properties.value) == 0) + { + previousInfillDensity = parseInt(infillDensity.properties.value) + newInfillDensity = 90 + } else { + newInfillDensity = previousInfillDensity + } + Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", String(newInfillDensity)) + + var infill_steps_value = 0 + if (parseInt(infillSteps.properties.value) == 0) + { + infill_steps_value = 5 + } + + Cura.MachineManager.setSettingForAllExtruders("gradual_infill_steps", "value", infill_steps_value) + } + + onEntered: base.showTooltip(enableGradualInfillCheckBox, Qt.point(-infillSliderContainer.x - UM.Theme.getSize("thick_margin").width, 0), + catalog.i18nc("@label", "Gradual infill will gradually increase the amount of infill towards the top.")) + + onExited: base.hideTooltip() + } + } + + UM.SettingPropertyProvider + { + id: infillDensity + containerStackId: Cura.MachineManager.activeStackId + key: "infill_sparse_density" + watchedProperties: [ "value" ] + storeIndex: 0 + } + + UM.SettingPropertyProvider + { + id: infillSteps + containerStackId: Cura.MachineManager.activeStackId + key: "gradual_infill_steps" + watchedProperties: ["value", "enabled"] + storeIndex: 0 + } +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedPrintSetup.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedPrintSetup.qml new file mode 100644 index 0000000000..44b3abf7cd --- /dev/null +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedPrintSetup.qml @@ -0,0 +1,86 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Item +{ + id: recommendedPrintSetup + + height: childrenRect.height + 2 * padding + + property Action configureSettings + + property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1 + property real padding: UM.Theme.getSize("thick_margin").width + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + Column + { + width: parent.width - 2 * parent.padding + spacing: UM.Theme.getSize("wide_margin").height + + anchors + { + left: parent.left + right: parent.right + top: parent.top + margins: parent.padding + } + + // TODO + property real firstColumnWidth: Math.round(width / 3) + + RecommendedQualityProfileSelector + { + width: parent.width + // TODO Create a reusable component with these properties to not define them separately for each component + labelColumnWidth: parent.firstColumnWidth + } + + RecommendedInfillDensitySelector + { + width: parent.width + // TODO Create a reusable component with these properties to not define them separately for each component + labelColumnWidth: parent.firstColumnWidth + } + + RecommendedSupportSelector + { + width: parent.width + // TODO Create a reusable component with these properties to not define them separately for each component + labelColumnWidth: parent.firstColumnWidth + } + + RecommendedAdhesionSelector + { + width: parent.width + // TODO Create a reusable component with these properties to not define them separately for each component + labelColumnWidth: parent.firstColumnWidth + } + + RecommendedTroubleshootingGuides + { + width: parent.width + } + } + + UM.SettingPropertyProvider + { + id: extrudersEnabledCount + containerStack: Cura.MachineManager.activeMachine + key: "extruders_enabled_count" + watchedProperties: [ "value" ] + storeIndex: 0 + } +} diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml new file mode 100644 index 0000000000..801e76382b --- /dev/null +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml @@ -0,0 +1,455 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + + +// +// Quality profile +// +Item +{ + id: qualityRow + height: childrenRect.height + + property real labelColumnWidth: Math.round(width / 3) + property real settingsColumnWidth: width - labelColumnWidth + + Timer + { + id: qualitySliderChangeTimer + interval: 50 + running: false + repeat: false + onTriggered: + { + var item = Cura.QualityProfilesDropDownMenuModel.getItem(qualitySlider.value); + Cura.MachineManager.activeQualityGroup = item.quality_group; + } + } + + Component.onCompleted: qualityModel.update() + + Connections + { + target: Cura.QualityProfilesDropDownMenuModel + onItemsChanged: qualityModel.update() + } + + Connections { + target: base + onVisibleChanged: + { + // update needs to be called when the widgets are visible, otherwise the step width calculation + // will fail because the width of an invisible item is 0. + if (visible) + { + qualityModel.update(); + } + } + } + + ListModel + { + id: qualityModel + + property var totalTicks: 0 + property var availableTotalTicks: 0 + property var existingQualityProfile: 0 + + property var qualitySliderActiveIndex: 0 + property var qualitySliderStepWidth: 0 + property var qualitySliderAvailableMin: 0 + property var qualitySliderAvailableMax: 0 + property var qualitySliderMarginRight: 0 + + function update () + { + reset() + + var availableMin = -1 + var availableMax = -1 + + for (var i = 0; i < Cura.QualityProfilesDropDownMenuModel.rowCount(); i++) + { + var qualityItem = Cura.QualityProfilesDropDownMenuModel.getItem(i) + + // Add each quality item to the UI quality model + qualityModel.append(qualityItem) + + // Set selected value + if (Cura.MachineManager.activeQualityType == qualityItem.quality_type) + { + // set to -1 when switching to user created profile so all ticks are clickable + if (Cura.MachineManager.hasCustomQuality) + { + qualityModel.qualitySliderActiveIndex = -1 + } + else + { + qualityModel.qualitySliderActiveIndex = i + } + + qualityModel.existingQualityProfile = 1 + } + + // Set min available + if (qualityItem.available && availableMin == -1) + { + availableMin = i + } + + // Set max available + if (qualityItem.available) + { + availableMax = i + } + } + + // Set total available ticks for active slider part + if (availableMin != -1) + { + qualityModel.availableTotalTicks = availableMax - availableMin + 1 + } + + // Calculate slider values + calculateSliderStepWidth(qualityModel.totalTicks) + calculateSliderMargins(availableMin, availableMax, qualityModel.totalTicks) + + qualityModel.qualitySliderAvailableMin = availableMin + qualityModel.qualitySliderAvailableMax = availableMax + } + + function calculateSliderStepWidth (totalTicks) + { + // Do not use Math.round otherwise the tickmarks won't be aligned + qualityModel.qualitySliderStepWidth = totalTicks != 0 ? + ((settingsColumnWidth - UM.Theme.getSize("print_setup_slider_handle").width) / (totalTicks)) : 0 + } + + function calculateSliderMargins (availableMin, availableMax, totalTicks) + { + if (availableMin == -1 || (availableMin == 0 && availableMax == 0)) + { + // Do not use Math.round otherwise the tickmarks won't be aligned + qualityModel.qualitySliderMarginRight = settingsColumnWidth + } + else if (availableMin == availableMax) + { + // Do not use Math.round otherwise the tickmarks won't be aligned + qualityModel.qualitySliderMarginRight = (totalTicks - availableMin) * qualitySliderStepWidth + } + else + { + // Do not use Math.round otherwise the tickmarks won't be aligned + qualityModel.qualitySliderMarginRight = (totalTicks - availableMax) * qualitySliderStepWidth + } + } + + function reset () { + qualityModel.clear() + qualityModel.availableTotalTicks = 0 + qualityModel.existingQualityProfile = 0 + + // check, the ticks count cannot be less than zero + qualityModel.totalTicks = Math.max(0, Cura.QualityProfilesDropDownMenuModel.rowCount() - 1) + } + } + + // Here are the elements that are shown in the left column + Item + { + id: titleRow + width: labelColumnWidth + height: childrenRect.height + + Cura.IconWithText + { + id: qualityRowTitle + source: UM.Theme.getIcon("category_layer_height") + text: catalog.i18nc("@label", "Layer Height") + font: UM.Theme.getFont("medium") + anchors.left: parent.left + anchors.right: customisedSettings.left + } + + UM.SimpleButton + { + id: customisedSettings + + visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.MachineManager.hasCustomQuality + height: visible ? UM.Theme.getSize("print_setup_icon").height : 0 + width: height + anchors + { + right: parent.right + rightMargin: UM.Theme.getSize("default_margin").width + leftMargin: UM.Theme.getSize("default_margin").width + verticalCenter: parent.verticalCenter + } + + color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button") + iconSource: UM.Theme.getIcon("reset") + + onClicked: + { + // if the current profile is user-created, switch to a built-in quality + Cura.MachineManager.resetToUseDefaultQuality() + } + onEntered: + { + var tooltipContent = catalog.i18nc("@tooltip","You have modified some profile settings. If you want to change these go to custom mode.") + base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, 0), tooltipContent) + } + onExited: base.hideTooltip() + } + } + + // Show titles for the each quality slider ticks + Item + { + anchors.left: speedSlider.left + anchors.top: speedSlider.bottom + height: childrenRect.height + + Repeater + { + model: qualityModel + + Label + { + anchors.verticalCenter: parent.verticalCenter + anchors.top: parent.top + // The height has to be set manually, otherwise it's not automatically calculated in the repeater + height: UM.Theme.getSize("default_margin").height + color: (Cura.MachineManager.activeMachine != null && Cura.QualityProfilesDropDownMenuModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") + text: + { + var result = "" + if(Cura.MachineManager.activeMachine != null) + { + result = Cura.QualityProfilesDropDownMenuModel.getItem(index).layer_height + + if(result == undefined) + { + result = ""; + } + else + { + result = Number(Math.round(result + "e+2") + "e-2"); //Round to 2 decimals. Javascript makes this difficult... + if (result == undefined || result != result) //Parse failure. + { + result = ""; + } + } + } + return result + } + + x: + { + // Make sure the text aligns correctly with each tick + if (qualityModel.totalTicks == 0) + { + // If there is only one tick, align it centrally + return Math.round(((settingsColumnWidth) - width) / 2) + } + else if (index == 0) + { + return Math.round(settingsColumnWidth / qualityModel.totalTicks) * index + } + else if (index == qualityModel.totalTicks) + { + return Math.round(settingsColumnWidth / qualityModel.totalTicks) * index - width + } + else + { + return Math.round((settingsColumnWidth / qualityModel.totalTicks) * index - (width / 2)) + } + } + font: UM.Theme.getFont("default") + } + } + } + + // Print speed slider + // Two sliders are created, one at the bottom with the unavailable qualities + // and the other at the top with the available quality profiles and so the handle to select them. + Item + { + id: speedSlider + height: childrenRect.height + + anchors + { + left: titleRow.right + right: parent.right + verticalCenter: titleRow.verticalCenter + } + + // Draw unavailable slider + Slider + { + id: unavailableSlider + + width: parent.width + height: qualitySlider.height // Same height as the slider that is on top + updateValueWhileDragging : false + tickmarksEnabled: true + + minimumValue: 0 + // maximumValue must be greater than minimumValue to be able to see the handle. While the value is strictly + // speaking not always correct, it seems to have the correct behavior (switching from 0 available to 1 available) + maximumValue: qualityModel.totalTicks + stepSize: 1 + + style: SliderStyle + { + //Draw Unvailable line + groove: Item + { + Rectangle + { + height: UM.Theme.getSize("print_setup_slider_groove").height + width: control.width - UM.Theme.getSize("print_setup_slider_handle").width + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + color: UM.Theme.getColor("quality_slider_unavailable") + } + } + + handle: Item {} + + tickmarks: Repeater + { + id: qualityRepeater + model: qualityModel.totalTicks > 0 ? qualityModel : 0 + + Rectangle + { + color: Cura.QualityProfilesDropDownMenuModel.getItem(index).available ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") + implicitWidth: UM.Theme.getSize("print_setup_slider_tickmarks").width + implicitHeight: UM.Theme.getSize("print_setup_slider_tickmarks").height + anchors.verticalCenter: parent.verticalCenter + + // Do not use Math.round otherwise the tickmarks won't be aligned + x: ((UM.Theme.getSize("print_setup_slider_handle").width / 2) - (implicitWidth / 2) + (qualityModel.qualitySliderStepWidth * index)) + radius: Math.round(implicitWidth / 2) + } + } + } + + // Create a mouse area on top of the unavailable profiles to show a specific tooltip + MouseArea + { + anchors.fill: parent + hoverEnabled: true + enabled: !Cura.MachineManager.hasCustomQuality + onEntered: + { + var tooltipContent = catalog.i18nc("@tooltip", "This quality profile is not available for your current material and nozzle configuration. Please change these to enable this quality profile") + base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), tooltipContent) + } + onExited: base.hideTooltip() + } + } + + // Draw available slider + Slider + { + id: qualitySlider + + width: qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks - 1) + UM.Theme.getSize("print_setup_slider_handle").width + height: UM.Theme.getSize("print_setup_slider_handle").height // The handle is the widest element of the slider + enabled: qualityModel.totalTicks > 0 && !Cura.SimpleModeSettingsManager.isProfileCustomized + visible: qualityModel.availableTotalTicks > 0 + updateValueWhileDragging : false + + anchors + { + right: parent.right + rightMargin: qualityModel.qualitySliderMarginRight + } + + minimumValue: qualityModel.qualitySliderAvailableMin >= 0 ? qualityModel.qualitySliderAvailableMin : 0 + // maximumValue must be greater than minimumValue to be able to see the handle. While the value is strictly + // speaking not always correct, it seems to have the correct behavior (switching from 0 available to 1 available) + maximumValue: qualityModel.qualitySliderAvailableMax >= 1 ? qualityModel.qualitySliderAvailableMax : 1 + stepSize: 1 + + value: qualityModel.qualitySliderActiveIndex + + style: SliderStyle + { + // Draw Available line + groove: Item + { + Rectangle + { + height: UM.Theme.getSize("print_setup_slider_groove").height + width: control.width - UM.Theme.getSize("print_setup_slider_handle").width + anchors.verticalCenter: parent.verticalCenter + + // Do not use Math.round otherwise the tickmarks won't be aligned + x: UM.Theme.getSize("print_setup_slider_handle").width / 2 + color: UM.Theme.getColor("quality_slider_available") + } + } + + handle: Rectangle + { + id: qualityhandleButton + color: UM.Theme.getColor("primary") + implicitWidth: UM.Theme.getSize("print_setup_slider_handle").width + implicitHeight: implicitWidth + radius: Math.round(implicitWidth / 2) + visible: !Cura.SimpleModeSettingsManager.isProfileCustomized && !Cura.MachineManager.hasCustomQuality && qualityModel.existingQualityProfile + } + } + + onValueChanged: + { + // only change if an active machine is set and the slider is visible at all. + if (Cura.MachineManager.activeMachine != null && visible) + { + // prevent updating during view initializing. Trigger only if the value changed by user + if (qualitySlider.value != qualityModel.qualitySliderActiveIndex && qualityModel.qualitySliderActiveIndex != -1) + { + // start updating with short delay + qualitySliderChangeTimer.start() + } + } + } + + // This mouse area is only used to capture the onHover state and don't propagate it to the unavailable mouse area + MouseArea + { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + enabled: !Cura.MachineManager.hasCustomQuality + } + } + + // This mouse area will only take the mouse events and show a tooltip when the profile in use is + // a user created profile + MouseArea + { + anchors.fill: parent + hoverEnabled: true + visible: Cura.MachineManager.hasCustomQuality + + onEntered: + { + var tooltipContent = catalog.i18nc("@tooltip", "A custom profile is currently active. To enable the quality slider, choose a default quality profile in Custom tab") + base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("thick_margin").width, customisedSettings.height), tooltipContent) + } + onExited: base.hideTooltip() + } + } +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedSupportSelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedSupportSelector.qml new file mode 100644 index 0000000000..0e834ac4df --- /dev/null +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedSupportSelector.qml @@ -0,0 +1,206 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + + +// +// Enable support +// +Item +{ + id: enableSupportRow + height: childrenRect.height + + property real labelColumnWidth: Math.round(width / 3) + + Cura.IconWithText + { + id: enableSupportRowTitle + anchors.top: parent.top + anchors.left: parent.left + visible: enableSupportCheckBox.visible + source: UM.Theme.getIcon("category_support") + text: catalog.i18nc("@label", "Support") + font: UM.Theme.getFont("medium") + width: labelColumnWidth + } + + Item + { + id: enableSupportContainer + height: enableSupportCheckBox.height + + anchors + { + left: enableSupportRowTitle.right + right: parent.right + verticalCenter: enableSupportRowTitle.verticalCenter + } + + CheckBox + { + id: enableSupportCheckBox + anchors.verticalCenter: parent.verticalCenter + + property alias _hovered: enableSupportMouseArea.containsMouse + + style: UM.Theme.styles.checkbox + enabled: recommendedPrintSetup.settingsEnabled + + visible: supportEnabled.properties.enabled == "True" + checked: supportEnabled.properties.value == "True" + + MouseArea + { + id: enableSupportMouseArea + anchors.fill: parent + hoverEnabled: true + + onClicked: supportEnabled.setPropertyValue("value", supportEnabled.properties.value != "True") + + onEntered: + { + base.showTooltip(enableSupportCheckBox, Qt.point(-enableSupportContainer.x - UM.Theme.getSize("thick_margin").width, 0), + catalog.i18nc("@label", "Generate structures to support parts of the model which have overhangs. Without these structures, such parts would collapse during printing.")) + } + onExited: base.hideTooltip() + } + } + + ComboBox + { + id: supportExtruderCombobox + + height: UM.Theme.getSize("print_setup_big_item").height + anchors + { + left: enableSupportCheckBox.right + right: parent.right + leftMargin: UM.Theme.getSize("thick_margin").width + rightMargin: UM.Theme.getSize("thick_margin").width + verticalCenter: parent.verticalCenter + } + + style: UM.Theme.styles.combobox_color + enabled: recommendedPrintSetup.settingsEnabled + visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1) + textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started + + model: extruderModel + + property alias _hovered: supportExtruderMouseArea.containsMouse + property string color_override: "" // for manually setting values + property string color: // is evaluated automatically, but the first time is before extruderModel being filled + { + var current_extruder = extruderModel.get(currentIndex) + color_override = "" + if (current_extruder === undefined) return "" + return (current_extruder.color) ? current_extruder.color : "" + } + + currentIndex: + { + if (supportExtruderNr.properties == null) + { + return Cura.MachineManager.defaultExtruderPosition + } + else + { + var extruder = parseInt(supportExtruderNr.properties.value) + if ( extruder === -1) + { + return Cura.MachineManager.defaultExtruderPosition + } + return extruder; + } + } + + onActivated: supportExtruderNr.setPropertyValue("value", String(index)) + + MouseArea + { + id: supportExtruderMouseArea + anchors.fill: parent + hoverEnabled: true + enabled: recommendedPrintSetup.settingsEnabled + acceptedButtons: Qt.NoButton + onEntered: + { + base.showTooltip(supportExtruderCombobox, Qt.point(-enableSupportContainer.x - supportExtruderCombobox.x - UM.Theme.getSize("thick_margin").width, 0), + catalog.i18nc("@label", "Select which extruder to use for support. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air.")); + } + onExited: base.hideTooltip() + + } + + function updateCurrentColor() + { + var current_extruder = extruderModel.get(currentIndex) + if (current_extruder !== undefined) + { + supportExtruderCombobox.color_override = current_extruder.color + } + } + } + } + + ListModel + { + id: extruderModel + Component.onCompleted: populateExtruderModel() + } + + //: Model used to populate the extrudelModel + property var extruders: CuraApplication.getExtrudersModel() + Connections + { + target: extruders + onModelChanged: populateExtruderModel() + } + + UM.SettingPropertyProvider + { + id: supportEnabled + containerStack: Cura.MachineManager.activeMachine + key: "support_enable" + watchedProperties: [ "value", "enabled", "description" ] + storeIndex: 0 + } + + UM.SettingPropertyProvider + { + id: supportExtruderNr + containerStack: Cura.MachineManager.activeMachine + key: "support_extruder_nr" + watchedProperties: [ "value" ] + storeIndex: 0 + } + + UM.SettingPropertyProvider + { + id: machineExtruderCount + containerStack: Cura.MachineManager.activeMachine + key: "machine_extruder_count" + watchedProperties: ["value"] + storeIndex: 0 + } + + function populateExtruderModel() + { + extruderModel.clear() + for (var extruderNumber = 0; extruderNumber < extruders.rowCount(); extruderNumber++) + { + extruderModel.append({ + text: extruders.getItem(extruderNumber).name, + color: extruders.getItem(extruderNumber).color + }) + } + supportExtruderCombobox.updateCurrentColor() + } +} \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedTroubleshootingGuides.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedTroubleshootingGuides.qml new file mode 100644 index 0000000000..846e343028 --- /dev/null +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedTroubleshootingGuides.qml @@ -0,0 +1,36 @@ +// Copyright (c) 2019 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.10 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import UM 1.2 as UM +import Cura 1.0 as Cura + + +Item +{ + id: tipsCell + anchors.top: adhesionCheckBox.visible ? adhesionCheckBox.bottom : (enableSupportCheckBox.visible ? supportExtruderCombobox.bottom : infillCellRight.bottom) + anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height * 2) + anchors.left: parent.left + width: parent.width + height: tipsText.contentHeight * tipsText.lineCount + + Label + { + id: tipsText + anchors.left: parent.left + anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width + anchors.right: parent.right + anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width + anchors.top: parent.top + wrapMode: Text.WordWrap + text: catalog.i18nc("@label", "Need help improving your prints?
Read the Ultimaker Troubleshooting Guides").arg("https://ultimaker.com/en/troubleshooting") + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + linkColor: UM.Theme.getColor("text_link") + onLinkActivated: Qt.openUrlExternally(link) + } +} \ No newline at end of file diff --git a/resources/qml/SidebarTooltip.qml b/resources/qml/PrintSetupTooltip.qml similarity index 87% rename from resources/qml/SidebarTooltip.qml rename to resources/qml/PrintSetupTooltip.qml index 29199481f6..6b1538d849 100644 --- a/resources/qml/SidebarTooltip.qml +++ b/resources/qml/PrintSetupTooltip.qml @@ -2,9 +2,7 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 -import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 import UM 1.0 as UM @@ -36,14 +34,15 @@ UM.PointingRectangle { } } base.opacity = 1; - target = Qt.point(40 , position.y + Math.round(UM.Theme.getSize("tooltip_arrow_margins").height / 2)) + target = Qt.point(position.x + 1, position.y + Math.round(UM.Theme.getSize("tooltip_arrow_margins").height / 2)) } function hide() { base.opacity = 0; } - Label { + Label + { id: label; anchors { top: parent.top; @@ -57,5 +56,6 @@ UM.PointingRectangle { textFormat: Text.RichText font: UM.Theme.getFont("default"); color: UM.Theme.getColor("tooltip_text"); + renderType: Text.NativeRendering } } diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index f0abd4cd6c..a19c02b0dd 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -12,8 +12,10 @@ Item property alias color: background.color property var extruderModel property var position: index + property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null + implicitWidth: parent.width - implicitHeight: UM.Theme.getSize("sidebar_extruder_box").height + implicitHeight: UM.Theme.getSize("print_setup_extruder_box").height UM.SettingPropertyProvider { @@ -45,7 +47,7 @@ Item { id: extruderTargetTemperature text: Math.round(extruderModel.targetHotendTemperature) + "°C" - font: UM.Theme.getFont("small") + font: UM.Theme.getFont("default_bold") color: UM.Theme.getColor("text_inactive") anchors.right: parent.right anchors.rightMargin: UM.Theme.getSize("default_margin").width @@ -78,7 +80,7 @@ Item id: extruderCurrentTemperature text: Math.round(extruderModel.hotendTemperature) + "°C" color: UM.Theme.getColor("text") - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") anchors.right: extruderTargetTemperature.left anchors.top: parent.top anchors.margins: UM.Theme.getSize("default_margin").width @@ -324,7 +326,7 @@ Item return UM.Theme.getColor("action_button_text"); } } - font: UM.Theme.getFont("action_button") + font: UM.Theme.getFont("medium") text: { if(extruderModel == null) diff --git a/resources/qml/PrinterOutput/HeatedBedBox.qml b/resources/qml/PrinterOutput/HeatedBedBox.qml index 9de66ad0be..77421c8aad 100644 --- a/resources/qml/PrinterOutput/HeatedBedBox.qml +++ b/resources/qml/PrinterOutput/HeatedBedBox.qml @@ -1,10 +1,10 @@ // Copyright (c) 2017 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 2.10 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 import UM 1.2 as UM import Cura 1.0 as Cura @@ -12,12 +12,13 @@ import Cura 1.0 as Cura Item { implicitWidth: parent.width - height: visible ? UM.Theme.getSize("sidebar_extruder_box").height : 0 + height: visible ? UM.Theme.getSize("print_setup_extruder_box").height : 0 property var printerModel + property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null Rectangle { - color: UM.Theme.getColor("sidebar") + color: UM.Theme.getColor("main_background") anchors.fill: parent Label //Build plate label. @@ -34,7 +35,7 @@ Item { id: bedTargetTemperature text: printerModel != null ? printerModel.targetBedTemperature + "°C" : "" - font: UM.Theme.getFont("small") + font: UM.Theme.getFont("default_bold") color: UM.Theme.getColor("text_inactive") anchors.right: parent.right anchors.rightMargin: UM.Theme.getSize("default_margin").width @@ -66,7 +67,7 @@ Item { id: bedCurrentTemperature text: printerModel != null ? printerModel.bedTemperature + "°C" : "" - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") anchors.right: bedTargetTemperature.left anchors.top: parent.top @@ -114,7 +115,7 @@ Item { return false; //Can't preheat if not connected. } - if (!connectedPrinter.acceptsCommands) + if (connectedPrinter == null || !connectedPrinter.acceptsCommands) { return false; //Not allowed to do anything. } @@ -319,7 +320,7 @@ Item return UM.Theme.getColor("action_button_text"); } } - font: UM.Theme.getFont("action_button") + font: UM.Theme.getFont("medium") text: { if(printerModel == null) diff --git a/resources/qml/PrinterOutput/ManualPrinterControl.qml b/resources/qml/PrinterOutput/ManualPrinterControl.qml index 70961a2eb2..106ae7db03 100644 --- a/resources/qml/PrinterOutput/ManualPrinterControl.qml +++ b/resources/qml/PrinterOutput/ManualPrinterControl.qml @@ -1,103 +1,26 @@ // Copyright (c) 2017 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 2.10 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 -import UM 1.2 as UM +import UM 1.3 as UM import Cura 1.0 as Cura +import "." + + Item { - property var printerModel + property var printerModel: null property var activePrintJob: printerModel != null ? printerModel.activePrintJob : null + property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null + implicitWidth: parent.width implicitHeight: childrenRect.height - Component - { - id: monitorButtonStyle - - ButtonStyle - { - background: Rectangle - { - border.width: UM.Theme.getSize("default_lining").width - border.color: - { - if(!control.enabled) - { - return UM.Theme.getColor("action_button_disabled_border"); - } - else if(control.pressed) - { - return UM.Theme.getColor("action_button_active_border"); - } - else if(control.hovered) - { - return UM.Theme.getColor("action_button_hovered_border"); - } - return UM.Theme.getColor("action_button_border"); - } - color: - { - if(!control.enabled) - { - return UM.Theme.getColor("action_button_disabled"); - } - else if(control.pressed) - { - return UM.Theme.getColor("action_button_active"); - } - else if(control.hovered) - { - return UM.Theme.getColor("action_button_hovered"); - } - return UM.Theme.getColor("action_button"); - } - Behavior on color - { - ColorAnimation - { - duration: 50 - } - } - } - - label: Item - { - UM.RecolorImage - { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - width: Math.floor(control.width / 2) - height: Math.floor(control.height / 2) - sourceSize.width: width - sourceSize.height: width - color: - { - if(!control.enabled) - { - return UM.Theme.getColor("action_button_disabled_text"); - } - else if(control.pressed) - { - return UM.Theme.getColor("action_button_active_text"); - } - else if(control.hovered) - { - return UM.Theme.getColor("action_button_hovered_text"); - } - return UM.Theme.getColor("action_button_text"); - } - source: control.iconSource - } - } - } - } - Column { enabled: @@ -180,7 +103,7 @@ Item Layout.preferredWidth: width Layout.preferredHeight: height iconSource: UM.Theme.getIcon("arrow_top"); - style: monitorButtonStyle + style: UM.Theme.styles.monitor_button_style width: height height: UM.Theme.getSize("setting_control").height @@ -197,7 +120,7 @@ Item Layout.preferredWidth: width Layout.preferredHeight: height iconSource: UM.Theme.getIcon("arrow_left"); - style: monitorButtonStyle + style: UM.Theme.styles.monitor_button_style width: height height: UM.Theme.getSize("setting_control").height @@ -214,7 +137,7 @@ Item Layout.preferredWidth: width Layout.preferredHeight: height iconSource: UM.Theme.getIcon("arrow_right"); - style: monitorButtonStyle + style: UM.Theme.styles.monitor_button_style width: height height: UM.Theme.getSize("setting_control").height @@ -231,7 +154,7 @@ Item Layout.preferredWidth: width Layout.preferredHeight: height iconSource: UM.Theme.getIcon("arrow_bottom"); - style: monitorButtonStyle + style: UM.Theme.styles.monitor_button_style width: height height: UM.Theme.getSize("setting_control").height @@ -248,7 +171,7 @@ Item Layout.preferredWidth: width Layout.preferredHeight: height iconSource: UM.Theme.getIcon("home"); - style: monitorButtonStyle + style: UM.Theme.styles.monitor_button_style width: height height: UM.Theme.getSize("setting_control").height @@ -278,7 +201,7 @@ Item Button { iconSource: UM.Theme.getIcon("arrow_top"); - style: monitorButtonStyle + style: UM.Theme.styles.monitor_button_style width: height height: UM.Theme.getSize("setting_control").height @@ -291,7 +214,7 @@ Item Button { iconSource: UM.Theme.getIcon("home"); - style: monitorButtonStyle + style: UM.Theme.styles.monitor_button_style width: height height: UM.Theme.getSize("setting_control").height @@ -304,7 +227,7 @@ Item Button { iconSource: UM.Theme.getIcon("arrow_bottom"); - style: monitorButtonStyle + style: UM.Theme.styles.monitor_button_style width: height height: UM.Theme.getSize("setting_control").height @@ -356,72 +279,7 @@ Item checked: distancesRow.currentDistance == model.value onClicked: distancesRow.currentDistance = model.value - style: ButtonStyle { - background: Rectangle { - border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width - border.color: - { - if(!control.enabled) - { - return UM.Theme.getColor("action_button_disabled_border"); - } - else if (control.checked || control.pressed) - { - return UM.Theme.getColor("action_button_active_border"); - } - else if(control.hovered) - { - return UM.Theme.getColor("action_button_hovered_border"); - } - return UM.Theme.getColor("action_button_border"); - } - color: - { - if(!control.enabled) - { - return UM.Theme.getColor("action_button_disabled"); - } - else if (control.checked || control.pressed) - { - return UM.Theme.getColor("action_button_active"); - } - else if (control.hovered) - { - return UM.Theme.getColor("action_button_hovered"); - } - return UM.Theme.getColor("action_button"); - } - Behavior on color { ColorAnimation { duration: 50; } } - Label { - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: UM.Theme.getSize("default_lining").width * 2 - anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2 - color: - { - if(!control.enabled) - { - return UM.Theme.getColor("action_button_disabled_text"); - } - else if (control.checked || control.pressed) - { - return UM.Theme.getColor("action_button_active_text"); - } - else if (control.hovered) - { - return UM.Theme.getColor("action_button_hovered_text"); - } - return UM.Theme.getColor("action_button_text"); - } - font: UM.Theme.getFont("default") - text: control.text - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideMiddle - } - } - label: Item { } - } + style: UM.Theme.styles.monitor_checkable_button_style } } } @@ -462,7 +320,7 @@ Item if (printerModel == null) { return false // Can't send custom commands if not connected. } - if (!connectedPrinter.acceptsCommands) { + if (connectedPrinter == null || !connectedPrinter.acceptsCommands) { return false // Not allowed to do anything } if (connectedPrinter.jobState == "printing" || connectedPrinter.jobState == "pre_print" || connectedPrinter.jobState == "resuming" || connectedPrinter.jobState == "pausing" || connectedPrinter.jobState == "paused" || connectedPrinter.jobState == "error" || connectedPrinter.jobState == "offline") { @@ -551,4 +409,4 @@ Item } ExclusiveGroup { id: distanceGroup } } -} \ No newline at end of file +} diff --git a/resources/qml/PrinterOutput/MonitorItem.qml b/resources/qml/PrinterOutput/MonitorItem.qml index cad8d2f7f3..a26ec20f64 100644 --- a/resources/qml/PrinterOutput/MonitorItem.qml +++ b/resources/qml/PrinterOutput/MonitorItem.qml @@ -15,6 +15,8 @@ Item property string value: "" height: childrenRect.height; + property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null + Row { height: UM.Theme.getSize("setting_control").height diff --git a/resources/qml/PrinterOutput/MonitorSection.qml b/resources/qml/PrinterOutput/MonitorSection.qml index 6ed762362d..1d9df777b6 100644 --- a/resources/qml/PrinterOutput/MonitorSection.qml +++ b/resources/qml/PrinterOutput/MonitorSection.qml @@ -1,10 +1,10 @@ // Copyright (c) 2017 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 2.10 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.3 import UM 1.2 as UM import Cura 1.0 as Cura @@ -13,7 +13,8 @@ Item { id: base property string label - height: childrenRect.height; + height: childrenRect.height + Rectangle { color: UM.Theme.getColor("setting_category") @@ -26,8 +27,8 @@ Item anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width text: label - font: UM.Theme.getFont("setting_category") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("setting_category_text") } } -} \ No newline at end of file +} diff --git a/resources/qml/PrinterOutput/OutputDeviceHeader.qml b/resources/qml/PrinterOutput/OutputDeviceHeader.qml index b5ed1b7b4e..47f855266b 100644 --- a/resources/qml/PrinterOutput/OutputDeviceHeader.qml +++ b/resources/qml/PrinterOutput/OutputDeviceHeader.qml @@ -31,7 +31,7 @@ Item Label { id: outputDeviceNameLabel - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") anchors.left: parent.left anchors.top: parent.top @@ -43,10 +43,10 @@ Item { id: outputDeviceAddressLabel text: (outputDevice != null && outputDevice.address != null) ? outputDevice.address : "" - font: UM.Theme.getFont("small") + font: UM.Theme.getFont("default_bold") color: UM.Theme.getColor("text_inactive") - anchors.top: parent.top - anchors.right: parent.right + anchors.top: outputDeviceNameLabel.bottom + anchors.left: parent.left anchors.margins: UM.Theme.getSize("default_margin").width } @@ -54,7 +54,7 @@ Item { text: outputDevice != null ? "" : catalog.i18nc("@info:status", "The printer is not connected.") color: outputDevice != null && outputDevice.acceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text") - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("default") wrapMode: Text.WordWrap anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_margin").width diff --git a/resources/qml/PrinterSelector/MachineSelector.qml b/resources/qml/PrinterSelector/MachineSelector.qml new file mode 100644 index 0000000000..cd5e041606 --- /dev/null +++ b/resources/qml/PrinterSelector/MachineSelector.qml @@ -0,0 +1,182 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Cura.ExpandablePopup +{ + id: machineSelector + + property bool isNetworkPrinter: Cura.MachineManager.activeMachineHasActiveNetworkConnection + property bool isCloudPrinter: Cura.MachineManager.activeMachineHasActiveCloudConnection + property bool isGroup: Cura.MachineManager.activeMachineIsGroup + + contentPadding: UM.Theme.getSize("default_lining").width + contentAlignment: Cura.ExpandablePopup.ContentAlignment.AlignLeft + + UM.I18nCatalog + { + id: catalog + name: "cura" + } + + headerItem: Cura.IconWithText + { + text: + { + if (isNetworkPrinter && Cura.MachineManager.activeMachineNetworkGroupName != "") + { + return Cura.MachineManager.activeMachineNetworkGroupName + } + return Cura.MachineManager.activeMachineName + } + source: + { + if (isGroup) + { + return UM.Theme.getIcon("printer_group") + } + else if (isNetworkPrinter || isCloudPrinter) + { + return UM.Theme.getIcon("printer_single") + } + else + { + return "" + } + } + font: UM.Theme.getFont("medium") + iconColor: UM.Theme.getColor("machine_selector_printer_icon") + iconSize: source != "" ? UM.Theme.getSize("machine_selector_icon").width: 0 + + UM.RecolorImage + { + anchors + { + bottom: parent.bottom + left: parent.left + leftMargin: UM.Theme.getSize("thick_margin").width + } + + source: + { + if (isNetworkPrinter) + { + return UM.Theme.getIcon("printer_connected") + } + else if (isCloudPrinter) + { + return UM.Theme.getIcon("printer_cloud_connected") + } + else + { + return "" + } + } + + width: UM.Theme.getSize("printer_status_icon").width + height: UM.Theme.getSize("printer_status_icon").height + + color: UM.Theme.getColor("primary") + visible: isNetworkPrinter || isCloudPrinter + + // Make a themable circle in the background so we can change it in other themes + Rectangle + { + id: iconBackground + anchors.centerIn: parent + // Make it a bit bigger so there is an outline + width: parent.width + 2 * UM.Theme.getSize("default_lining").width + height: parent.height + 2 * UM.Theme.getSize("default_lining").height + radius: Math.round(width / 2) + color: UM.Theme.getColor("main_background") + z: parent.z - 1 + } + } + } + + contentItem: Item + { + id: popup + width: UM.Theme.getSize("machine_selector_widget_content").width + + ScrollView + { + id: scroll + width: parent.width + clip: true + leftPadding: UM.Theme.getSize("default_lining").width + rightPadding: UM.Theme.getSize("default_lining").width + + MachineSelectorList + { + // Can't use parent.width since the parent is the flickable component and not the ScrollView + width: scroll.width - scroll.leftPadding - scroll.rightPadding + property real maximumHeight: UM.Theme.getSize("machine_selector_widget_content").height - buttonRow.height + + // We use an extra property here, since we only want to to be informed about the content size changes. + onContentHeightChanged: + { + scroll.height = Math.min(contentHeight, maximumHeight) + popup.height = scroll.height + buttonRow.height + } + + Component.onCompleted: + { + scroll.height = Math.min(contentHeight, maximumHeight) + popup.height = scroll.height + buttonRow.height + } + + } + } + + Rectangle + { + id: separator + + anchors.top: scroll.bottom + width: parent.width + height: UM.Theme.getSize("default_lining").height + color: UM.Theme.getColor("lining") + } + + Row + { + id: buttonRow + + // The separator is inside the buttonRow. This is to avoid some weird behaviours with the scroll bar. + anchors.top: separator.top + anchors.horizontalCenter: parent.horizontalCenter + padding: UM.Theme.getSize("default_margin").width + spacing: UM.Theme.getSize("default_margin").width + + Cura.SecondaryButton + { + leftPadding: UM.Theme.getSize("default_margin").width + rightPadding: UM.Theme.getSize("default_margin").width + text: catalog.i18nc("@button", "Add printer") + onClicked: + { + toggleContent() + Cura.Actions.addMachine.trigger() + } + } + + Cura.SecondaryButton + { + leftPadding: UM.Theme.getSize("default_margin").width + rightPadding: UM.Theme.getSize("default_margin").width + text: catalog.i18nc("@button", "Manage printers") + onClicked: + { + toggleContent() + Cura.Actions.configureMachines.trigger() + } + } + } + } +} diff --git a/resources/qml/PrinterSelector/MachineSelectorButton.qml b/resources/qml/PrinterSelector/MachineSelectorButton.qml new file mode 100644 index 0000000000..39e63d27c3 --- /dev/null +++ b/resources/qml/PrinterSelector/MachineSelectorButton.qml @@ -0,0 +1,103 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 + +import UM 1.1 as UM +import Cura 1.0 as Cura + +Button +{ + id: machineSelectorButton + + width: parent.width + height: UM.Theme.getSize("action_button").height + leftPadding: UM.Theme.getSize("thick_margin").width + rightPadding: UM.Theme.getSize("thick_margin").width + checkable: true + hoverEnabled: true + + property var outputDevice: null + property var printerTypesList: [] + + function updatePrinterTypesList() + { + printerTypesList = (checked && (outputDevice != null)) ? outputDevice.uniquePrinterTypes : [] + } + + contentItem: Item + { + width: machineSelectorButton.width - machineSelectorButton.leftPadding + height: UM.Theme.getSize("action_button").height + + Label + { + id: buttonText + anchors + { + left: parent.left + right: printerTypes.left + verticalCenter: parent.verticalCenter + } + text: machineSelectorButton.text + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("medium") + visible: text != "" + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + Row + { + id: printerTypes + width: childrenRect.width + + anchors + { + right: parent.right + verticalCenter: parent.verticalCenter + } + spacing: UM.Theme.getSize("narrow_margin").width + + Repeater + { + model: printerTypesList + delegate: Cura.PrinterTypeLabel + { + text: Cura.MachineManager.getAbbreviatedMachineName(modelData) + } + } + } + } + + background: Rectangle + { + id: backgroundRect + color: machineSelectorButton.hovered ? UM.Theme.getColor("action_button_hovered") : "transparent" + radius: UM.Theme.getSize("action_button_radius").width + border.width: UM.Theme.getSize("default_lining").width + border.color: machineSelectorButton.checked ? UM.Theme.getColor("primary") : "transparent" + } + + onClicked: + { + toggleContent() + Cura.MachineManager.setActiveMachine(model.id) + } + + Connections + { + target: outputDevice + onUniqueConfigurationsChanged: updatePrinterTypesList() + } + + Connections + { + target: Cura.MachineManager + onOutputDevicesChanged: updatePrinterTypesList() + } + + Component.onCompleted: updatePrinterTypesList() +} diff --git a/resources/qml/PrinterSelector/MachineSelectorList.qml b/resources/qml/PrinterSelector/MachineSelectorList.qml new file mode 100644 index 0000000000..5fd3515cd3 --- /dev/null +++ b/resources/qml/PrinterSelector/MachineSelectorList.qml @@ -0,0 +1,46 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +ListView +{ + id: listView + model: Cura.GlobalStacksModel {} + section.property: "hasRemoteConnection" + property real contentHeight: childrenRect.height + + section.delegate: Label + { + text: section == "true" ? catalog.i18nc("@label", "Connected printers") : catalog.i18nc("@label", "Preset printers") + width: parent.width + height: UM.Theme.getSize("action_button").height + leftPadding: UM.Theme.getSize("default_margin").width + renderType: Text.NativeRendering + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text_medium") + verticalAlignment: Text.AlignVCenter + } + + delegate: MachineSelectorButton + { + text: model.name + width: listView.width + outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null + + checked: + { + // If the machine has a remote connection + var result = Cura.MachineManager.activeMachineId == model.id + if (Cura.MachineManager.activeMachineHasRemoteConnection) + { + result |= Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"] + } + return result + } + } +} diff --git a/resources/qml/PrinterTypeLabel.qml b/resources/qml/PrinterTypeLabel.qml new file mode 100644 index 0000000000..cfc9e56513 --- /dev/null +++ b/resources/qml/PrinterTypeLabel.qml @@ -0,0 +1,35 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.1 + +import UM 1.1 as UM + +// This component creates a label with the abbreviated name of a printer, with a rectangle surrounding the label. +// It is created in a separated place in order to be reused whenever needed. +Item +{ + property alias text: printerTypeLabel.text + + width: UM.Theme.getSize("printer_type_label").width + height: UM.Theme.getSize("printer_type_label").height + + Rectangle + { + anchors.fill: parent + color: UM.Theme.getColor("printer_type_label_background") + radius: UM.Theme.getSize("checkbox_radius").width + } + + Label + { + id: printerTypeLabel + text: "CFFFP" // As an abbreviated name of the Custom FFF Printer + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + renderType: Text.NativeRendering + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + } +} \ No newline at end of file diff --git a/resources/qml/RoundedRectangle.qml b/resources/qml/RoundedRectangle.qml new file mode 100644 index 0000000000..3ca05e2125 --- /dev/null +++ b/resources/qml/RoundedRectangle.qml @@ -0,0 +1,72 @@ +import QtQuick 2.7 + +import UM 1.2 as UM + +// The rounded rectangle works mostly like a regular rectangle, but provides the option to have rounded corners on only one side of the rectangle. +Item +{ + id: roundedRectangle + // As per the regular rectangle + property color color: "transparent" + + // As per regular rectangle + property int radius: UM.Theme.getSize("default_radius").width + + // On what side should the corners be shown 5 can be used if no radius is needed. + // 1 is down, 2 is left, 3 is up and 4 is right. + property int cornerSide: RoundedRectangle.Direction.None + + // Simple object to ensure that border.width and border.color work + property BorderGroup border: BorderGroup {} + + enum Direction + { + None = 0, + Down = 1, + Left = 2, + Up = 3, + Right = 4, + All = 5 + } + + Rectangle + { + id: background + anchors.fill: parent + radius: cornerSide != RoundedRectangle.Direction.None ? parent.radius : 0 + color: parent.color + border.width: parent.border.width + border.color: parent.border.color + } + + // The item that covers 2 of the corners to make them not rounded. + Rectangle + { + visible: cornerSide != RoundedRectangle.Direction.None && cornerSide != RoundedRectangle.Direction.All + height: cornerSide % 2 ? parent.radius: parent.height + width: cornerSide % 2 ? parent.width : parent.radius + color: parent.color + anchors + { + right: cornerSide == RoundedRectangle.Direction.Left ? parent.right: undefined + bottom: cornerSide == RoundedRectangle.Direction.Up ? parent.bottom: undefined + } + + border.width: parent.border.width + border.color: parent.border.color + + Rectangle + { + color: roundedRectangle.color + height: cornerSide % 2 ? roundedRectangle.border.width: roundedRectangle.height - 2 * roundedRectangle.border.width + width: cornerSide % 2 ? roundedRectangle.width - 2 * roundedRectangle.border.width: roundedRectangle.border.width + anchors + { + right: cornerSide == RoundedRectangle.Direction.Right ? parent.right : undefined + bottom: cornerSide == RoundedRectangle.Direction.Down ? parent.bottom: undefined + horizontalCenter: cornerSide % 2 ? parent.horizontalCenter: undefined + verticalCenter: cornerSide % 2 ? undefined: parent.verticalCenter + } + } + } +} diff --git a/resources/qml/SaveButton.qml b/resources/qml/SaveButton.qml deleted file mode 100644 index 2a0a523026..0000000000 --- a/resources/qml/SaveButton.qml +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 -import QtQuick.Layouts 1.1 - -import UM 1.1 as UM -import Cura 1.0 as Cura - -Item { - id: base; - UM.I18nCatalog { id: catalog; name:"cura"} - - property real progress: UM.Backend.progress - property int backendState: UM.Backend.state - property bool activity: CuraApplication.platformActivity - - property alias buttonRowWidth: saveRow.width - - property string fileBaseName - property string statusText: - { - if(!activity) - { - return catalog.i18nc("@label:PrintjobStatus", "Please load a 3D model"); - } - - if (base.backendState == "undefined") { - return "" - } - - switch(base.backendState) - { - case 1: - return catalog.i18nc("@label:PrintjobStatus", "Ready to slice"); - case 2: - return catalog.i18nc("@label:PrintjobStatus", "Slicing..."); - case 3: - return catalog.i18nc("@label:PrintjobStatus %1 is target operation","Ready to %1").arg(UM.OutputDeviceManager.activeDeviceShortDescription); - case 4: - return catalog.i18nc("@label:PrintjobStatus", "Unable to Slice"); - case 5: - return catalog.i18nc("@label:PrintjobStatus", "Slicing unavailable"); - default: - return ""; - } - } - - function sliceOrStopSlicing() { - try { - if ([1, 5].indexOf(base.backendState) != -1) { - CuraApplication.backend.forceSlice(); - } else { - CuraApplication.backend.stopSlicing(); - } - } catch (e) { - console.log('Could not start or stop slicing', e) - } - } - - Label { - id: statusLabel - width: parent.width - 2 * UM.Theme.getSize("sidebar_margin").width - anchors.top: parent.top - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - - color: UM.Theme.getColor("text") - font: UM.Theme.getFont("default_bold") - text: statusText; - } - - Rectangle { - id: progressBar - width: parent.width - 2 * UM.Theme.getSize("sidebar_margin").width - height: UM.Theme.getSize("progressbar").height - anchors.top: statusLabel.bottom - anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height / 4) - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - radius: UM.Theme.getSize("progressbar_radius").width - color: UM.Theme.getColor("progressbar_background") - - Rectangle { - width: Math.max(parent.width * base.progress) - height: parent.height - color: UM.Theme.getColor("progressbar_control") - radius: UM.Theme.getSize("progressbar_radius").width - visible: (base.backendState != "undefined" && base.backendState == 2) ? true : false - } - } - - // Shortcut for "save as/print/..." - Action { - shortcut: "Ctrl+P" - onTriggered: - { - // only work when the button is enabled - if (saveToButton.enabled) { - saveToButton.clicked(); - } - // prepare button - if (prepareButton.enabled) { - sliceOrStopSlicing(); - } - } - } - - Item { - id: saveRow - width: { - // using childrenRect.width directly causes a binding loop, because setting the width affects the childrenRect - var children_width = UM.Theme.getSize("default_margin").width; - for (var index in children) - { - var child = children[index]; - if(child.visible) - { - children_width += child.width + child.anchors.rightMargin; - } - } - return Math.min(children_width, base.width - UM.Theme.getSize("sidebar_margin").width); - } - height: saveToButton.height - anchors.bottom: parent.bottom - anchors.bottomMargin: UM.Theme.getSize("sidebar_margin").height - anchors.right: parent.right - clip: true - - Row { - id: additionalComponentsRow - anchors.top: parent.top - anchors.right: saveToButton.visible ? saveToButton.left : (prepareButton.visible ? prepareButton.left : parent.right) - anchors.rightMargin: UM.Theme.getSize("default_margin").width - - spacing: UM.Theme.getSize("default_margin").width - } - - Component.onCompleted: { - saveRow.addAdditionalComponents("saveButton") - } - - Connections { - target: CuraApplication - onAdditionalComponentsChanged: saveRow.addAdditionalComponents("saveButton") - } - - function addAdditionalComponents (areaId) { - if(areaId == "saveButton") { - for (var component in CuraApplication.additionalComponents["saveButton"]) { - CuraApplication.additionalComponents["saveButton"][component].parent = additionalComponentsRow - } - } - } - - Connections { - target: UM.Preferences - onPreferenceChanged: - { - var autoSlice = UM.Preferences.getValue("general/auto_slice"); - prepareButton.autoSlice = autoSlice; - saveToButton.autoSlice = autoSlice; - } - } - - // Prepare button, only shows if auto_slice is off - Button { - id: prepareButton - - tooltip: [1, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@info:tooltip","Slice current printjob") : catalog.i18nc("@info:tooltip","Cancel slicing process") - // 1 = not started, 2 = Processing - enabled: base.backendState != "undefined" && ([1, 2].indexOf(base.backendState) != -1) && base.activity - visible: base.backendState != "undefined" && !autoSlice && ([1, 2, 4].indexOf(base.backendState) != -1) && base.activity - property bool autoSlice - height: UM.Theme.getSize("save_button_save_to_button").height - - anchors.top: parent.top - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - - // 1 = not started, 4 = error, 5 = disabled - text: [1, 4, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@label:Printjob", "Prepare") : catalog.i18nc("@label:Printjob", "Cancel") - onClicked: - { - sliceOrStopSlicing(); - } - - style: ButtonStyle { - background: Rectangle - { - border.width: UM.Theme.getSize("default_lining").width - border.color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled_border"); - else if(control.pressed) - return UM.Theme.getColor("action_button_active_border"); - else if(control.hovered) - return UM.Theme.getColor("action_button_hovered_border"); - else - return UM.Theme.getColor("action_button_border"); - } - color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled"); - else if(control.pressed) - return UM.Theme.getColor("action_button_active"); - else if(control.hovered) - return UM.Theme.getColor("action_button_hovered"); - else - return UM.Theme.getColor("action_button"); - } - - Behavior on color { ColorAnimation { duration: 50; } } - - implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("sidebar_margin").width * 2) - - Label { - id: actualLabel - anchors.centerIn: parent - color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled_text"); - else if(control.pressed) - return UM.Theme.getColor("action_button_active_text"); - else if(control.hovered) - return UM.Theme.getColor("action_button_hovered_text"); - else - return UM.Theme.getColor("action_button_text"); - } - font: UM.Theme.getFont("action_button") - text: control.text; - } - } - label: Item { } - } - } - - Button { - id: saveToButton - - tooltip: UM.OutputDeviceManager.activeDeviceDescription; - // 3 = done, 5 = disabled - enabled: base.backendState != "undefined" && (base.backendState == 3 || base.backendState == 5) && base.activity == true - visible: base.backendState != "undefined" && autoSlice || ((base.backendState == 3 || base.backendState == 5) && base.activity == true) - property bool autoSlice - height: UM.Theme.getSize("save_button_save_to_button").height - - anchors.top: parent.top - anchors.right: deviceSelectionMenu.visible ? deviceSelectionMenu.left : parent.right - anchors.rightMargin: deviceSelectionMenu.visible ? -3 * UM.Theme.getSize("default_lining").width : UM.Theme.getSize("sidebar_margin").width - - text: UM.OutputDeviceManager.activeDeviceShortDescription - onClicked: - { - forceActiveFocus(); - UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName, - { "filter_by_machine": true, "preferred_mimetypes": Cura.MachineManager.activeMachine.preferred_output_file_formats }); - } - - style: ButtonStyle { - background: Rectangle - { - border.width: UM.Theme.getSize("default_lining").width - border.color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled_border"); - else if(control.pressed) - return UM.Theme.getColor("print_button_ready_pressed_border"); - else if(control.hovered) - return UM.Theme.getColor("print_button_ready_hovered_border"); - else - return UM.Theme.getColor("print_button_ready_border"); - } - color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled"); - else if(control.pressed) - return UM.Theme.getColor("print_button_ready_pressed"); - else if(control.hovered) - return UM.Theme.getColor("print_button_ready_hovered"); - else - return UM.Theme.getColor("print_button_ready"); - } - - Behavior on color { ColorAnimation { duration: 50; } } - - implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("sidebar_margin").width * 2) - - Label { - id: actualLabel - anchors.centerIn: parent - color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled_text"); - else if(control.pressed) - return UM.Theme.getColor("print_button_ready_text"); - else if(control.hovered) - return UM.Theme.getColor("print_button_ready_text"); - else - return UM.Theme.getColor("print_button_ready_text"); - } - font: UM.Theme.getFont("action_button") - text: control.text; - } - } - label: Item { } - } - } - - Button { - id: deviceSelectionMenu - tooltip: catalog.i18nc("@info:tooltip","Select the active output device"); - anchors.top: parent.top - anchors.right: parent.right - - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - width: UM.Theme.getSize("save_button_save_to_button").height - height: UM.Theme.getSize("save_button_save_to_button").height - // 3 = Done, 5 = Disabled - enabled: base.backendState != "undefined" && (base.backendState == 3 || base.backendState == 5) && base.activity == true - visible: base.backendState != "undefined" && (devicesModel.deviceCount > 1) && (base.backendState == 3 || base.backendState == 5) && base.activity == true - - - style: ButtonStyle { - background: Rectangle { - id: deviceSelectionIcon - border.width: UM.Theme.getSize("default_lining").width - border.color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled_border"); - else if(control.pressed) - return UM.Theme.getColor("print_button_ready_pressed_border"); - else if(control.hovered) - return UM.Theme.getColor("print_button_ready_hovered_border"); - else - return UM.Theme.getColor("print_button_ready_border"); - } - color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled"); - else if(control.pressed) - return UM.Theme.getColor("print_button_ready_pressed"); - else if(control.hovered) - return UM.Theme.getColor("print_button_ready_hovered"); - else - return UM.Theme.getColor("print_button_ready"); - } - Behavior on color { ColorAnimation { duration: 50; } } - anchors.left: parent.left - anchors.leftMargin: Math.round(UM.Theme.getSize("save_button_text_margin").width / 2); - width: parent.height - height: parent.height - - UM.RecolorImage { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: height - color: - { - if(!control.enabled) - return UM.Theme.getColor("action_button_disabled_text"); - else if(control.pressed) - return UM.Theme.getColor("print_button_ready_text"); - else if(control.hovered) - return UM.Theme.getColor("print_button_ready_text"); - else - return UM.Theme.getColor("print_button_ready_text"); - } - source: UM.Theme.getIcon("arrow_bottom"); - } - } - label: Label{ } - } - - menu: Menu { - id: devicesMenu; - Instantiator { - model: devicesModel; - MenuItem { - text: model.description - checkable: true; - checked: model.id == UM.OutputDeviceManager.activeDevice; - exclusiveGroup: devicesMenuGroup; - onTriggered: { - UM.OutputDeviceManager.setActiveDevice(model.id); - } - } - onObjectAdded: devicesMenu.insertItem(index, object) - onObjectRemoved: devicesMenu.removeItem(object) - } - ExclusiveGroup { id: devicesMenuGroup; } - } - } - UM.OutputDevicesModel { id: devicesModel; } - } -} diff --git a/resources/qml/SecondaryButton.qml b/resources/qml/SecondaryButton.qml new file mode 100644 index 0000000000..f03d8acdfa --- /dev/null +++ b/resources/qml/SecondaryButton.qml @@ -0,0 +1,20 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 + +import UM 1.4 as UM +import Cura 1.1 as Cura + + +Cura.ActionButton +{ + shadowEnabled: true + shadowColor: enabled ? UM.Theme.getColor("secondary_button_shadow"): UM.Theme.getColor("action_button_disabled_shadow") + color: UM.Theme.getColor("secondary_button") + textColor: UM.Theme.getColor("secondary_button_text") + outlineColor: "transparent" + disabledColor: UM.Theme.getColor("action_button_disabled") + textDisabledColor: UM.Theme.getColor("action_button_disabled_text") + hoverColor: UM.Theme.getColor("secondary_button_hover") +} \ No newline at end of file diff --git a/resources/qml/Settings/SettingCategory.qml b/resources/qml/Settings/SettingCategory.qml index e3202323eb..1e88867889 100644 --- a/resources/qml/Settings/SettingCategory.qml +++ b/resources/qml/Settings/SettingCategory.qml @@ -12,48 +12,39 @@ Button id: base anchors.left: parent.left anchors.right: parent.right - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width + // To avoid overlaping with the scrollBars + anchors.rightMargin: 2 * UM.Theme.getSize("thin_margin").width + hoverEnabled: true + background: Rectangle { id: backgroundRectangle implicitHeight: UM.Theme.getSize("section").height - color: { - if (base.color) { - return base.color; - } else if (!base.enabled) { - return UM.Theme.getColor("setting_category_disabled"); - } else if (base.hovered && base.checkable && base.checked) { - return UM.Theme.getColor("setting_category_active_hover"); - } else if (base.pressed || (base.checkable && base.checked)) { - return UM.Theme.getColor("setting_category_active"); - } else if (base.hovered) { - return UM.Theme.getColor("setting_category_hover"); - } else { - return UM.Theme.getColor("setting_category"); + color: + { + if (base.color) + { + return base.color } + else if (!base.enabled) + { + return UM.Theme.getColor("setting_category_disabled") + } + else if (base.hovered && base.checkable && base.checked) + { + return UM.Theme.getColor("setting_category_active_hover") + } + else if (base.pressed || (base.checkable && base.checked)) + { + return UM.Theme.getColor("setting_category_active") + } + else if (base.hovered) + { + return UM.Theme.getColor("setting_category_hover") + } + return UM.Theme.getColor("setting_category") } Behavior on color { ColorAnimation { duration: 50; } } - Rectangle - { - id: backgroundLiningRectangle - height: UM.Theme.getSize("default_lining").height - width: parent.width - anchors.bottom: parent.bottom - color: { - if (!base.enabled) { - return UM.Theme.getColor("setting_category_disabled_border"); - } else if ((base.hovered || base.activeFocus) && base.checkable && base.checked) { - return UM.Theme.getColor("setting_category_active_hover_border"); - } else if (base.pressed || (base.checkable && base.checked)) { - return UM.Theme.getColor("setting_category_active_border"); - } else if (base.hovered || base.activeFocus) { - return UM.Theme.getColor("setting_category_hover_border"); - } else { - return UM.Theme.getColor("setting_category_border"); - } - } - } } signal showTooltip(string text) @@ -65,40 +56,47 @@ Button property var focusItem: base - contentItem: Item { + contentItem: Item + { anchors.fill: parent - anchors.left: parent.left - Label { + Label + { id: settingNameLabel anchors { left: parent.left leftMargin: 2 * UM.Theme.getSize("default_margin").width + UM.Theme.getSize("section_icon").width - right: parent.right; - verticalCenter: parent.verticalCenter; + right: parent.right + verticalCenter: parent.verticalCenter } text: definition.label textFormat: Text.PlainText renderType: Text.NativeRendering - font: UM.Theme.getFont("setting_category") + font: UM.Theme.getFont("medium_bold") color: { - if (!base.enabled) { - return UM.Theme.getColor("setting_category_disabled_text"); - } else if ((base.hovered || base.activeFocus) && base.checkable && base.checked) { - return UM.Theme.getColor("setting_category_active_hover_text"); - } else if (base.pressed || (base.checkable && base.checked)) { - return UM.Theme.getColor("setting_category_active_text"); - } else if (base.hovered || base.activeFocus) { - return UM.Theme.getColor("setting_category_hover_text"); - } else { - return UM.Theme.getColor("setting_category_text"); + if (!base.enabled) + { + return UM.Theme.getColor("setting_category_disabled_text") + } else if ((base.hovered || base.activeFocus) && base.checkable && base.checked) + { + return UM.Theme.getColor("setting_category_active_hover_text") + } else if (base.pressed || (base.checkable && base.checked)) + { + return UM.Theme.getColor("setting_category_active_text") + } else if (base.hovered || base.activeFocus) + { + return UM.Theme.getColor("setting_category_hover_text") + } else + { + return UM.Theme.getColor("setting_category_text") } } fontSizeMode: Text.HorizontalFit minimumPointSize: 8 } + UM.RecolorImage { id: category_arrow @@ -107,22 +105,8 @@ Button anchors.rightMargin: UM.Theme.getSize("default_margin").width width: UM.Theme.getSize("standard_arrow").width height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width sourceSize.height: width - color: - { - if (!base.enabled) { - return UM.Theme.getColor("setting_category_disabled_text"); - } else if ((base.hovered || base.activeFocus) && base.checkable && base.checked) { - return UM.Theme.getColor("setting_category_active_hover_text"); - } else if (base.pressed || (base.checkable && base.checked)) { - return UM.Theme.getColor("setting_category_active_text"); - } else if (base.hovered || base.activeFocus) { - return UM.Theme.getColor("setting_category_hover_text"); - } else { - return UM.Theme.getColor("setting_category_text"); - } - } + color: UM.Theme.getColor("setting_control_button") source: base.checked ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left") } } @@ -132,24 +116,30 @@ Button id: icon anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.leftMargin: UM.Theme.getSize("thin_margin").width color: { - if (!base.enabled) { - return UM.Theme.getColor("setting_category_disabled_text"); - } else if((base.hovered || base.activeFocus) && base.checkable && base.checked) { - return UM.Theme.getColor("setting_category_active_hover_text"); - } else if(base.pressed || (base.checkable && base.checked)) { - return UM.Theme.getColor("setting_category_active_text"); - } else if(base.hovered || base.activeFocus) { - return UM.Theme.getColor("setting_category_hover_text"); - } else { - return UM.Theme.getColor("setting_category_text"); + if (!base.enabled) + { + return UM.Theme.getColor("setting_category_disabled_text") } + else if((base.hovered || base.activeFocus) && base.checkable && base.checked) + { + return UM.Theme.getColor("setting_category_active_hover_text") + } + else if(base.pressed || (base.checkable && base.checked)) + { + return UM.Theme.getColor("setting_category_active_text") + } + else if(base.hovered || base.activeFocus) + { + return UM.Theme.getColor("setting_category_hover_text") + } + return UM.Theme.getColor("setting_category_text") } source: UM.Theme.getIcon(definition.icon) - width: UM.Theme.getSize("section_icon").width; - height: UM.Theme.getSize("section_icon").height; + width: UM.Theme.getSize("section_icon").width + height: UM.Theme.getSize("section_icon").height sourceSize.width: width + 15 * screenScaleFactor sourceSize.height: width + 15 * screenScaleFactor } @@ -159,31 +149,28 @@ Button onClicked: { - if (definition.expanded) { - settingDefinitionsModel.collapse(definition.key); - } else { - settingDefinitionsModel.expandRecursive(definition.key); + if (definition.expanded) + { + settingDefinitionsModel.collapse(definition.key) + } + else + { + settingDefinitionsModel.expandRecursive(definition.key) } //Set focus so that tab navigation continues from this point on. //NB: This must be set AFTER collapsing/expanding the category so that the scroll position is correct. - forceActiveFocus(); + forceActiveFocus() } onActiveFocusChanged: { - if(activeFocus) + if (activeFocus) { - base.focusReceived(); + base.focusReceived() } } - Keys.onTabPressed: - { - base.setActiveFocusToNextSetting(true) - } - Keys.onBacktabPressed: - { - base.setActiveFocusToNextSetting(false) - } + Keys.onTabPressed: base.setActiveFocusToNextSetting(true) + Keys.onBacktabPressed: base.setActiveFocusToNextSetting(false) UM.SimpleButton { @@ -193,9 +180,10 @@ Button height: Math.round(base.height * 0.6) width: Math.round(base.height * 0.6) - anchors { + anchors + { right: inheritButton.visible ? inheritButton.left : parent.right - // use 1.9 as the factor because there is a 0.1 difference between the settings and inheritance warning icons + // Use 1.9 as the factor because there is a 0.1 difference between the settings and inheritance warning icons rightMargin: inheritButton.visible ? Math.round(UM.Theme.getSize("default_margin").width / 2) : category_arrow.width + Math.round(UM.Theme.getSize("default_margin").width * 1.9) verticalCenter: parent.verticalCenter } @@ -204,9 +192,7 @@ Button hoverColor: UM.Theme.getColor("setting_control_button_hover") iconSource: UM.Theme.getIcon("settings") - onClicked: { - Cura.Actions.configureSettingVisibility.trigger(definition) - } + onClicked: Cura.Actions.configureSettingVisibility.trigger(definition) } UM.SimpleButton @@ -239,24 +225,18 @@ Button onClicked: { - settingDefinitionsModel.expandRecursive(definition.key); - base.checked = true; - base.showAllHiddenInheritedSettings(definition.key); + settingDefinitionsModel.expandRecursive(definition.key) + base.checked = true + base.showAllHiddenInheritedSettings(definition.key) } color: UM.Theme.getColor("setting_control_button") hoverColor: UM.Theme.getColor("setting_control_button_hover") iconSource: UM.Theme.getIcon("notice") - onEntered: - { - base.showTooltip(catalog.i18nc("@label","Some hidden settings use values different from their normal calculated value.\n\nClick to make these settings visible.")) - } + onEntered: base.showTooltip(catalog.i18nc("@label","Some hidden settings use values different from their normal calculated value.\n\nClick to make these settings visible.")) - onExited: - { - base.hideTooltip(); - } + onExited: base.hideTooltip() UM.I18nCatalog { id: catalog; name: "cura" } } diff --git a/resources/qml/Settings/SettingCheckBox.qml b/resources/qml/Settings/SettingCheckBox.qml index d37754d27c..0c7321d08a 100644 --- a/resources/qml/Settings/SettingCheckBox.qml +++ b/resources/qml/Settings/SettingCheckBox.qml @@ -28,37 +28,40 @@ SettingItem // 3: material -> user changed material in materials page // 4: variant // 5: machine - var value; - if ((base.resolve != "None") && (stackLevel != 0) && (stackLevel != 1)) { + var value + if ((base.resolve != "None") && (stackLevel != 0) && (stackLevel != 1)) + { // We have a resolve function. Indicates that the setting is not settable per extruder and that // we have to choose between the resolved value (default) and the global value // (if user has explicitly set this). - value = base.resolve; - } else { - value = propertyProvider.properties.value; + value = base.resolve + } + else + { + value = propertyProvider.properties.value } switch(value) { case "True": - return true; + return true case "False": - return false; + return false default: - return value; + return value } } Keys.onSpacePressed: { - forceActiveFocus(); - propertyProvider.setPropertyValue("value", !checked); + forceActiveFocus() + propertyProvider.setPropertyValue("value", !checked) } onClicked: { - forceActiveFocus(); - propertyProvider.setPropertyValue("value", !checked); + forceActiveFocus() + propertyProvider.setPropertyValue("value", !checked) } Keys.onTabPressed: @@ -72,9 +75,9 @@ SettingItem onActiveFocusChanged: { - if(activeFocus) + if (activeFocus) { - base.focusReceived(); + base.focusReceived() } } @@ -90,37 +93,38 @@ SettingItem color: { - if(!enabled) + if (!enabled) { return UM.Theme.getColor("setting_control_disabled") } - if(control.containsMouse || control.activeFocus) + if (control.containsMouse || control.activeFocus) { return UM.Theme.getColor("setting_control_highlight") } return UM.Theme.getColor("setting_control") } + radius: UM.Theme.getSize("setting_control_radius").width border.width: UM.Theme.getSize("default_lining").width border.color: { - if(!enabled) + if (!enabled) { return UM.Theme.getColor("setting_control_disabled_border") } - if(control.containsMouse || control.activeFocus) + if (control.containsMouse || control.activeFocus) { return UM.Theme.getColor("setting_control_border_highlight") } return UM.Theme.getColor("setting_control_border") } - UM.RecolorImage { + UM.RecolorImage + { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter width: Math.round(parent.width / 2.5) height: Math.round(parent.height / 2.5) - sourceSize.width: width sourceSize.height: width color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text"); source: UM.Theme.getIcon("check") diff --git a/resources/qml/Settings/SettingComboBox.qml b/resources/qml/Settings/SettingComboBox.qml index 76d458e427..a287e0c3ce 100644 --- a/resources/qml/Settings/SettingComboBox.qml +++ b/resources/qml/Settings/SettingComboBox.qml @@ -35,6 +35,7 @@ SettingItem return UM.Theme.getColor("setting_control") } + radius: UM.Theme.getSize("setting_control_radius").width border.width: UM.Theme.getSize("default_lining").width border.color: { @@ -62,7 +63,7 @@ SettingItem sourceSize.width: width + 5 * screenScaleFactor sourceSize.height: width + 5 * screenScaleFactor - color: UM.Theme.getColor("setting_control_text") + color: UM.Theme.getColor("setting_control_button") } contentItem: Label diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml index a9427f863a..6d39192de7 100644 --- a/resources/qml/Settings/SettingExtruder.qml +++ b/resources/qml/Settings/SettingExtruder.qml @@ -17,10 +17,16 @@ SettingItem id: control anchors.fill: parent - model: Cura.ExtrudersModel + property var extrudersModel: CuraApplication.getExtrudersModel() + + model: extrudersModel + + Connections { - onModelChanged: { - control.color = getItem(control.currentIndex).color; + target: extrudersModel + onModelChanged: + { + control.color = extrudersModel.getItem(control.currentIndex).color } } @@ -104,7 +110,7 @@ SettingItem sourceSize.width: width + 5 * screenScaleFactor sourceSize.height: width + 5 * screenScaleFactor - color: UM.Theme.getColor("setting_control_text"); + color: UM.Theme.getColor("setting_control_button"); } background: Rectangle @@ -113,14 +119,15 @@ SettingItem { if (!enabled) { - return UM.Theme.getColor("setting_control_disabled"); + return UM.Theme.getColor("setting_control_disabled") } if (control.hovered || base.activeFocus) { - return UM.Theme.getColor("setting_control_highlight"); + return UM.Theme.getColor("setting_control_highlight") } - return UM.Theme.getColor("setting_control"); + return UM.Theme.getColor("setting_control") } + radius: UM.Theme.getSize("setting_control_radius").width border.width: UM.Theme.getSize("default_lining").width border.color: { @@ -153,20 +160,18 @@ SettingItem elide: Text.ElideLeft verticalAlignment: Text.AlignVCenter - background: Rectangle + background: UM.RecolorImage { id: swatch - height: Math.round(UM.Theme.getSize("setting_control").height / 2) + height: Math.round(parent.height / 2) width: height - anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.margins: Math.round(UM.Theme.getSize("default_margin").width / 4) - - border.width: UM.Theme.getSize("default_lining").width - border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") - radius: Math.round(width / 2) + anchors.rightMargin: UM.Theme.getSize("thin_margin").width + sourceSize.width: width + sourceSize.height: height + source: UM.Theme.getIcon("extruder_button") color: control.color } } @@ -219,20 +224,18 @@ SettingItem verticalAlignment: Text.AlignVCenter rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width - background: Rectangle + background: UM.RecolorImage { id: swatch - height: Math.round(UM.Theme.getSize("setting_control").height / 2) + height: Math.round(parent.height / 2) width: height - anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.margins: Math.round(UM.Theme.getSize("default_margin").width / 4) - - border.width: UM.Theme.getSize("default_lining").width - border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") - radius: Math.round(width / 2) + anchors.rightMargin: UM.Theme.getSize("thin_margin").width + sourceSize.width: width + sourceSize.height: height + source: UM.Theme.getIcon("extruder_button") color: control.model.getItem(index).color } } diff --git a/resources/qml/Settings/SettingItem.qml b/resources/qml/Settings/SettingItem.qml index 785562cff5..4dd53f8663 100644 --- a/resources/qml/Settings/SettingItem.qml +++ b/resources/qml/Settings/SettingItem.qml @@ -10,10 +10,15 @@ import Cura 1.0 as Cura import "." -Item { - id: base; +Item +{ + id: base height: UM.Theme.getSize("section").height + anchors.left: parent.left + anchors.right: parent.right + // To avoid overlaping with the scrollBars + anchors.rightMargin: 2 * UM.Theme.getSize("thin_margin").width property alias contents: controlContainer.children property alias hovered: mouse.containsMouse @@ -43,25 +48,25 @@ Item { var affected_by = settingDefinitionsModel.getRequires(definition.key, "value") var affected_by_list = "" - for(var i in affected_by) + for (var i in affected_by) { affected_by_list += "
  • %1
  • \n".arg(affected_by[i].label) } var affects_list = "" - for(var i in affects) + for (var i in affects) { affects_list += "
  • %1
  • \n".arg(affects[i].label) } var tooltip = "%1\n

    %2

    ".arg(definition.label).arg(definition.description) - if(affects_list != "") + if (affects_list != "") { tooltip += "
    %1\n".arg(catalog.i18nc("@label Header for list of settings.", "Affects")).arg(affects_list) } - if(affected_by_list != "") + if (affected_by_list != "") { tooltip += "
    %1\n".arg(catalog.i18nc("@label Header for list of settings.", "Affected By")).arg(affected_by_list) } @@ -71,53 +76,57 @@ Item { MouseArea { - id: mouse; + id: mouse - anchors.fill: parent; + anchors.fill: parent - acceptedButtons: Qt.RightButton; + acceptedButtons: Qt.RightButton hoverEnabled: true; - onClicked: base.contextMenuRequested(); + onClicked: base.contextMenuRequested() - onEntered: { - hoverTimer.start(); + onEntered: + { + hoverTimer.start() } - onExited: { - if(controlContainer.item && controlContainer.item.hovered) { - return; + onExited: + { + if (controlContainer.item && controlContainer.item.hovered) + { + return } - hoverTimer.stop(); - base.hideTooltip(); + hoverTimer.stop() + base.hideTooltip() } - Timer { - id: hoverTimer; - interval: 500; - repeat: false; + Timer + { + id: hoverTimer + interval: 500 + repeat: false onTriggered: { - base.showTooltip(base.tooltipText); + base.showTooltip(base.tooltipText) } } Label { - id: label; + id: label - anchors.left: parent.left; - anchors.leftMargin: doDepthIndentation ? Math.round((UM.Theme.getSize("section_icon_column").width + 5) + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width)) : 0 - anchors.right: settingControls.left; + anchors.left: parent.left + anchors.leftMargin: doDepthIndentation ? Math.round(UM.Theme.getSize("thin_margin").width + ((definition.depth - 1) * UM.Theme.getSize("setting_control_depth_margin").width)) : 0 + anchors.right: settingControls.left anchors.verticalCenter: parent.verticalCenter text: definition.label - elide: Text.ElideMiddle; + elide: Text.ElideMiddle renderType: Text.NativeRendering textFormat: Text.PlainText - color: UM.Theme.getColor("setting_control_text"); + color: UM.Theme.getColor("setting_control_text") opacity: (definition.visible) ? 1 : 0.5 // emphasize the setting if it has a value in the user or quality profile font: base.doQualityUserSettingEmphasis && base.stackLevel != undefined && base.stackLevel <= 1 ? UM.Theme.getFont("default_italic") : UM.Theme.getFont("default") @@ -128,11 +137,12 @@ Item { id: settingControls height: Math.round(parent.height / 2) - spacing: Math.round(UM.Theme.getSize("sidebar_margin").height / 2) + spacing: Math.round(UM.Theme.getSize("thick_margin").height / 2) - anchors { + anchors + { right: controlContainer.left - rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width / 2) + rightMargin: Math.round(UM.Theme.getSize("thick_margin").width / 2) verticalCenter: parent.verticalCenter } @@ -150,112 +160,123 @@ Item { iconSource: UM.Theme.getIcon("link") - onEntered: { - hoverTimer.stop(); - var tooltipText = catalog.i18nc("@label", "This setting is always shared between all extruders. Changing it here will change the value for all extruders."); - if ((resolve != "None") && (stackLevel != 0)) { + onEntered: + { + hoverTimer.stop() + var tooltipText = catalog.i18nc("@label", "This setting is always shared between all extruders. Changing it here will change the value for all extruders.") + if ((resolve != "None") && (stackLevel != 0)) + { // We come here if a setting has a resolve and the setting is not manually edited. - tooltipText += " " + catalog.i18nc("@label", "The value is resolved from per-extruder values ") + "[" + Cura.ExtruderManager.getInstanceExtruderValues(definition.key) + "]."; + tooltipText += " " + catalog.i18nc("@label", "The value is resolved from per-extruder values ") + "[" + Cura.ExtruderManager.getInstanceExtruderValues(definition.key) + "]." } - base.showTooltip(tooltipText); + base.showTooltip(tooltipText) } - onExited: base.showTooltip(base.tooltipText); + onExited: base.showTooltip(base.tooltipText) } UM.SimpleButton { - id: revertButton; + id: revertButton visible: base.stackLevel == 0 && base.showRevertButton - height: parent.height; - width: height; + height: parent.height + width: height color: UM.Theme.getColor("setting_control_button") hoverColor: UM.Theme.getColor("setting_control_button_hover") iconSource: UM.Theme.getIcon("reset") - onClicked: { + onClicked: + { revertButton.focus = true - if (externalResetHandler) { + if (externalResetHandler) + { externalResetHandler(propertyProvider.key) - } else { + } + else + { Cura.MachineManager.clearUserSettingAllCurrentStacks(propertyProvider.key) } } - onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) } - onExited: base.showTooltip(base.tooltipText); + onEntered: + { + hoverTimer.stop() + base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) + } + onExited: base.showTooltip(base.tooltipText) } UM.SimpleButton { // This button shows when the setting has an inherited function, but is overriden by profile. - id: inheritButton; + id: inheritButton // Inherit button needs to be visible if; // - User made changes that override any loaded settings // - This setting item uses inherit button at all // - The type of the value of any deeper container is an "object" (eg; is a function) visible: { - if(!base.showInheritButton) + if (!base.showInheritButton) { - return false; + return false } - if(!propertyProvider.properties.enabled) + if (!propertyProvider.properties.enabled) { // Note: This is not strictly necessary since a disabled setting is hidden anyway. // But this will cause the binding to be re-evaluated when the enabled property changes. - return false; + return false } // There are no settings with any warning. - if(Cura.SettingInheritanceManager.settingsWithInheritanceWarning.length == 0) + if (Cura.SettingInheritanceManager.settingsWithInheritanceWarning.length == 0) { - return false; + return false } // This setting has a resolve value, so an inheritance warning doesn't do anything. - if(resolve != "None") + if (resolve != "None") { return false } // If the setting does not have a limit_to_extruder property (or is -1), use the active stack. - if(globalPropertyProvider.properties.limit_to_extruder == null || String(globalPropertyProvider.properties.limit_to_extruder) == "-1") + if (globalPropertyProvider.properties.limit_to_extruder == null || String(globalPropertyProvider.properties.limit_to_extruder) == "-1") { - return Cura.SettingInheritanceManager.settingsWithInheritanceWarning.indexOf(definition.key) >= 0; + return Cura.SettingInheritanceManager.settingsWithInheritanceWarning.indexOf(definition.key) >= 0 } // Setting does have a limit_to_extruder property, so use that one instead. if (definition.key === undefined) { // Observed when loading workspace, probably when SettingItems are removed. - return false; + return false } - return Cura.SettingInheritanceManager.getOverridesForExtruder(definition.key, String(globalPropertyProvider.properties.limit_to_extruder)).indexOf(definition.key) >= 0; + return Cura.SettingInheritanceManager.getOverridesForExtruder(definition.key, String(globalPropertyProvider.properties.limit_to_extruder)).indexOf(definition.key) >= 0 } - height: parent.height; - width: height; + height: parent.height + width: height - onClicked: { - focus = true; + onClicked: + { + focus = true // Get the most shallow function value (eg not a number) that we can find. var last_entry = propertyProvider.stackLevels[propertyProvider.stackLevels.length - 1] for (var i = 1; i < base.stackLevels.length; i++) { - var has_setting_function = typeof(propertyProvider.getPropertyValue("value", base.stackLevels[i])) == "object"; + var has_setting_function = typeof(propertyProvider.getPropertyValue("value", base.stackLevels[i])) == "object" if(has_setting_function) { last_entry = propertyProvider.stackLevels[i] - break; + break } } - if((last_entry == 4 || last_entry == 11) && base.stackLevel == 0 && base.stackLevels.length == 2) + if ((last_entry == 4 || last_entry == 11) && base.stackLevel == 0 && base.stackLevels.length == 2) { // Special case of the inherit reset. If only the definition (4th or 11th) container) and the first // entry (user container) are set, we can simply remove the container. @@ -276,23 +297,22 @@ Item { color: UM.Theme.getColor("setting_control_button") hoverColor: UM.Theme.getColor("setting_control_button_hover") - iconSource: UM.Theme.getIcon("formula"); + iconSource: UM.Theme.getIcon("formula") onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting is normally calculated, but it currently has an absolute value set.\n\nClick to restore the calculated value.")) } - onExited: base.showTooltip(base.tooltipText); + onExited: base.showTooltip(base.tooltipText) } } Item { - id: controlContainer; + id: controlContainer enabled: propertyProvider.isValueUsed - anchors.right: parent.right; - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - anchors.verticalCenter: parent.verticalCenter; - width: UM.Theme.getSize("setting_control").width; + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + width: UM.Theme.getSize("setting_control").width height: UM.Theme.getSize("setting_control").height } } diff --git a/resources/qml/Settings/SettingOptionalExtruder.qml b/resources/qml/Settings/SettingOptionalExtruder.qml index a3c1422b30..b73c7498ae 100644 --- a/resources/qml/Settings/SettingOptionalExtruder.qml +++ b/resources/qml/Settings/SettingOptionalExtruder.qml @@ -1,5 +1,5 @@ -// Copyright (c) 2016 Ultimaker B.V. -// Uranium is released under the terms of the LGPLv3 or higher. +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 import QtQuick.Controls 2.0 @@ -12,15 +12,24 @@ SettingItem id: base property var focusItem: control + // Somehow if we directory set control.model to CuraApplication.getExtrudersModelWithOptional() + // and in the Connections.onModelChanged use control.model as a reference, it will complain about + // non-existing properties such as "onModelChanged" and "getItem". I guess if we access the model + // via "control.model", it gives back a generic/abstract model instance. To avoid this, we add + // this extra property to keep the ExtrudersModel and use this in the rest of the code. + property var extrudersWithOptionalModel: CuraApplication.getExtrudersModelWithOptional() + contents: ComboBox { id: control anchors.fill: parent - model: Cura.ExtrudersModel + model: base.extrudersWithOptionalModel + + Connections { - onModelChanged: control.color = getItem(control.currentIndex).color - addOptionalExtruder: true + target: base.extrudersWithOptionalModel + onModelChanged: control.color = base.extrudersWithOptionalModel.getItem(control.currentIndex).color } textRole: "name" @@ -31,12 +40,15 @@ SettingItem { forceActiveFocus(); propertyProvider.setPropertyValue("value", model.getItem(index).index); - } else + } + else { if (propertyProvider.properties.value == -1) { - control.currentIndex = model.rowCount() - 1; // we know the last item is "Not overriden" - } else { + control.currentIndex = model.count - 1; // we know the last item is "Not overriden" + } + else + { control.currentIndex = propertyProvider.properties.value; // revert to the old value } } @@ -99,7 +111,7 @@ SettingItem sourceSize.width: width + 5 * screenScaleFactor sourceSize.height: width + 5 * screenScaleFactor - color: UM.Theme.getColor("setting_control_text"); + color: UM.Theme.getColor("setting_control_button"); } background: Rectangle @@ -116,6 +128,7 @@ SettingItem } return UM.Theme.getColor("setting_control"); } + radius: UM.Theme.getSize("setting_control_radius").width border.width: UM.Theme.getSize("default_lining").width border.color: { @@ -148,20 +161,18 @@ SettingItem elide: Text.ElideRight verticalAlignment: Text.AlignVCenter - background: Rectangle + background: UM.RecolorImage { id: swatch - height: Math.round(UM.Theme.getSize("setting_control").height / 2) + height: Math.round(parent.height / 2) width: height - anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.margins: Math.round(UM.Theme.getSize("default_margin").width / 4) - - border.width: UM.Theme.getSize("default_lining").width - border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") - radius: Math.round(width / 2) + anchors.rightMargin: UM.Theme.getSize("thin_margin").width + sourceSize.width: width + sourceSize.height: height + source: UM.Theme.getIcon("extruder_button") color: control.color } } @@ -215,20 +226,18 @@ SettingItem verticalAlignment: Text.AlignVCenter rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width - background: Rectangle + background: UM.RecolorImage { id: swatch - height: Math.round(UM.Theme.getSize("setting_control").height / 2) + height: Math.round(parent.height / 2) width: height - anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.margins: Math.round(UM.Theme.getSize("default_margin").width / 4) - - border.width: UM.Theme.getSize("default_lining").width - border.color: enabled ? UM.Theme.getColor("setting_control_border") : UM.Theme.getColor("setting_control_disabled_border") - radius: Math.round(width / 2) + anchors.rightMargin: UM.Theme.getSize("thin_margin").width + sourceSize.width: width + sourceSize.height: height + source: UM.Theme.getIcon("extruder_button") color: control.model.getItem(index).color } } diff --git a/resources/qml/Settings/SettingTextField.qml b/resources/qml/Settings/SettingTextField.qml index 9ec9338316..770ef53900 100644 --- a/resources/qml/Settings/SettingTextField.qml +++ b/resources/qml/Settings/SettingTextField.qml @@ -32,6 +32,7 @@ SettingItem anchors.fill: parent + radius: UM.Theme.getSize("setting_control_radius").width border.width: Math.round(UM.Theme.getSize("default_lining").width) border.color: { @@ -81,10 +82,10 @@ SettingItem Rectangle { - anchors.fill: parent; - anchors.margins: Math.round(UM.Theme.getSize("default_lining").width); + anchors.fill: parent + anchors.margins: Math.round(UM.Theme.getSize("default_lining").width) color: UM.Theme.getColor("setting_control_highlight") - opacity: !control.hovered ? 0 : propertyProvider.properties.validationState == "ValidatorState.Valid" ? 1.0 : 0.35; + opacity: !control.hovered ? 0 : propertyProvider.properties.validationState == "ValidatorState.Valid" ? 1.0 : 0.35 } Label @@ -145,11 +146,11 @@ SettingItem } color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default"); + font: UM.Theme.getFont("default") - selectByMouse: true; + selectByMouse: true - maximumLength: (definition.type == "str" || definition.type == "[int]") ? -1 : 10; + maximumLength: (definition.type == "str" || definition.type == "[int]") ? -1 : 10 clip: true; //Hide any text that exceeds the width of the text box. validator: RegExpValidator { regExp: (definition.type == "[int]") ? /^\[?(\s*-?[0-9]{0,9}\s*,)*(\s*-?[0-9]{0,9})\s*\]?$/ : (definition.type == "int") ? /^-?[0-9]{0,10}$/ : (definition.type == "float") ? /^-?[0-9]{0,9}[.,]?[0-9]{0,3}$/ : /^.*$/ } // definition.type property from parent loader used to disallow fractional number entry @@ -158,7 +159,8 @@ SettingItem { target: input property: "text" - value: { + value: + { // Stacklevels // 0: user -> unsaved change // 1: quality changes -> saved change @@ -167,13 +169,15 @@ SettingItem // 4: variant // 5: machine_changes // 6: machine - if ((base.resolve != "None" && base.resolve) && (stackLevel != 0) && (stackLevel != 1)) { + if ((base.resolve != "None" && base.resolve) && (stackLevel != 0) && (stackLevel != 1)) + { // We have a resolve function. Indicates that the setting is not settable per extruder and that // we have to choose between the resolved value (default) and the global value // (if user has explicitly set this). - return base.resolve; - } else { - return propertyProvider.properties.value; + return base.resolve + } + else { + return propertyProvider.properties.value } } when: !input.activeFocus @@ -182,16 +186,17 @@ SettingItem MouseArea { id: mouseArea - anchors.fill: parent; + anchors.fill: parent cursorShape: Qt.IBeamCursor onPressed: { - if(!input.activeFocus) { - base.focusGainedByClick = true; - input.forceActiveFocus(); + if (!input.activeFocus) + { + base.focusGainedByClick = true + input.forceActiveFocus() } - mouse.accepted = false; + mouse.accepted = false } } } diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index da50b430ac..972cbcdbb1 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -1,5 +1,5 @@ -// Copyright (c) 2017 Ultimaker B.V. -// Uranium is released under the terms of the LGPLv3 or higher. +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 import QtQuick.Controls 1.1 @@ -13,156 +13,28 @@ import "../Menus" Item { - id: base; + id: settingsView property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel() property Action configureSettings property bool findingSettings - signal showTooltip(Item item, point location, string text) - signal hideTooltip() - - Item - { - id: globalProfileRow - height: UM.Theme.getSize("sidebar_setup").height - visible: !sidebar.hideSettings - - anchors - { - top: parent.top - left: parent.left - leftMargin: Math.round(UM.Theme.getSize("sidebar_margin").width) - right: parent.right - rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width) - } - - Label - { - id: globalProfileLabel - text: catalog.i18nc("@label","Profile:") - textFormat: Text.PlainText - width: Math.round(parent.width * 0.45 - UM.Theme.getSize("sidebar_margin").width - 2) - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - verticalAlignment: Text.AlignVCenter - anchors.top: parent.top - anchors.bottom: parent.bottom - } - - ToolButton - { - id: globalProfileSelection - - text: generateActiveQualityText() - enabled: !header.currentExtruderVisible || header.currentExtruderIndex > -1 - width: Math.round(parent.width * 0.55) - height: UM.Theme.getSize("setting_control").height - anchors.left: globalProfileLabel.right - anchors.right: parent.right - tooltip: Cura.MachineManager.activeQualityOrQualityChangesName - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true - menu: ProfileMenu { } - - function generateActiveQualityText () { - var result = Cura.MachineManager.activeQualityOrQualityChangesName; - - if (Cura.MachineManager.isActiveQualitySupported) { - if (Cura.MachineManager.activeQualityLayerHeight > 0) { - result += " " - result += " - " - result += Cura.MachineManager.activeQualityLayerHeight + "mm" - result += "" - } - } - - return result - } - - UM.SimpleButton - { - id: customisedSettings - - visible: Cura.MachineManager.hasUserSettings - height: Math.round(parent.height * 0.6) - width: Math.round(parent.height * 0.6) - - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: Math.round(UM.Theme.getSize("setting_preferences_button_margin").width - UM.Theme.getSize("sidebar_margin").width) - - color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button"); - iconSource: UM.Theme.getIcon("star"); - - onClicked: - { - forceActiveFocus(); - Cura.Actions.manageProfiles.trigger() - } - onEntered: - { - var content = catalog.i18nc("@tooltip","Some setting/override values are different from the values stored in the profile.\n\nClick to open the profile manager.") - base.showTooltip(globalProfileRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), content) - } - onExited: base.hideTooltip() - } - } - } - - ToolButton - { - id: settingVisibilityMenu - - width: height - height: UM.Theme.getSize("setting_control").height - anchors - { - top: globalProfileRow.bottom - topMargin: UM.Theme.getSize("sidebar_margin").height - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - style: ButtonStyle - { - background: Item { - UM.RecolorImage { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - width: UM.Theme.getSize("standard_arrow").width - height: UM.Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: width - color: control.enabled ? UM.Theme.getColor("setting_category_text") : UM.Theme.getColor("setting_category_disabled_text") - source: UM.Theme.getIcon("menu") - } - } - label: Label{} - } - menu: SettingVisibilityPresetsMenu - { - onShowAllSettings: - { - definitionsModel.setAllVisible(true); - filter.updateDefinitionModel(); - } - } - } Rectangle { id: filterContainer visible: true + radius: UM.Theme.getSize("setting_control_radius").width border.width: Math.round(UM.Theme.getSize("default_lining").width) border.color: { - if(hoverMouseArea.containsMouse || clearFilterButton.containsMouse) + if (hoverMouseArea.containsMouse || clearFilterButton.containsMouse) { - return UM.Theme.getColor("setting_control_border_highlight"); + return UM.Theme.getColor("setting_control_border_highlight") } else { - return UM.Theme.getColor("setting_control_border"); + return UM.Theme.getColor("setting_control_border") } } @@ -170,16 +42,12 @@ Item anchors { - top: globalProfileRow.bottom - topMargin: UM.Theme.getSize("sidebar_margin").height + top: parent.top left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width right: settingVisibilityMenu.left - rightMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2) + rightMargin: UM.Theme.getSize("default_margin").width } - height: visible ? UM.Theme.getSize("setting_control").height : 0 - Behavior on height { NumberAnimation { duration: 100 } } - + height: UM.Theme.getSize("print_setup_big_item").height Timer { id: settingsSearchTimer @@ -191,19 +59,19 @@ Item TextField { - id: filter; + id: filter height: parent.height anchors.left: parent.left anchors.right: clearFilterButton.left - anchors.rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width) + anchors.rightMargin: Math.round(UM.Theme.getSize("thick_margin").width) - placeholderText: catalog.i18nc("@label:textbox", "Search...") + placeholderText: "" + "
    " + catalog.i18nc("@label:textbox", "search settings") style: TextFieldStyle { - textColor: UM.Theme.getColor("setting_control_text"); - placeholderTextColor: UM.Theme.getColor("setting_control_text") - font: UM.Theme.getFont("default"); + textColor: UM.Theme.getColor("setting_control_text") + placeholderTextColor: UM.Theme.getColor("setting_filter_field") + font: UM.Theme.getFont("default_italic") background: Item {} } @@ -217,38 +85,38 @@ Item onEditingFinished: { - definitionsModel.filter = {"i18n_label": "*" + text}; - findingSettings = (text.length > 0); - if(findingSettings != lastFindingSettings) + definitionsModel.filter = {"i18n_label": "*" + text} + findingSettings = (text.length > 0) + if (findingSettings != lastFindingSettings) { - updateDefinitionModel(); - lastFindingSettings = findingSettings; + updateDefinitionModel() + lastFindingSettings = findingSettings } } Keys.onEscapePressed: { - filter.text = ""; + filter.text = "" } function updateDefinitionModel() { - if(findingSettings) + if (findingSettings) { - expandedCategories = definitionsModel.expanded.slice(); - definitionsModel.expanded = [""]; // keep categories closed while to prevent render while making settings visible one by one - definitionsModel.showAncestors = true; - definitionsModel.showAll = true; - definitionsModel.expanded = ["*"]; + expandedCategories = definitionsModel.expanded.slice() + definitionsModel.expanded = [""] // keep categories closed while to prevent render while making settings visible one by one + definitionsModel.showAncestors = true + definitionsModel.showAll = true + definitionsModel.expanded = ["*"] } else { - if(expandedCategories) + if (expandedCategories) { - definitionsModel.expanded = expandedCategories; + definitionsModel.expanded = expandedCategories } - definitionsModel.showAncestors = false; - definitionsModel.showAll = false; + definitionsModel.showAncestors = false + definitionsModel.showAll = false } } } @@ -280,41 +148,93 @@ Item onClicked: { - filter.text = ""; - filter.forceActiveFocus(); + filter.text = "" + filter.forceActiveFocus() } } } + ToolButton + { + id: settingVisibilityMenu + + anchors + { + top: filterContainer.top + bottom: filterContainer.bottom + right: parent.right + rightMargin: UM.Theme.getSize("wide_margin").width + } + + style: ButtonStyle + { + background: Item + { + UM.RecolorImage + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: UM.Theme.getSize("standard_arrow").width + height: UM.Theme.getSize("standard_arrow").height + sourceSize.width: width + sourceSize.height: height + color: control.hovered ? UM.Theme.getColor("small_button_text_hover") : UM.Theme.getColor("small_button_text") + source: UM.Theme.getIcon("menu") + } + } + label: Label {} + } + + menu: SettingVisibilityPresetsMenu + { + onShowAllSettings: + { + definitionsModel.setAllVisible(true) + filter.updateDefinitionModel() + } + } + } + + // Mouse area that gathers the scroll events to not propagate it to the main view. + MouseArea + { + anchors.fill: scrollView + acceptedButtons: Qt.AllButtons + onWheel: wheel.accepted = true + } + ScrollView { - anchors.top: filterContainer.bottom; - anchors.bottom: parent.bottom; - anchors.right: parent.right; - anchors.left: parent.left; - anchors.topMargin: filterContainer.visible ? UM.Theme.getSize("sidebar_margin").height : 0 - Behavior on anchors.topMargin { NumberAnimation { duration: 100 } } + id: scrollView + anchors + { + top: filterContainer.bottom + topMargin: UM.Theme.getSize("default_margin").height + bottom: parent.bottom + right: parent.right + left: parent.left + } - style: UM.Theme.styles.scrollview; - flickableItem.flickableDirection: Flickable.VerticalFlick; - __wheelAreaScrollSpeed: 75; // Scroll three lines in one scroll event + style: UM.Theme.styles.scrollview + flickableItem.flickableDirection: Flickable.VerticalFlick + __wheelAreaScrollSpeed: 75 // Scroll three lines in one scroll event ListView { id: contents - spacing: Math.round(UM.Theme.getSize("default_lining").height); - cacheBuffer: 1000000; // Set a large cache to effectively just cache every list item. + spacing: UM.Theme.getSize("default_lining").height + cacheBuffer: 1000000 // Set a large cache to effectively just cache every list item. model: UM.SettingDefinitionsModel { - id: definitionsModel; + id: definitionsModel containerId: Cura.MachineManager.activeDefinitionId visibilityHandler: UM.SettingPreferenceVisibilityHandler { } exclude: ["machine_settings", "command_line_settings", "infill_mesh", "infill_mesh_order", "cutting_mesh", "support_mesh", "anti_overhang_mesh"] // TODO: infill_mesh settigns are excluded hardcoded, but should be based on the fact that settable_globally, settable_per_meshgroup and settable_per_extruder are false. expanded: CuraApplication.expandedCategories onExpandedChanged: { - if(!findingSettings) + if (!findingSettings) { // Do not change expandedCategories preference while filtering settings // because all categories are expanded while filtering @@ -330,7 +250,7 @@ Item { id: delegate - width: Math.round(UM.Theme.getSize("sidebar").width); + width: scrollView.width height: provider.properties.enabled == "True" ? UM.Theme.getSize("section").height : - contents.spacing Behavior on height { NumberAnimation { duration: 100 } } opacity: provider.properties.enabled == "True" ? 1 : 0 @@ -400,17 +320,17 @@ Item // machine gets changed. var activeMachineId = Cura.MachineManager.activeMachineId; - if(!model.settable_per_extruder) + if (!model.settable_per_extruder) { //Not settable per extruder or there only is global, so we must pick global. return activeMachineId; } - if(inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0) + if (inheritStackProvider.properties.limit_to_extruder != null && inheritStackProvider.properties.limit_to_extruder >= 0) { //We have limit_to_extruder, so pick that stack. return Cura.ExtruderManager.extruderIds[String(inheritStackProvider.properties.limit_to_extruder)]; } - if(Cura.ExtruderManager.activeExtruderStackId) + if (Cura.ExtruderManager.activeExtruderStackId) { //We're on an extruder tab. Pick the current extruder. return Cura.ExtruderManager.activeExtruderStackId; @@ -451,7 +371,7 @@ Item contextMenu.provider = provider contextMenu.popup(); } - onShowTooltip: base.showTooltip(delegate, { x: -UM.Theme.getSize("default_arrow").width, y: Math.round(delegate.height / 2) }, text) + onShowTooltip: base.showTooltip(delegate, Qt.point(- settingsView.x - UM.Theme.getSize("default_margin").width, 0), text) onHideTooltip: base.hideTooltip() onShowAllHiddenInheritedSettings: { @@ -472,14 +392,14 @@ Item } onSetActiveFocusToNextSetting: { - if(forward == undefined || forward) + if (forward == undefined || forward) { contents.currentIndex = contents.indexWithFocus + 1; while(contents.currentItem && contents.currentItem.height <= 0) { contents.currentIndex++; } - if(contents.currentItem) + if (contents.currentItem) { contents.currentItem.item.focusItem.forceActiveFocus(); } @@ -491,7 +411,7 @@ Item { contents.currentIndex--; } - if(contents.currentItem) + if (contents.currentItem) { contents.currentItem.item.focusItem.forceActiveFocus(); } @@ -638,17 +558,6 @@ Item onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu); } - MenuSeparator {} - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Collapse All") - onTriggered: definitionsModel.collapseAll() - } - MenuItem - { - text: catalog.i18nc("@action:inmenu", "Expand All") - onTriggered: definitionsModel.expandRecursive() - } } UM.SettingPropertyProvider diff --git a/resources/qml/SidebarAdvanced.qml b/resources/qml/SidebarAdvanced.qml deleted file mode 100644 index ff5f545c80..0000000000 --- a/resources/qml/SidebarAdvanced.qml +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2015 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 2.0 - -import "Settings" - -SettingView { -} diff --git a/resources/qml/SidebarContents.qml b/resources/qml/SidebarContents.qml deleted file mode 100644 index 0b19bfe3c1..0000000000 --- a/resources/qml/SidebarContents.qml +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2016 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 -import QtQuick.Layouts 1.1 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -StackView -{ - id: sidebarContents - - delegate: StackViewDelegate - { - function transitionFinished(properties) - { - properties.exitItem.opacity = 1 - } - - pushTransition: StackViewTransition - { - PropertyAnimation - { - target: enterItem - property: "opacity" - from: 0 - to: 1 - duration: 100 - } - PropertyAnimation - { - target: exitItem - property: "opacity" - from: 1 - to: 0 - duration: 100 - } - } - } -} \ No newline at end of file diff --git a/resources/qml/SidebarHeader.qml b/resources/qml/SidebarHeader.qml deleted file mode 100644 index 5fde199cd0..0000000000 --- a/resources/qml/SidebarHeader.qml +++ /dev/null @@ -1,617 +0,0 @@ -// Copyright (c) 2017 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -import "Menus" - -Column -{ - id: base; - - property int currentExtruderIndex: Cura.ExtruderManager.activeExtruderIndex; - property bool currentExtruderVisible: extrudersList.visible; - property bool printerConnected: Cura.MachineManager.printerConnected - property bool hasManyPrinterTypes: - { - if (printerConnected) - { - if (Cura.MachineManager.printerOutputDevices[0].connectedPrintersTypeCount != null) - { - return Cura.MachineManager.printerOutputDevices[0].connectedPrintersTypeCount.length > 1; - } - } - return false; - } - property bool buildplateCompatibilityError: !Cura.MachineManager.variantBuildplateCompatible && !Cura.MachineManager.variantBuildplateUsable - property bool buildplateCompatibilityWarning: Cura.MachineManager.variantBuildplateUsable - - spacing: Math.round(UM.Theme.getSize("sidebar_margin").width * 0.9) - - signal showTooltip(Item item, point location, string text) - signal hideTooltip() - - Item - { - id: initialSeparator - anchors - { - left: parent.left - right: parent.right - } - visible: printerTypeSelectionRow.visible || buildplateRow.visible || extruderSelectionRow.visible - height: UM.Theme.getSize("default_lining").height - width: height - } - - // Printer Type Row - Item - { - id: printerTypeSelectionRow - height: UM.Theme.getSize("sidebar_setup").height - visible: printerConnected && hasManyPrinterTypes && !sidebar.hideSettings - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - Label - { - id: configurationLabel - text: catalog.i18nc("@label", "Printer type"); - width: Math.round(parent.width * 0.4 - UM.Theme.getSize("default_margin").width) - height: parent.height - verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton - { - id: printerTypeSelection - text: Cura.MachineManager.activeMachineDefinitionName - tooltip: Cura.MachineManager.activeMachineDefinitionName - height: UM.Theme.getSize("setting_control").height - width: Math.round(parent.width * 0.7) + UM.Theme.getSize("sidebar_margin").width - anchors.right: parent.right - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true; - - menu: PrinterTypeMenu { } - } - } - - Rectangle { - id: headerSeparator - width: parent.width - visible: printerTypeSelectionRow.visible - height: visible ? UM.Theme.getSize("sidebar_lining").height : 0 - color: UM.Theme.getColor("sidebar_lining") - } - - // Extruder Row - Item - { - id: extruderSelectionRow - width: parent.width - height: Math.round(UM.Theme.getSize("sidebar_tabs").height * 2 / 3) - visible: machineExtruderCount.properties.value > 1 - - anchors - { - left: parent.left - leftMargin: Math.round(UM.Theme.getSize("sidebar_margin").width * 0.7) - right: parent.right - rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width * 0.7) - topMargin: UM.Theme.getSize("sidebar_margin").height - } - - ListView - { - id: extrudersList - property var index: 0 - - height: UM.Theme.getSize("sidebar_header_mode_tabs").height - width: Math.round(parent.width) - boundsBehavior: Flickable.StopAtBounds - - anchors - { - left: parent.left - leftMargin: Math.round(UM.Theme.getSize("default_margin").width / 2) - right: parent.right - rightMargin: Math.round(UM.Theme.getSize("default_margin").width / 2) - verticalCenter: parent.verticalCenter - } - - ExclusiveGroup { id: extruderMenuGroup; } - - orientation: ListView.Horizontal - - model: Cura.ExtrudersModel { id: extrudersModel; } - - Connections - { - target: Cura.MachineManager - onGlobalContainerChanged: forceActiveFocus() // Changing focus applies the currently-being-typed values so it can change the displayed setting values. - } - - delegate: Button - { - height: ListView.view.height - width: Math.round(ListView.view.width / extrudersModel.rowCount()) - - text: model.name - tooltip: model.name - exclusiveGroup: extruderMenuGroup - checked: base.currentExtruderIndex == index - - property bool extruder_enabled: true - - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: { - switch (mouse.button) { - case Qt.LeftButton: - extruder_enabled = Cura.MachineManager.getExtruder(model.index).isEnabled - if (extruder_enabled) - { - forceActiveFocus(); // Changing focus applies the currently-being-typed values so it can change the displayed setting values. - Cura.ExtruderManager.setActiveExtruderIndex(index); - } - break; - case Qt.RightButton: - extruder_enabled = Cura.MachineManager.getExtruder(model.index).isEnabled - extruderMenu.popup(); - break; - } - - } - } - - Menu - { - id: extruderMenu - - MenuItem { - text: catalog.i18nc("@action:inmenu", "Enable Extruder") - onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, true) - visible: !extruder_enabled // using an intermediate variable prevents an empty popup that occured now and then - } - - MenuItem { - text: catalog.i18nc("@action:inmenu", "Disable Extruder") - onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false) - visible: extruder_enabled - enabled: Cura.MachineManager.numberExtrudersEnabled > 1 - } - } - - style: ButtonStyle - { - background: Item - { - function buttonBackgroundColor(index) - { - var extruder = Cura.MachineManager.getExtruder(index) - if (extruder.isEnabled) { - return (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active") : - control.hovered ? UM.Theme.getColor("action_button_hovered") : - UM.Theme.getColor("action_button") - } else { - return UM.Theme.getColor("action_button_disabled") - } - } - - function buttonBorderColor(index) - { - var extruder = Cura.MachineManager.getExtruder(index) - if (extruder.isEnabled) { - return (control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_border") : - control.hovered ? UM.Theme.getColor("action_button_hovered_border") : - UM.Theme.getColor("action_button_border") - } else { - return UM.Theme.getColor("action_button_disabled_border") - } - } - - function buttonColor(index) { - var extruder = Cura.MachineManager.getExtruder(index); - if (extruder.isEnabled) - { - return ( - control.checked || control.pressed) ? UM.Theme.getColor("action_button_active_text") : - control.hovered ? UM.Theme.getColor("action_button_hovered_text") : - UM.Theme.getColor("action_button_text"); - } else { - return UM.Theme.getColor("action_button_disabled_text"); - } - } - - Rectangle - { - anchors.fill: parent - border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width - border.color: buttonBorderColor(index) - color: buttonBackgroundColor(index) - Behavior on color { ColorAnimation { duration: 50; } } - } - - Item - { - id: extruderButtonFace - anchors.centerIn: parent - - width: { - var extruderTextWidth = extruderStaticText.visible ? extruderStaticText.width : 0; - var iconWidth = extruderIconItem.width; - return Math.round(extruderTextWidth + iconWidth + UM.Theme.getSize("default_margin").width / 2); - } - - // Static text "Extruder" - Label - { - id: extruderStaticText - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - - color: buttonColor(index) - - font: UM.Theme.getFont("large_nonbold") - text: catalog.i18nc("@label", "Extruder") - visible: width < (control.width - extruderIconItem.width - UM.Theme.getSize("default_margin").width) - elide: Text.ElideRight - } - - // Everything for the extruder icon - Item - { - id: extruderIconItem - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - - property var sizeToUse: - { - var minimumWidth = control.width < UM.Theme.getSize("button").width ? control.width : UM.Theme.getSize("button").width; - var minimumHeight = control.height < UM.Theme.getSize("button").height ? control.height : UM.Theme.getSize("button").height; - var minimumSize = minimumWidth < minimumHeight ? minimumWidth : minimumHeight; - minimumSize -= Math.round(UM.Theme.getSize("default_margin").width / 2); - return minimumSize; - } - - width: sizeToUse - height: sizeToUse - - UM.RecolorImage { - id: mainCircle - anchors.fill: parent - - sourceSize.width: parent.width - sourceSize.height: parent.width - source: UM.Theme.getIcon("extruder_button") - - color: extruderNumberText.color - } - - Label - { - id: extruderNumberText - anchors.centerIn: parent - text: index + 1; - color: buttonColor(index) - font: UM.Theme.getFont("default_bold") - } - - // Material colour circle - // Only draw the filling colour of the material inside the SVG border. - Rectangle - { - id: materialColorCircle - - anchors - { - right: parent.right - top: parent.top - rightMargin: Math.round(parent.sizeToUse * 0.01) - topMargin: Math.round(parent.sizeToUse * 0.05) - } - - color: model.color - - width: Math.round(parent.width * 0.35) - height: Math.round(parent.height * 0.35) - radius: Math.round(width / 2) - - border.width: 1 - border.color: UM.Theme.getColor("extruder_button_material_border") - - opacity: !control.checked ? 0.6 : 1.0 - } - } - } - } - label: Item {} - } - } - } - } - - Item - { - id: variantRowSpacer - height: Math.round(UM.Theme.getSize("sidebar_margin").height / 4) - width: height - visible: !extruderSelectionRow.visible && !initialSeparator.visible - } - - // Material Row - Item - { - id: materialRow - height: UM.Theme.getSize("sidebar_setup").height - visible: Cura.MachineManager.hasMaterials && !sidebar.hideSettings - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - Label - { - id: materialLabel - text: catalog.i18nc("@label", "Material"); - width: Math.round(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) - height: parent.height - verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton - { - id: materialSelection - - property var activeExtruder: Cura.MachineManager.activeStack - property var hasActiveExtruder: activeExtruder != null - property var currentRootMaterialName: hasActiveExtruder ? activeExtruder.material.name : "" - - text: currentRootMaterialName - tooltip: currentRootMaterialName - visible: Cura.MachineManager.hasMaterials - enabled: !extrudersList.visible || base.currentExtruderIndex > -1 - height: UM.Theme.getSize("setting_control").height - width: Math.round(parent.width * 0.7) + UM.Theme.getSize("sidebar_margin").width - anchors.right: parent.right - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true; - menu: MaterialMenu - { - extruderIndex: base.currentExtruderIndex - } - - property var valueError: !isMaterialSupported() - property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported - - function isMaterialSupported () - { - if (!hasActiveExtruder) - { - return false; - } - return Cura.ContainerManager.getContainerMetaDataEntry(activeExtruder.material.id, "compatible", "") == "True" - } - } - } - - //Variant row - Item - { - id: variantRow - height: UM.Theme.getSize("sidebar_setup").height - visible: Cura.MachineManager.hasVariants && !sidebar.hideSettings - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - Label - { - id: variantLabel - text: Cura.MachineManager.activeDefinitionVariantsName; - width: Math.round(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) - height: parent.height - verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton - { - id: variantSelection - text: Cura.MachineManager.activeVariantName - tooltip: Cura.MachineManager.activeVariantName; - visible: Cura.MachineManager.hasVariants - - height: UM.Theme.getSize("setting_control").height - width: Math.round(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) - anchors.right: parent.right - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true; - - menu: NozzleMenu { extruderIndex: base.currentExtruderIndex } - } - } - - Rectangle - { - id: buildplateSeparator - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - width: parent.width - 2 * UM.Theme.getSize("sidebar_margin").width - visible: buildplateRow.visible - height: visible ? UM.Theme.getSize("sidebar_lining_thin").height : 0 - color: UM.Theme.getColor("sidebar_lining") - } - - //Buildplate row - Item - { - id: buildplateRow - height: UM.Theme.getSize("sidebar_setup").height - // TODO Only show in dev mode. Remove check when feature ready - visible: CuraSDKVersion == "dev" ? Cura.MachineManager.hasVariantBuildplates && !sidebar.hideSettings : false - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - Label - { - id: buildplateLabel - text: catalog.i18nc("@label", "Build plate"); - width: Math.floor(parent.width * 0.45 - UM.Theme.getSize("default_margin").width) - height: parent.height - verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - } - - ToolButton - { - id: buildplateSelection - text: Cura.MachineManager.activeVariantBuildplateName - tooltip: Cura.MachineManager.activeVariantBuildplateName - visible: Cura.MachineManager.hasVariantBuildplates - - height: UM.Theme.getSize("setting_control").height - width: Math.floor(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width) - anchors.right: parent.right - style: UM.Theme.styles.sidebar_header_button - activeFocusOnPress: true; - - menu: BuildplateMenu {} - - property var valueError: !Cura.MachineManager.variantBuildplateCompatible && !Cura.MachineManager.variantBuildplateUsable - property var valueWarning: Cura.MachineManager.variantBuildplateUsable - } - } - - // Material info row - Item - { - id: materialInfoRow - height: Math.round(UM.Theme.getSize("sidebar_setup").height / 2) - visible: (Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariantBuildplates) && !sidebar.hideSettings - - anchors - { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: parent.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - } - - // TODO This was added to replace the buildplate selector. Remove this component when the feature is ready - Label - { - id: materialCompatibilityLabel - y: -Math.round(UM.Theme.getSize("sidebar_margin").height / 3) - anchors.left: parent.left - width: parent.width - materialCompatibilityLink.width - text: catalog.i18nc("@label", "Use glue with this material combination") - font: UM.Theme.getFont("very_small") - color: UM.Theme.getColor("text") - visible: CuraSDKVersion == "dev" ? false : buildplateCompatibilityError || buildplateCompatibilityWarning - wrapMode: Text.WordWrap - opacity: 0.5 - } - - Item - { - id: materialCompatibilityLink - height: UM.Theme.getSize("sidebar_setup").height - anchors.right: parent.right - width: childrenRect.width + UM.Theme.getSize("default_margin").width - - UM.RecolorImage { - id: warningImage - anchors.right: materialInfoLabel.left - anchors.rightMargin: UM.Theme.getSize("default_margin").width - anchors.verticalCenter: parent.Bottom - source: UM.Theme.getIcon("warning") - width: UM.Theme.getSize("section_icon").width - height: UM.Theme.getSize("section_icon").height - sourceSize.width: width - sourceSize.height: height - color: UM.Theme.getColor("material_compatibility_warning") - visible: !Cura.MachineManager.isCurrentSetupSupported || buildplateCompatibilityError || buildplateCompatibilityWarning - } - - Label { - id: materialInfoLabel - wrapMode: Text.WordWrap - text: "" + catalog.i18nc("@label", "Check compatibility") + "" - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - linkColor: UM.Theme.getColor("text_link") - verticalAlignment: Text.AlignTop - anchors.top: parent.top - anchors.right: parent.right - anchors.bottom: parent.bottom - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onClicked: { - // open the material URL with web browser - var url = "https://ultimaker.com/incoming-links/cura/material-compatibilty" - Qt.openUrlExternally(url); - } - onEntered: { - var content = catalog.i18nc("@tooltip", "Click to check the material compatibility on Ultimaker.com."); - base.showTooltip( - materialInfoRow, - Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), - catalog.i18nc("@tooltip", content) - ); - } - onExited: base.hideTooltip(); - } - } - } - } - - UM.SettingPropertyProvider - { - id: machineExtruderCount - - containerStack: Cura.MachineManager.activeMachine - key: "machine_extruder_count" - watchedProperties: [ "value" ] - storeIndex: 0 - } - - UM.I18nCatalog { id: catalog; name:"cura" } -} diff --git a/resources/qml/SidebarSimple.qml b/resources/qml/SidebarSimple.qml deleted file mode 100644 index ddb42f44c6..0000000000 --- a/resources/qml/SidebarSimple.qml +++ /dev/null @@ -1,1168 +0,0 @@ -// Copyright (c) 2018 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Layouts 1.3 - -import UM 1.2 as UM -import Cura 1.0 as Cura - -Item -{ - id: base - - signal showTooltip(Item item, point location, string text); - signal hideTooltip(); - - property Action configureSettings; - property variant minimumPrintTime: PrintInformation.minimumPrintTime; - property variant maximumPrintTime: PrintInformation.maximumPrintTime; - property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1 - Component.onCompleted: PrintInformation.enabled = true - Component.onDestruction: PrintInformation.enabled = false - UM.I18nCatalog { id: catalog; name: "cura" } - - ScrollView - { - visible: Cura.MachineManager.activeMachineName != "" // If no printers added then the view is invisible - anchors.fill: parent - style: UM.Theme.styles.scrollview - flickableItem.flickableDirection: Flickable.VerticalFlick - - Rectangle - { - width: childrenRect.width - height: childrenRect.height - color: UM.Theme.getColor("sidebar") - - // - // Quality profile - // - Item - { - id: qualityRow - - height: UM.Theme.getSize("sidebar_margin").height - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.right: parent.right - - Timer - { - id: qualitySliderChangeTimer - interval: 50 - running: false - repeat: false - onTriggered: - { - var item = Cura.QualityProfilesDropDownMenuModel.getItem(qualitySlider.value); - Cura.MachineManager.activeQualityGroup = item.quality_group; - } - } - - Component.onCompleted: qualityModel.update() - - Connections - { - target: Cura.QualityProfilesDropDownMenuModel - onItemsChanged: qualityModel.update() - } - - Connections { - target: base - onVisibleChanged: - { - // update needs to be called when the widgets are visible, otherwise the step width calculation - // will fail because the width of an invisible item is 0. - if (visible) - { - qualityModel.update(); - } - } - } - - ListModel - { - id: qualityModel - - property var totalTicks: 0 - property var availableTotalTicks: 0 - property var existingQualityProfile: 0 - - property var qualitySliderActiveIndex: 0 - property var qualitySliderStepWidth: 0 - property var qualitySliderAvailableMin: 0 - property var qualitySliderAvailableMax: 0 - property var qualitySliderMarginRight: 0 - - function update () - { - reset() - - var availableMin = -1 - var availableMax = -1 - - for (var i = 0; i < Cura.QualityProfilesDropDownMenuModel.rowCount(); i++) - { - var qualityItem = Cura.QualityProfilesDropDownMenuModel.getItem(i) - - // Add each quality item to the UI quality model - qualityModel.append(qualityItem) - - // Set selected value - if (Cura.MachineManager.activeQualityType == qualityItem.quality_type) - { - // set to -1 when switching to user created profile so all ticks are clickable - if (Cura.SimpleModeSettingsManager.isProfileUserCreated) - { - qualityModel.qualitySliderActiveIndex = -1 - } - else - { - qualityModel.qualitySliderActiveIndex = i - } - - qualityModel.existingQualityProfile = 1 - } - - // Set min available - if (qualityItem.available && availableMin == -1) - { - availableMin = i - } - - // Set max available - if (qualityItem.available) - { - availableMax = i - } - } - - // Set total available ticks for active slider part - if (availableMin != -1) - { - qualityModel.availableTotalTicks = availableMax - availableMin + 1 - } - - // Calculate slider values - calculateSliderStepWidth(qualityModel.totalTicks) - calculateSliderMargins(availableMin, availableMax, qualityModel.totalTicks) - - qualityModel.qualitySliderAvailableMin = availableMin - qualityModel.qualitySliderAvailableMax = availableMax - } - - function calculateSliderStepWidth (totalTicks) - { - qualityModel.qualitySliderStepWidth = totalTicks != 0 ? Math.round((base.width * 0.55) / (totalTicks)) : 0 - } - - function calculateSliderMargins (availableMin, availableMax, totalTicks) - { - if (availableMin == -1 || (availableMin == 0 && availableMax == 0)) - { - qualityModel.qualitySliderMarginRight = Math.round(base.width * 0.55) - } - else if (availableMin == availableMax) - { - qualityModel.qualitySliderMarginRight = Math.round((totalTicks - availableMin) * qualitySliderStepWidth) - } - else - { - qualityModel.qualitySliderMarginRight = Math.round((totalTicks - availableMax) * qualitySliderStepWidth) - } - } - - function reset () { - qualityModel.clear() - qualityModel.availableTotalTicks = 0 - qualityModel.existingQualityProfile = 0 - - // check, the ticks count cannot be less than zero - qualityModel.totalTicks = Math.max(0, Cura.QualityProfilesDropDownMenuModel.rowCount() - 1) - } - } - - Label - { - id: qualityRowTitle - text: catalog.i18nc("@label", "Layer Height") - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - } - - // Show titles for the each quality slider ticks - Item - { - y: -5; - anchors.left: speedSlider.left - Repeater - { - model: qualityModel - - Label - { - anchors.verticalCenter: parent.verticalCenter - anchors.top: parent.top - anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height / 2) - color: (Cura.MachineManager.activeMachine != null && Cura.QualityProfilesDropDownMenuModel.getItem(index).available) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") - text: - { - var result = "" - if(Cura.MachineManager.activeMachine != null) - { - result = Cura.QualityProfilesDropDownMenuModel.getItem(index).layer_height - - if(result == undefined) - { - result = ""; - } - else - { - result = Number(Math.round(result + "e+2") + "e-2"); //Round to 2 decimals. Javascript makes this difficult... - if (result == undefined || result != result) //Parse failure. - { - result = ""; - } - } - } - return result - } - - x: - { - // Make sure the text aligns correctly with each tick - if (qualityModel.totalTicks == 0) - { - // If there is only one tick, align it centrally - return Math.round(((base.width * 0.55) - width) / 2) - } - else if (index == 0) - { - return Math.round(base.width * 0.55 / qualityModel.totalTicks) * index - } - else if (index == qualityModel.totalTicks) - { - return Math.round(base.width * 0.55 / qualityModel.totalTicks) * index - width - } - else - { - return Math.round((base.width * 0.55 / qualityModel.totalTicks) * index - (width / 2)) - } - } - } - } - } - - //Print speed slider - Item - { - id: speedSlider - width: Math.round(base.width * 0.55) - height: UM.Theme.getSize("sidebar_margin").height - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - - // This Item is used only for tooltip, for slider area which is unavailable - Item - { - function showTooltip (showTooltip) - { - if (showTooltip) - { - var content = catalog.i18nc("@tooltip", "This quality profile is not available for you current material and nozzle configuration. Please change these to enable this quality profile") - base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content) - } - else - { - base.hideTooltip() - } - } - - id: unavailableLineToolTip - height: 20 * screenScaleFactor // hovered area height - z: parent.z + 1 // should be higher, otherwise the area can be hovered - x: 0 - anchors.verticalCenter: qualitySlider.verticalCenter - - Rectangle - { - id: leftArea - width: - { - if (qualityModel.availableTotalTicks == 0) - { - return qualityModel.qualitySliderStepWidth * qualityModel.totalTicks - } - return qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin - 10 - } - height: parent.height - color: "transparent" - - MouseArea - { - anchors.fill: parent - hoverEnabled: true - enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false - onEntered: unavailableLineToolTip.showTooltip(true) - onExited: unavailableLineToolTip.showTooltip(false) - } - } - - Rectangle - { - id: rightArea - width: - { - if(qualityModel.availableTotalTicks == 0) - return 0 - - return qualityModel.qualitySliderMarginRight - 10 - } - height: parent.height - color: "transparent" - x: - { - if (qualityModel.availableTotalTicks == 0) - { - return 0 - } - - var leftUnavailableArea = qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin - var totalGap = qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks -1) + leftUnavailableArea + 10 - - return totalGap - } - - MouseArea - { - anchors.fill: parent - hoverEnabled: true - enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false - onEntered: unavailableLineToolTip.showTooltip(true) - onExited: unavailableLineToolTip.showTooltip(false) - } - } - } - - // Draw Unavailable line - Rectangle - { - id: groovechildrect - width: Math.round(base.width * 0.55) - height: 2 * screenScaleFactor - color: UM.Theme.getColor("quality_slider_unavailable") - anchors.verticalCenter: qualitySlider.verticalCenter - x: 0 - } - - // Draw ticks - Repeater - { - id: qualityRepeater - model: qualityModel.totalTicks > 0 ? qualityModel : 0 - - Rectangle - { - anchors.verticalCenter: parent.verticalCenter - color: Cura.QualityProfilesDropDownMenuModel.getItem(index).available ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") - width: 1 * screenScaleFactor - height: 6 * screenScaleFactor - y: 0 - x: Math.round(qualityModel.qualitySliderStepWidth * index) - } - } - - Slider - { - id: qualitySlider - height: UM.Theme.getSize("sidebar_margin").height - anchors.bottom: speedSlider.bottom - enabled: qualityModel.totalTicks > 0 && !Cura.SimpleModeSettingsManager.isProfileCustomized - visible: qualityModel.availableTotalTicks > 0 - updateValueWhileDragging : false - - minimumValue: qualityModel.qualitySliderAvailableMin >= 0 ? qualityModel.qualitySliderAvailableMin : 0 - // maximumValue must be greater than minimumValue to be able to see the handle. While the value is strictly - // speaking not always correct, it seems to have the correct behavior (switching from 0 available to 1 available) - maximumValue: qualityModel.qualitySliderAvailableMax >= 1 ? qualityModel.qualitySliderAvailableMax : 1 - stepSize: 1 - - value: qualityModel.qualitySliderActiveIndex - - width: qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks - 1) - - anchors.right: parent.right - anchors.rightMargin: qualityModel.qualitySliderMarginRight - - style: SliderStyle - { - //Draw Available line - groove: Rectangle - { - implicitHeight: 2 * screenScaleFactor - color: UM.Theme.getColor("quality_slider_available") - radius: Math.round(height / 2) - } - handle: Item - { - Rectangle - { - id: qualityhandleButton - anchors.centerIn: parent - color: UM.Theme.getColor("quality_slider_available") - implicitWidth: 10 * screenScaleFactor - implicitHeight: implicitWidth - radius: Math.round(implicitWidth / 2) - visible: !Cura.SimpleModeSettingsManager.isProfileCustomized && !Cura.SimpleModeSettingsManager.isProfileUserCreated && qualityModel.existingQualityProfile - } - } - } - - onValueChanged: - { - // only change if an active machine is set and the slider is visible at all. - if (Cura.MachineManager.activeMachine != null && visible) - { - // prevent updating during view initializing. Trigger only if the value changed by user - if (qualitySlider.value != qualityModel.qualitySliderActiveIndex && qualityModel.qualitySliderActiveIndex != -1) - { - // start updating with short delay - qualitySliderChangeTimer.start() - } - } - } - } - - MouseArea - { - id: speedSliderMouseArea - anchors.fill: parent - hoverEnabled: true - enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated - - onEntered: - { - var content = catalog.i18nc("@tooltip","A custom profile is currently active. To enable the quality slider, choose a default quality profile in Custom tab") - base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content) - } - onExited: - { - base.hideTooltip(); - } - } - } - - Label - { - id: speedLabel - anchors.top: speedSlider.bottom - - anchors.left: parent.left - - text: catalog.i18nc("@label", "Print Speed") - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - width: Math.round(UM.Theme.getSize("sidebar").width * 0.35) - elide: Text.ElideRight - } - - Label - { - anchors.bottom: speedLabel.bottom - anchors.left: speedSlider.left - - text: catalog.i18nc("@label", "Slower") - font: UM.Theme.getFont("default") - color: (qualityModel.availableTotalTicks > 1) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") - horizontalAlignment: Text.AlignLeft - } - - Label - { - anchors.bottom: speedLabel.bottom - anchors.right: speedSlider.right - - text: catalog.i18nc("@label", "Faster") - font: UM.Theme.getFont("default") - color: (qualityModel.availableTotalTicks > 1) ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") - horizontalAlignment: Text.AlignRight - } - - UM.SimpleButton - { - id: customisedSettings - - visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.SimpleModeSettingsManager.isProfileUserCreated - height: Math.round(speedSlider.height * 0.8) - width: Math.round(speedSlider.height * 0.8) - - anchors.verticalCenter: speedSlider.verticalCenter - anchors.right: speedSlider.left - anchors.rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width / 2) - - color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button"); - iconSource: UM.Theme.getIcon("reset"); - - onClicked: - { - // if the current profile is user-created, switch to a built-in quality - Cura.MachineManager.resetToUseDefaultQuality() - } - onEntered: - { - var content = catalog.i18nc("@tooltip","You have modified some profile settings. If you want to change these go to custom mode.") - base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content) - } - onExited: base.hideTooltip() - } - } - - // - // Infill - // - Item - { - id: infillCellLeft - - anchors.top: qualityRow.bottom - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height * 2 - anchors.left: parent.left - - width: Math.round(UM.Theme.getSize("sidebar").width * .45) - UM.Theme.getSize("sidebar_margin").width - - Label - { - id: infillLabel - text: catalog.i18nc("@label", "Infill") - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - - anchors.top: parent.top - anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height * 1.7) - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - } - } - - Item - { - id: infillCellRight - - height: infillSlider.height + UM.Theme.getSize("sidebar_margin").height + enableGradualInfillCheckBox.visible * (enableGradualInfillCheckBox.height + UM.Theme.getSize("sidebar_margin").height) - width: Math.round(UM.Theme.getSize("sidebar").width * .55) - - anchors.left: infillCellLeft.right - anchors.top: infillCellLeft.top - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - - Label { - id: selectedInfillRateText - - //anchors.top: parent.top - anchors.left: infillSlider.left - anchors.leftMargin: Math.round((infillSlider.value / infillSlider.stepSize) * (infillSlider.width / (infillSlider.maximumValue / infillSlider.stepSize)) - 10 * screenScaleFactor) - anchors.right: parent.right - - text: parseInt(infillDensity.properties.value) + "%" - horizontalAlignment: Text.AlignLeft - - color: infillSlider.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") - } - - // We use a binding to make sure that after manually setting infillSlider.value it is still bound to the property provider - Binding { - target: infillSlider - property: "value" - value: parseInt(infillDensity.properties.value) - } - - Slider - { - id: infillSlider - - anchors.top: selectedInfillRateText.bottom - anchors.left: parent.left - anchors.right: infillIcon.left - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - - height: UM.Theme.getSize("sidebar_margin").height - width: parseInt(infillCellRight.width - UM.Theme.getSize("sidebar_margin").width - style.handleWidth) - - minimumValue: 0 - maximumValue: 100 - stepSize: 1 - tickmarksEnabled: true - - // disable slider when gradual support is enabled - enabled: parseInt(infillSteps.properties.value) == 0 - - // set initial value from stack - value: parseInt(infillDensity.properties.value) - - onValueChanged: { - - // Don't round the value if it's already the same - if (parseInt(infillDensity.properties.value) == infillSlider.value) { - return - } - - // Round the slider value to the nearest multiple of 10 (simulate step size of 10) - var roundedSliderValue = Math.round(infillSlider.value / 10) * 10 - - // Update the slider value to represent the rounded value - infillSlider.value = roundedSliderValue - - // Update value only if the Recomended mode is Active, - // Otherwise if I change the value in the Custom mode the Recomended view will try to repeat - // same operation - var active_mode = UM.Preferences.getValue("cura/active_mode") - - if (active_mode == 0 || active_mode == "simple") - { - Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue) - Cura.MachineManager.resetSettingForAllExtruders("infill_line_distance") - } - } - - style: SliderStyle - { - groove: Rectangle { - id: groove - implicitWidth: 200 * screenScaleFactor - implicitHeight: 2 * screenScaleFactor - color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") - radius: 1 - } - - handle: Item { - Rectangle { - id: handleButton - anchors.centerIn: parent - color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") - implicitWidth: 10 * screenScaleFactor - implicitHeight: 10 * screenScaleFactor - radius: 10 * screenScaleFactor - } - } - - tickmarks: Repeater { - id: repeater - model: control.maximumValue / control.stepSize + 1 - - // check if a tick should be shown based on it's index and wether the infill density is a multiple of 10 (slider step size) - function shouldShowTick (index) { - if (index % 10 == 0) { - return true - } - return false - } - - Rectangle { - anchors.verticalCenter: parent.verticalCenter - color: control.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable") - width: 1 * screenScaleFactor - height: 6 * screenScaleFactor - y: 0 - x: Math.round(styleData.handleWidth / 2 + index * ((repeater.width - styleData.handleWidth) / (repeater.count-1))) - visible: shouldShowTick(index) - } - } - } - } - - Rectangle - { - id: infillIcon - - width: Math.round((parent.width / 5) - (UM.Theme.getSize("sidebar_margin").width)) - height: width - - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height / 2) - - // we loop over all density icons and only show the one that has the current density and steps - Repeater - { - id: infillIconList - model: infillModel - anchors.fill: parent - - function activeIndex () { - for (var i = 0; i < infillModel.count; i++) { - var density = Math.round(infillDensity.properties.value) - var steps = Math.round(infillSteps.properties.value) - var infillModelItem = infillModel.get(i) - - if (infillModelItem != "undefined" - && density >= infillModelItem.percentageMin - && density <= infillModelItem.percentageMax - && steps >= infillModelItem.stepsMin - && steps <= infillModelItem.stepsMax - ){ - return i - } - } - return -1 - } - - Rectangle - { - anchors.fill: parent - visible: infillIconList.activeIndex() == index - - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("quality_slider_unavailable") - - UM.RecolorImage { - anchors.fill: parent - anchors.margins: 2 * screenScaleFactor - sourceSize.width: width - sourceSize.height: width - source: UM.Theme.getIcon(model.icon) - color: UM.Theme.getColor("quality_slider_unavailable") - } - } - } - } - - // Gradual Support Infill Checkbox - CheckBox { - id: enableGradualInfillCheckBox - property alias _hovered: enableGradualInfillMouseArea.containsMouse - - anchors.top: infillSlider.bottom - anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height / 2) // closer to slider since it belongs to the same category - anchors.left: infillCellRight.left - - style: UM.Theme.styles.checkbox - enabled: base.settingsEnabled - visible: infillSteps.properties.enabled == "True" - checked: parseInt(infillSteps.properties.value) > 0 - - MouseArea { - id: enableGradualInfillMouseArea - - anchors.fill: parent - hoverEnabled: true - enabled: true - - property var previousInfillDensity: parseInt(infillDensity.properties.value) - - onClicked: { - // Set to 90% only when enabling gradual infill - var newInfillDensity; - if (parseInt(infillSteps.properties.value) == 0) { - previousInfillDensity = parseInt(infillDensity.properties.value) - newInfillDensity = 90; - } else { - newInfillDensity = previousInfillDensity; - } - Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", String(newInfillDensity)) - - var infill_steps_value = 0; - if (parseInt(infillSteps.properties.value) == 0) - infill_steps_value = 5; - - Cura.MachineManager.setSettingForAllExtruders("gradual_infill_steps", "value", infill_steps_value) - } - - onEntered: { - base.showTooltip(enableGradualInfillCheckBox, Qt.point(-infillCellRight.x, 0), - catalog.i18nc("@label", "Gradual infill will gradually increase the amount of infill towards the top.")) - } - - onExited: { - base.hideTooltip() - } - } - - Label { - id: gradualInfillLabel - height: parent.height - anchors.left: enableGradualInfillCheckBox.right - anchors.leftMargin: Math.round(UM.Theme.getSize("sidebar_margin").width / 2) - verticalAlignment: Text.AlignVCenter; - text: catalog.i18nc("@label", "Enable gradual") - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - } - } - - // Infill list model for mapping icon - ListModel - { - id: infillModel - Component.onCompleted: - { - infillModel.append({ - percentageMin: -1, - percentageMax: 0, - stepsMin: -1, - stepsMax: 0, - icon: "hollow" - }) - infillModel.append({ - percentageMin: 0, - percentageMax: 40, - stepsMin: -1, - stepsMax: 0, - icon: "sparse" - }) - infillModel.append({ - percentageMin: 40, - percentageMax: 89, - stepsMin: -1, - stepsMax: 0, - icon: "dense" - }) - infillModel.append({ - percentageMin: 90, - percentageMax: 9999999999, - stepsMin: -1, - stepsMax: 0, - icon: "solid" - }) - infillModel.append({ - percentageMin: 0, - percentageMax: 9999999999, - stepsMin: 1, - stepsMax: 9999999999, - icon: "gradual" - }) - } - } - } - - // - // Enable support - // - Label - { - id: enableSupportLabel - visible: enableSupportCheckBox.visible - - anchors.top: infillCellRight.bottom - anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height * 1.5) - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.right: infillCellLeft.right - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - anchors.verticalCenter: enableSupportCheckBox.verticalCenter - - text: catalog.i18nc("@label", "Generate Support"); - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - elide: Text.ElideRight - } - - CheckBox - { - id: enableSupportCheckBox - property alias _hovered: enableSupportMouseArea.containsMouse - - anchors.top: enableSupportLabel.top - anchors.left: infillCellRight.left - - style: UM.Theme.styles.checkbox; - enabled: base.settingsEnabled - - visible: supportEnabled.properties.enabled == "True" - checked: supportEnabled.properties.value == "True"; - - MouseArea - { - id: enableSupportMouseArea - anchors.fill: parent - hoverEnabled: true - enabled: true - onClicked: - { - // The value is a string "True" or "False" - supportEnabled.setPropertyValue("value", supportEnabled.properties.value != "True"); - } - onEntered: - { - base.showTooltip(enableSupportCheckBox, Qt.point(-enableSupportCheckBox.x, 0), - catalog.i18nc("@label", "Generate structures to support parts of the model which have overhangs. Without these structures, such parts would collapse during printing.")); - } - onExited: - { - base.hideTooltip(); - } - } - } - - ComboBox - { - id: supportExtruderCombobox - visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1) - model: extruderModel - - property string color_override: "" // for manually setting values - property string color: // is evaluated automatically, but the first time is before extruderModel being filled - { - var current_extruder = extruderModel.get(currentIndex); - color_override = ""; - if (current_extruder === undefined) return "" - return (current_extruder.color) ? current_extruder.color : ""; - } - - textRole: "text" // this solves that the combobox isn't populated in the first time Cura is started - - anchors.top: enableSupportCheckBox.top - //anchors.topMargin: ((supportEnabled.properties.value === "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("sidebar_margin").height : 0 - anchors.left: enableSupportCheckBox.right - anchors.leftMargin: Math.round(UM.Theme.getSize("sidebar_margin").width / 2) - - width: Math.round(UM.Theme.getSize("sidebar").width * .55) - Math.round(UM.Theme.getSize("sidebar_margin").width / 2) - enableSupportCheckBox.width - height: ((supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)) ? UM.Theme.getSize("setting_control").height : 0 - - Behavior on height { NumberAnimation { duration: 100 } } - - style: UM.Theme.styles.combobox_color - enabled: base.settingsEnabled - property alias _hovered: supportExtruderMouseArea.containsMouse - - currentIndex: - { - if (supportExtruderNr.properties == null) - { - return Cura.MachineManager.defaultExtruderPosition; - } - else - { - var extruder = parseInt(supportExtruderNr.properties.value); - if ( extruder === -1) - { - return Cura.MachineManager.defaultExtruderPosition; - } - return extruder; - } - } - - onActivated: - { - // Send the extruder nr as a string. - supportExtruderNr.setPropertyValue("value", String(index)); - } - MouseArea - { - id: supportExtruderMouseArea - anchors.fill: parent - hoverEnabled: true - enabled: base.settingsEnabled - acceptedButtons: Qt.NoButton - onEntered: - { - base.showTooltip(supportExtruderCombobox, Qt.point(-supportExtruderCombobox.x, 0), - catalog.i18nc("@label", "Select which extruder to use for support. This will build up supporting structures below the model to prevent the model from sagging or printing in mid air.")); - } - onExited: - { - base.hideTooltip(); - } - } - - function updateCurrentColor() - { - var current_extruder = extruderModel.get(currentIndex); - if (current_extruder !== undefined) { - supportExtruderCombobox.color_override = current_extruder.color; - } - } - - } - - Label - { - id: adhesionHelperLabel - visible: adhesionCheckBox.visible - - text: catalog.i18nc("@label", "Build Plate Adhesion") - font: UM.Theme.getFont("default") - color: UM.Theme.getColor("text") - elide: Text.ElideRight - - anchors { - left: parent.left - leftMargin: UM.Theme.getSize("sidebar_margin").width - right: infillCellLeft.right - rightMargin: UM.Theme.getSize("sidebar_margin").width - verticalCenter: adhesionCheckBox.verticalCenter - } - } - - CheckBox - { - id: adhesionCheckBox - property alias _hovered: adhesionMouseArea.containsMouse - - anchors.top: enableSupportCheckBox.bottom - anchors.topMargin: UM.Theme.getSize("sidebar_margin").height - anchors.left: infillCellRight.left - - //: Setting enable printing build-plate adhesion helper checkbox - style: UM.Theme.styles.checkbox; - enabled: base.settingsEnabled - - visible: platformAdhesionType.properties.enabled == "True" - checked: platformAdhesionType.properties.value != "skirt" && platformAdhesionType.properties.value != "none" - - MouseArea - { - id: adhesionMouseArea - anchors.fill: parent - hoverEnabled: true - enabled: base.settingsEnabled - onClicked: - { - var adhesionType = "skirt"; - if(!parent.checked) - { - // Remove the "user" setting to see if the rest of the stack prescribes a brim or a raft - platformAdhesionType.removeFromContainer(0); - adhesionType = platformAdhesionType.properties.value; - if(adhesionType == "skirt" || adhesionType == "none") - { - // If the rest of the stack doesn't prescribe an adhesion-type, default to a brim - adhesionType = "brim"; - } - } - platformAdhesionType.setPropertyValue("value", adhesionType); - } - onEntered: - { - base.showTooltip(adhesionCheckBox, Qt.point(-adhesionCheckBox.x, 0), - catalog.i18nc("@label", "Enable printing a brim or raft. This will add a flat area around or under your object which is easy to cut off afterwards.")); - } - onExited: - { - base.hideTooltip(); - } - } - } - - ListModel - { - id: extruderModel - Component.onCompleted: populateExtruderModel() - } - - //: Model used to populate the extrudelModel - Cura.ExtrudersModel - { - id: extruders - onModelChanged: populateExtruderModel() - } - - Item - { - id: tipsCell - anchors.top: adhesionCheckBox.visible ? adhesionCheckBox.bottom : (enableSupportCheckBox.visible ? supportExtruderCombobox.bottom : infillCellRight.bottom) - anchors.topMargin: Math.round(UM.Theme.getSize("sidebar_margin").height * 2) - anchors.left: parent.left - width: parent.width - height: tipsText.contentHeight * tipsText.lineCount - - Label - { - id: tipsText - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("sidebar_margin").width - anchors.right: parent.right - anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width - anchors.top: parent.top - wrapMode: Text.WordWrap - text: catalog.i18nc("@label", "Need help improving your prints?
    Read the Ultimaker Troubleshooting Guides").arg("https://ultimaker.com/en/troubleshooting") - font: UM.Theme.getFont("default"); - color: UM.Theme.getColor("text"); - linkColor: UM.Theme.getColor("text_link") - onLinkActivated: Qt.openUrlExternally(link) - } - } - - UM.SettingPropertyProvider - { - id: infillExtruderNumber - containerStackId: Cura.MachineManager.activeStackId - key: "infill_extruder_nr" - watchedProperties: [ "value" ] - storeIndex: 0 - } - - UM.SettingPropertyProvider - { - id: infillDensity - containerStackId: Cura.MachineManager.activeStackId - key: "infill_sparse_density" - watchedProperties: [ "value" ] - storeIndex: 0 - } - - UM.SettingPropertyProvider - { - id: infillSteps - containerStackId: Cura.MachineManager.activeStackId - key: "gradual_infill_steps" - watchedProperties: ["value", "enabled"] - storeIndex: 0 - } - - UM.SettingPropertyProvider - { - id: platformAdhesionType - containerStack: Cura.MachineManager.activeMachine - removeUnusedValue: false //Doesn't work with settings that are resolved. - key: "adhesion_type" - watchedProperties: [ "value", "enabled" ] - storeIndex: 0 - } - - UM.SettingPropertyProvider - { - id: supportEnabled - containerStack: Cura.MachineManager.activeMachine - key: "support_enable" - watchedProperties: [ "value", "enabled", "description" ] - storeIndex: 0 - } - - UM.SettingPropertyProvider - { - id: extrudersEnabledCount - containerStack: Cura.MachineManager.activeMachine - key: "extruders_enabled_count" - watchedProperties: [ "value" ] - storeIndex: 0 - } - - UM.SettingPropertyProvider - { - id: supportExtruderNr - containerStack: Cura.MachineManager.activeMachine - key: "support_extruder_nr" - watchedProperties: [ "value" ] - storeIndex: 0 - } - } - } - - function populateExtruderModel() - { - extruderModel.clear(); - for(var extruderNumber = 0; extruderNumber < extruders.rowCount() ; extruderNumber++) - { - extruderModel.append({ - text: extruders.getItem(extruderNumber).name, - color: extruders.getItem(extruderNumber).color - }) - } - supportExtruderCombobox.updateCurrentColor(); - } -} diff --git a/resources/qml/ToolTip.qml b/resources/qml/ToolTip.qml new file mode 100644 index 0000000000..e82caf01b2 --- /dev/null +++ b/resources/qml/ToolTip.qml @@ -0,0 +1,63 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.0 as UM +import Cura 1.0 as Cura + +ToolTip +{ + enum ContentAlignment + { + AlignLeft, + AlignRight + } + + // Defines the alignment of the content, by default to the left + property int contentAlignment: Cura.ToolTip.ContentAlignment.AlignRight + + property alias tooltipText: tooltip.text + property var targetPoint: Qt.point(parent.x, y + Math.round(height/2)) + + id: tooltip + text: "" + delay: 500 + font: UM.Theme.getFont("default") + + // If the text is not set, just set the height to 0 to prevent it from showing + height: text != "" ? label.contentHeight + 2 * UM.Theme.getSize("thin_margin").width: 0 + + x: + { + if (contentAlignment == Cura.ToolTip.ContentAlignment.AlignLeft) + { + return (label.width + Math.round(UM.Theme.getSize("default_arrow").width * 1.2) + padding * 2) * -1 + } + return parent.width + Math.round(UM.Theme.getSize("default_arrow").width * 1.2 + padding) + } + + y: Math.round(parent.height / 2 - label.height / 2 ) - padding + + padding: UM.Theme.getSize("thin_margin").width + + background: UM.PointingRectangle + { + id: backgroundRect + color: UM.Theme.getColor("tooltip") + target: Qt.point(targetPoint.x - tooltip.x, targetPoint.y - tooltip.y) + arrowSize: UM.Theme.getSize("default_arrow").width + } + + contentItem: Label + { + id: label + text: tooltip.text + font: tooltip.font + wrapMode: Text.Wrap + textFormat: Text.RichText + color: UM.Theme.getColor("tooltip_text") + renderType: Text.NativeRendering + } +} \ No newline at end of file diff --git a/resources/qml/Toolbar.qml b/resources/qml/Toolbar.qml index a04b3650df..33481b9183 100644 --- a/resources/qml/Toolbar.qml +++ b/resources/qml/Toolbar.qml @@ -2,96 +2,159 @@ // 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.Controls 2.3 import UM 1.2 as UM import Cura 1.0 as Cura Item { - id: base; + id: base - width: buttons.width; + width: buttons.width height: buttons.height property int activeY - Column + Item { - id: buttons; + id: buttons + width: parent.visible ? toolButtons.width : 0 + height: childrenRect.height - anchors.bottom: parent.bottom - anchors.left: parent.left - spacing: UM.Theme.getSize("button_lining").width + Behavior on width { NumberAnimation { duration: 100 } } - Repeater + // Used to create a rounded rectangle behind the toolButtons + Rectangle { - id: repeat - - model: UM.ToolModel { } - width: childrenRect.width - height: childrenRect.height - Button + anchors { - text: model.name + (model.shortcut ? (" (" + model.shortcut + ")") : "") - iconSource: (UM.Theme.getIcon(model.icon) != "") ? UM.Theme.getIcon(model.icon) : "file:///" + model.location + "/" + model.icon - checkable: true - checked: model.active - enabled: model.enabled && UM.Selection.hasSelection && UM.Controller.toolsEnabled - style: UM.Theme.styles.tool_button + fill: toolButtons + leftMargin: -radius - border.width + rightMargin: -border.width + topMargin: -border.width + bottomMargin: -border.width + } + radius: UM.Theme.getSize("default_radius").width + color: UM.Theme.getColor("lining") + } - onCheckedChanged: + Column + { + id: toolButtons + + anchors.top: parent.top + anchors.right: parent.right + spacing: UM.Theme.getSize("default_lining").height + + Repeater + { + id: repeat + + model: UM.ToolModel { id: toolsModel } + width: childrenRect.width + height: childrenRect.height + + delegate: ToolbarButton { - if (checked) + text: model.name + (model.shortcut ? (" (" + model.shortcut + ")") : "") + checkable: true + checked: model.active + enabled: model.enabled && UM.Selection.hasSelection && UM.Controller.toolsEnabled + + isTopElement: toolsModel.getItem(0).id == model.id + isBottomElement: toolsModel.getItem(toolsModel.count - 1).id == model.id + + toolItem: UM.RecolorImage { - base.activeY = y; + source: UM.Theme.getIcon(model.icon) != "" ? UM.Theme.getIcon(model.icon) : "file:///" + model.location + "/" + model.icon + color: UM.Theme.getColor("icon") + + sourceSize: UM.Theme.getSize("button_icon") } - } - //Workaround since using ToolButton's onClicked would break the binding of the checked property, instead - //just catch the click so we do not trigger that behaviour. - MouseArea - { - anchors.fill: parent; - onClicked: + onCheckedChanged: { - forceActiveFocus() //First grab focus, so all the text fields are updated - if(parent.checked) + if (checked) { - UM.Controller.setActiveTool(null); + base.activeY = y; } - else + } + + //Workaround since using ToolButton's onClicked would break the binding of the checked property, instead + //just catch the click so we do not trigger that behaviour. + MouseArea + { + anchors.fill: parent; + onClicked: { - UM.Controller.setActiveTool(model.id); + forceActiveFocus() //First grab focus, so all the text fields are updated + if(parent.checked) + { + UM.Controller.setActiveTool(null); + } + else + { + UM.Controller.setActiveTool(model.id); + } } } } } } - Item { height: UM.Theme.getSize("default_margin").height; width: UM.Theme.getSize("default_lining").width; visible: extruders.count > 0 } - - Repeater + // Used to create a rounded rectangle behind the extruderButtons + Rectangle { - id: extruders - width: childrenRect.width - height: childrenRect.height - property var _model: Cura.ExtrudersModel { id: extrudersModel } - model: _model.items.length > 1 ? _model : 0 - ExtruderButton { extruder: model } + anchors + { + fill: extruderButtons + leftMargin: -radius - border.width + rightMargin: -border.width + topMargin: -border.width + bottomMargin: -border.width + } + radius: UM.Theme.getSize("default_radius").width + color: UM.Theme.getColor("lining") + visible: extrudersModel.items.length > 1 + } + + Column + { + id: extruderButtons + + anchors.topMargin: UM.Theme.getSize("default_margin").height + anchors.top: toolButtons.bottom + anchors.right: parent.right + spacing: UM.Theme.getSize("default_lining").height + + Repeater + { + id: extruders + width: childrenRect.width + height: childrenRect.height + model: extrudersModel.items.length > 1 ? extrudersModel : 0 + + delegate: ExtruderButton + { + extruder: model + isTopElement: extrudersModel.getItem(0).id == model.id + isBottomElement: extrudersModel.getItem(extrudersModel.rowCount() - 1).id == model.id + } + } } } + property var extrudersModel: CuraApplication.getExtrudersModel() + UM.PointingRectangle { - id: panelBorder; + id: panelBorder - anchors.left: parent.right; - anchors.leftMargin: UM.Theme.getSize("default_margin").width; - anchors.top: base.top; + anchors.left: parent.right + anchors.leftMargin: UM.Theme.getSize("default_margin").width + anchors.top: base.top anchors.topMargin: base.activeY - z: buttons.z -1 + z: buttons.z - 1 target: Qt.point(parent.right, base.activeY + Math.round(UM.Theme.getSize("button").height/2)) arrowSize: UM.Theme.getSize("default_arrow").width @@ -100,14 +163,14 @@ Item { if (panel.item && panel.width > 0) { - return Math.max(panel.width + 2 * UM.Theme.getSize("default_margin").width); + return Math.max(panel.width + 2 * UM.Theme.getSize("default_margin").width) } else { return 0; } } - height: panel.item ? panel.height + 2 * UM.Theme.getSize("default_margin").height : 0; + height: panel.item ? panel.height + 2 * UM.Theme.getSize("default_margin").height : 0 opacity: panel.item && panel.width > 0 ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 100 } } @@ -125,11 +188,11 @@ Item { id: panel - x: UM.Theme.getSize("default_margin").width; - y: UM.Theme.getSize("default_margin").height; + x: UM.Theme.getSize("default_margin").width + y: UM.Theme.getSize("default_margin").height source: UM.ActiveTool.valid ? UM.ActiveTool.activeToolPanel : "" - enabled: UM.Controller.toolsEnabled; + enabled: UM.Controller.toolsEnabled } } diff --git a/resources/qml/ToolbarButton.qml b/resources/qml/ToolbarButton.qml new file mode 100644 index 0000000000..b3f84bba1d --- /dev/null +++ b/resources/qml/ToolbarButton.qml @@ -0,0 +1,106 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Button +{ + id: base + + property alias toolItem: contentItemLoader.sourceComponent + + // These two properties indicate whether the toolbar button is at the top of the toolbar column or at the bottom. + // If it is somewhere in the middle, then both has to be false. If there is only one element in the column, then + // both properties have to be set to true. This is used to create a rounded corner. + property bool isTopElement: false + property bool isBottomElement: false + + hoverEnabled: true + + background: Rectangle + { + implicitWidth: UM.Theme.getSize("button").width + implicitHeight: UM.Theme.getSize("button").height + color: + { + if (base.checked && base.hovered) + { + return UM.Theme.getColor("toolbar_button_active_hover") + } + else if (base.checked) + { + return UM.Theme.getColor("toolbar_button_active") + } + else if(base.hovered) + { + return UM.Theme.getColor("toolbar_button_hover") + } + return UM.Theme.getColor("toolbar_background") + } + radius: UM.Theme.getSize("default_radius").width + + Rectangle + { + id: topSquare + anchors + { + left: parent.left + right: parent.right + top: parent.top + } + height: parent.radius + color: parent.color + visible: !base.isTopElement + } + + Rectangle + { + id: bottomSquare + anchors + { + left: parent.left + right: parent.right + bottom: parent.bottom + } + height: parent.radius + color: parent.color + visible: !base.isBottomElement + } + + Rectangle + { + id: leftSquare + anchors + { + left: parent.left + top: parent.top + bottom: parent.bottom + } + width: parent.radius + color: parent.color + } + } + + contentItem: Item + { + opacity: parent.enabled ? 1.0 : 0.2 + Loader + { + id: contentItemLoader + anchors.centerIn: parent + width: UM.Theme.getSize("button_icon").width + height: UM.Theme.getSize("button_icon").height + } + } + + Cura.ToolTip + { + id: tooltip + tooltipText: base.text + visible: base.hovered + } +} diff --git a/resources/qml/Topbar.qml b/resources/qml/Topbar.qml deleted file mode 100644 index 17819dbd27..0000000000 --- a/resources/qml/Topbar.qml +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) 2017 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 UM 1.4 as UM -import Cura 1.0 as Cura -import "Menus" - -Rectangle -{ - id: base - anchors.left: parent.left - anchors.right: parent.right - height: UM.Theme.getSize("sidebar_header").height - color: UM.Controller.activeStage.stageId == "MonitorStage" ? UM.Theme.getColor("topbar_background_color_monitoring") : UM.Theme.getColor("topbar_background_color") - - property bool printerConnected: Cura.MachineManager.printerConnected - property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands - - property int rightMargin: UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width; - property int allItemsWidth: 0; - - function updateMarginsAndSizes() { - if (UM.Preferences.getValue("cura/sidebar_collapsed")) - { - rightMargin = UM.Theme.getSize("default_margin").width; - } - else - { - rightMargin = UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width; - } - allItemsWidth = ( - logo.width + UM.Theme.getSize("topbar_logo_right_margin").width + - UM.Theme.getSize("topbar_logo_right_margin").width + stagesMenuContainer.width + - UM.Theme.getSize("default_margin").width + viewModeButton.width + - rightMargin); - } - - UM.I18nCatalog - { - id: catalog - name:"cura" - } - - Image - { - id: logo - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.verticalCenter: parent.verticalCenter - - source: UM.Theme.getImage("logo"); - width: UM.Theme.getSize("logo").width; - height: UM.Theme.getSize("logo").height; - - sourceSize.width: width; - sourceSize.height: height; - } - - Row - { - id: stagesMenuContainer - anchors.left: logo.right - anchors.leftMargin: UM.Theme.getSize("topbar_logo_right_margin").width - spacing: UM.Theme.getSize("default_margin").width - - // The topbar is dynamically filled with all available stages - Repeater - { - id: stagesMenu - - model: UM.StageModel{} - - delegate: Button - { - text: model.name - checkable: true - checked: model.active - exclusiveGroup: topbarMenuGroup - style: (model.stage.iconSource != "") ? UM.Theme.styles.topbar_header_tab_no_overlay : UM.Theme.styles.topbar_header_tab - height: UM.Theme.getSize("sidebar_header").height - onClicked: UM.Controller.setActiveStage(model.id) - iconSource: model.stage.iconSource - - property color overlayColor: "transparent" - property string overlayIconSource: "" - } - } - - ExclusiveGroup { id: topbarMenuGroup } - } - - // View orientation Item - Row - { - id: viewOrientationControl - height: 30 - - spacing: 2 - visible: UM.Controller.activeStage.stageId != "MonitorStage" - - anchors - { - verticalCenter: base.verticalCenter - right: viewModeButton.left - rightMargin: UM.Theme.getSize("default_margin").width - } - - // #1 3d view - Button - { - iconSource: UM.Theme.getIcon("view_3d") - style: UM.Theme.styles.small_tool_button - anchors.verticalCenter: viewOrientationControl.verticalCenter - onClicked:UM.Controller.rotateView("3d", 0) - visible: base.width - allItemsWidth - 4 * this.width > 0 - } - - // #2 Front view - Button - { - iconSource: UM.Theme.getIcon("view_front") - style: UM.Theme.styles.small_tool_button - anchors.verticalCenter: viewOrientationControl.verticalCenter - onClicked: UM.Controller.rotateView("home", 0); - visible: base.width - allItemsWidth - 3 * this.width > 0 - } - - // #3 Top view - Button - { - iconSource: UM.Theme.getIcon("view_top") - style: UM.Theme.styles.small_tool_button - anchors.verticalCenter: viewOrientationControl.verticalCenter - onClicked: UM.Controller.rotateView("y", 90) - visible: base.width - allItemsWidth - 2 * this.width > 0 - } - - // #4 Left view - Button - { - iconSource: UM.Theme.getIcon("view_left") - style: UM.Theme.styles.small_tool_button - anchors.verticalCenter: viewOrientationControl.verticalCenter - onClicked: UM.Controller.rotateView("x", 90) - visible: base.width - allItemsWidth - 1 * this.width > 0 - } - - // #5 Right view - Button - { - iconSource: UM.Theme.getIcon("view_right") - style: UM.Theme.styles.small_tool_button - anchors.verticalCenter: viewOrientationControl.verticalCenter - onClicked: UM.Controller.rotateView("x", -90) - visible: base.width - allItemsWidth > 0 - } - } - - ComboBox - { - id: viewModeButton - - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: rightMargin - } - - style: UM.Theme.styles.combobox - visible: UM.Controller.activeStage.stageId != "MonitorStage" - - model: UM.ViewModel { } - textRole: "name" - - // update the model's active index - function updateItemActiveFlags () { - currentIndex = getActiveIndex() - for (var i = 0; i < model.rowCount(); i++) { - model.getItem(i).active = (i == currentIndex) - } - } - - // get the index of the active model item on start - function getActiveIndex () { - for (var i = 0; i < model.rowCount(); i++) { - if (model.getItem(i).active) { - return i - } - } - return 0 - } - - // set the active index - function setActiveIndex (index) { - UM.Controller.setActiveView(index) - // the connection to UM.ActiveView will trigger update so there is no reason to call it manually here - } - - onCurrentIndexChanged: - { - if (model.getItem(currentIndex).id != undefined) - viewModeButton.setActiveIndex(model.getItem(currentIndex).id) - } - currentIndex: getActiveIndex() - - // watch the active view proxy for changes made from the menu item - Connections - { - target: UM.ActiveView - onActiveViewChanged: viewModeButton.updateItemActiveFlags() - } - } - - Loader - { - id: view_panel - - anchors.top: viewModeButton.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height - anchors.right: viewModeButton.right - - property var buttonTarget: Qt.point(viewModeButton.x + Math.round(viewModeButton.width / 2), viewModeButton.y + Math.round(viewModeButton.height / 2)) - - height: childrenRect.height - width: childrenRect.width - - source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : ""; - } - - // Expand or collapse sidebar - Connections - { - target: Cura.Actions.expandSidebar - onTriggered: updateMarginsAndSizes() - } - - Component.onCompleted: - { - updateMarginsAndSizes(); - } - -} diff --git a/resources/qml/ViewOrientationButton.qml b/resources/qml/ViewOrientationButton.qml new file mode 100644 index 0000000000..5d72de9a8d --- /dev/null +++ b/resources/qml/ViewOrientationButton.qml @@ -0,0 +1,15 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.2 + +import UM 1.4 as UM + +UM.SimpleButton +{ + width: UM.Theme.getSize("small_button").width + height: UM.Theme.getSize("small_button").height + hoverColor: UM.Theme.getColor("small_button_text_hover") + color: UM.Theme.getColor("small_button_text") + iconMargin: UM.Theme.getSize("thick_lining").width +} \ No newline at end of file diff --git a/resources/qml/ViewOrientationControls.qml b/resources/qml/ViewOrientationControls.qml new file mode 100644 index 0000000000..51ed6e3dcb --- /dev/null +++ b/resources/qml/ViewOrientationControls.qml @@ -0,0 +1,48 @@ +// 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 UM 1.4 as UM + +// A row of buttons that control the view direction +Row +{ + id: viewOrientationControl + + spacing: UM.Theme.getSize("narrow_margin").width + height: childrenRect.height + width: childrenRect.width + + ViewOrientationButton + { + iconSource: UM.Theme.getIcon("view_3d") + onClicked: UM.Controller.rotateView("3d", 0) + } + + ViewOrientationButton + { + iconSource: UM.Theme.getIcon("view_front") + onClicked: UM.Controller.rotateView("home", 0) + } + + ViewOrientationButton + { + iconSource: UM.Theme.getIcon("view_top") + onClicked: UM.Controller.rotateView("y", 90) + } + + ViewOrientationButton + { + iconSource: UM.Theme.getIcon("view_left") + onClicked: UM.Controller.rotateView("x", 90) + } + + ViewOrientationButton + { + iconSource: UM.Theme.getIcon("view_right") + onClicked: UM.Controller.rotateView("x", -90) + } +} diff --git a/resources/qml/ViewsSelector.qml b/resources/qml/ViewsSelector.qml new file mode 100644 index 0000000000..0e9be649db --- /dev/null +++ b/resources/qml/ViewsSelector.qml @@ -0,0 +1,133 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.2 as UM +import Cura 1.0 as Cura + +Cura.ExpandablePopup +{ + id: viewSelector + + contentPadding: UM.Theme.getSize("default_lining").width + contentAlignment: Cura.ExpandablePopup.ContentAlignment.AlignLeft + + property var viewModel: UM.ViewModel + { + onDataChanged: updateActiveView() + } + + property var activeView: null + + function updateActiveView() + { + for (var index in viewModel.items) + { + if (viewModel.items[index].active) + { + activeView = viewModel.items[index] + return + } + } + activeView = null + } + + Component.onCompleted: + { + if (activeView == null) + { + UM.Controller.setActiveView(viewModel.getItem(0).id) + } + } + + headerItem: Item + { + Label + { + id: title + text: catalog.i18nc("@label", "View types") + verticalAlignment: Text.AlignVCenter + height: parent.height + elide: Text.ElideRight + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text_medium") + renderType: Text.NativeRendering + } + + Label + { + text: viewSelector.activeView ? viewSelector.activeView.name : "" + verticalAlignment: Text.AlignVCenter + anchors + { + left: title.right + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + } + height: parent.height + elide: Text.ElideRight + font: UM.Theme.getFont("medium") + color: UM.Theme.getColor("text") + renderType: Text.NativeRendering + } + } + + contentItem: Column + { + id: viewSelectorPopup + width: viewSelector.width - 2 * viewSelector.contentPadding + + // For some reason the height/width of the column gets set to 0 if this is not set... + Component.onCompleted: + { + height = implicitHeight + width = viewSelector.width - 2 * viewSelector.contentPadding + } + + Repeater + { + id: viewsList + model: viewSelector.viewModel + + delegate: Button + { + id: viewsSelectorButton + text: model.name + width: parent.width - viewSelectorPopup.leftPadding - viewSelectorPopup.rightPadding + height: UM.Theme.getSize("action_button").height + leftPadding: UM.Theme.getSize("default_margin").width + rightPadding: UM.Theme.getSize("default_margin").width + checkable: true + checked: viewSelector.activeView != null ? viewSelector.activeView.id == id : false + + contentItem: Label + { + id: buttonText + text: viewsSelectorButton.text + color: UM.Theme.getColor("text") + font: UM.Theme.getFont("medium") + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + background: Rectangle + { + id: backgroundRect + color: viewsSelectorButton.hovered ? UM.Theme.getColor("action_button_hovered") : "transparent" + radius: UM.Theme.getSize("action_button_radius").width + border.width: UM.Theme.getSize("default_lining").width + border.color: viewsSelectorButton.checked ? UM.Theme.getColor("primary") : "transparent" + } + + onClicked: + { + toggleContent() + UM.Controller.setActiveView(id) + } + } + } + } +} \ No newline at end of file diff --git a/resources/qml/qmldir b/resources/qml/qmldir new file mode 100644 index 0000000000..62997cc27a --- /dev/null +++ b/resources/qml/qmldir @@ -0,0 +1,19 @@ +module Cura + +MachineSelector 1.0 MachineSelector.qml +CustomConfigurationSelector 1.0 CustomConfigurationSelector.qml +PrintSetupSelector 1.0 PrintSetupSelector.qml +ActionButton 1.0 ActionButton.qml +MaterialMenu 1.0 MaterialMenu.qml +NozzleMenu 1.0 NozzleMenu.qml +ActionPanelWidget 1.0 ActionPanelWidget.qml +IconWithText 1.0 IconWithText.qml +OutputDevicesActionButton 1.0 OutputDevicesActionButton.qml +ExpandableComponent 1.0 ExpandableComponent.qml +PrinterTypeLabel 1.0 PrinterTypeLabel.qml +ViewsSelector 1.0 ViewsSelector.qml +ToolbarButton 1.0 ToolbarButton.qml +SettingView 1.0 SettingView.qml +ProfileMenu 1.0 ProfileMenu.qml +CheckBoxWithTooltip 1.0 CheckBoxWithTooltip.qml +ToolTip 1.0 ToolTip.qml diff --git a/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg b/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg index 1d406e4387..1ca2674e1f 100644 --- a/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg +++ b/resources/quality/abax_pri3/apri3_pla_fast.inst.cfg @@ -4,10 +4,10 @@ name = Fine definition = abax_pri3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = -1 +weight = 0 material = generic_pla [values] diff --git a/resources/quality/abax_pri3/apri3_pla_high.inst.cfg b/resources/quality/abax_pri3/apri3_pla_high.inst.cfg index 20d2c024aa..e9e8d53a03 100644 --- a/resources/quality/abax_pri3/apri3_pla_high.inst.cfg +++ b/resources/quality/abax_pri3/apri3_pla_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = abax_pri3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/abax_pri3/apri3_pla_normal.inst.cfg b/resources/quality/abax_pri3/apri3_pla_normal.inst.cfg index 0a4d1f1c62..40399c9548 100644 --- a/resources/quality/abax_pri3/apri3_pla_normal.inst.cfg +++ b/resources/quality/abax_pri3/apri3_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = abax_pri3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg b/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg index 6d0fdd40d2..c6d20f70da 100644 --- a/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg +++ b/resources/quality/abax_pri5/apri5_pla_fast.inst.cfg @@ -4,10 +4,10 @@ name = Fine definition = abax_pri5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = -1 +weight = 0 material = generic_pla [values] diff --git a/resources/quality/abax_pri5/apri5_pla_high.inst.cfg b/resources/quality/abax_pri5/apri5_pla_high.inst.cfg index 212c92e7d1..99bd10d654 100644 --- a/resources/quality/abax_pri5/apri5_pla_high.inst.cfg +++ b/resources/quality/abax_pri5/apri5_pla_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = abax_pri5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/abax_pri5/apri5_pla_normal.inst.cfg b/resources/quality/abax_pri5/apri5_pla_normal.inst.cfg index 8a1338f28c..55e0a7755a 100644 --- a/resources/quality/abax_pri5/apri5_pla_normal.inst.cfg +++ b/resources/quality/abax_pri5/apri5_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = abax_pri5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/abax_titan/atitan_pla_fast.inst.cfg b/resources/quality/abax_titan/atitan_pla_fast.inst.cfg index 71740ede84..6a2a49b555 100644 --- a/resources/quality/abax_titan/atitan_pla_fast.inst.cfg +++ b/resources/quality/abax_titan/atitan_pla_fast.inst.cfg @@ -4,10 +4,10 @@ name = Fine definition = abax_titan [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = -1 +weight = 0 material = generic_pla [values] diff --git a/resources/quality/abax_titan/atitan_pla_high.inst.cfg b/resources/quality/abax_titan/atitan_pla_high.inst.cfg index 73cd31f3fd..7dd5833297 100644 --- a/resources/quality/abax_titan/atitan_pla_high.inst.cfg +++ b/resources/quality/abax_titan/atitan_pla_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = abax_titan [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/abax_titan/atitan_pla_normal.inst.cfg b/resources/quality/abax_titan/atitan_pla_normal.inst.cfg index c356e197ce..b6aae46c6d 100644 --- a/resources/quality/abax_titan/atitan_pla_normal.inst.cfg +++ b/resources/quality/abax_titan/atitan_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = abax_titan [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/anycubic_4max/abs/anycubic_4max_abs_draft.inst.cfg b/resources/quality/anycubic_4max/abs/anycubic_4max_abs_draft.inst.cfg index f5baa55029..e12954b6bc 100644 --- a/resources/quality/anycubic_4max/abs/anycubic_4max_abs_draft.inst.cfg +++ b/resources/quality/anycubic_4max/abs/anycubic_4max_abs_draft.inst.cfg @@ -4,10 +4,10 @@ name = Draft definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 material = generic_abs [values] diff --git a/resources/quality/anycubic_4max/abs/anycubic_4max_abs_high.inst.cfg b/resources/quality/anycubic_4max/abs/anycubic_4max_abs_high.inst.cfg index bd613c6aad..0218b87a63 100644 --- a/resources/quality/anycubic_4max/abs/anycubic_4max_abs_high.inst.cfg +++ b/resources/quality/anycubic_4max/abs/anycubic_4max_abs_high.inst.cfg @@ -4,10 +4,10 @@ name = High definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 2 +weight = 1 material = generic_abs [values] diff --git a/resources/quality/anycubic_4max/abs/anycubic_4max_abs_normal.inst.cfg b/resources/quality/anycubic_4max/abs/anycubic_4max_abs_normal.inst.cfg index 7cff1db4d2..f686855364 100644 --- a/resources/quality/anycubic_4max/abs/anycubic_4max_abs_normal.inst.cfg +++ b/resources/quality/anycubic_4max/abs/anycubic_4max_abs_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 1 +weight = 0 material = generic_abs [values] diff --git a/resources/quality/anycubic_4max/anycubic_4max_draft.inst.cfg b/resources/quality/anycubic_4max/anycubic_4max_draft.inst.cfg index c0114e3d6c..d9dc632c16 100644 --- a/resources/quality/anycubic_4max/anycubic_4max_draft.inst.cfg +++ b/resources/quality/anycubic_4max/anycubic_4max_draft.inst.cfg @@ -4,10 +4,10 @@ name = Draft definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 global_quality = True [values] diff --git a/resources/quality/anycubic_4max/anycubic_4max_high.inst.cfg b/resources/quality/anycubic_4max/anycubic_4max_high.inst.cfg index 4a0993412a..55b5833c3f 100644 --- a/resources/quality/anycubic_4max/anycubic_4max_high.inst.cfg +++ b/resources/quality/anycubic_4max/anycubic_4max_high.inst.cfg @@ -4,10 +4,10 @@ name = High definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 2 +weight = 1 global_quality = True [values] diff --git a/resources/quality/anycubic_4max/anycubic_4max_normal.inst.cfg b/resources/quality/anycubic_4max/anycubic_4max_normal.inst.cfg index eeb1d699e4..45c6f19f8b 100644 --- a/resources/quality/anycubic_4max/anycubic_4max_normal.inst.cfg +++ b/resources/quality/anycubic_4max/anycubic_4max_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 1 +weight = 0 global_quality = True [values] diff --git a/resources/quality/anycubic_4max/hips/anycubic_4max_hips_draft.inst.cfg b/resources/quality/anycubic_4max/hips/anycubic_4max_hips_draft.inst.cfg index 3cd0226bd4..97c19b7083 100644 --- a/resources/quality/anycubic_4max/hips/anycubic_4max_hips_draft.inst.cfg +++ b/resources/quality/anycubic_4max/hips/anycubic_4max_hips_draft.inst.cfg @@ -4,10 +4,10 @@ name = Draft definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 material = generic_hips [values] diff --git a/resources/quality/anycubic_4max/hips/anycubic_4max_hips_high.inst.cfg b/resources/quality/anycubic_4max/hips/anycubic_4max_hips_high.inst.cfg index ff5c6bee2f..cfa727bcb8 100644 --- a/resources/quality/anycubic_4max/hips/anycubic_4max_hips_high.inst.cfg +++ b/resources/quality/anycubic_4max/hips/anycubic_4max_hips_high.inst.cfg @@ -4,10 +4,10 @@ name = High definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 2 +weight = 1 material = generic_hips [values] diff --git a/resources/quality/anycubic_4max/hips/anycubic_4max_hips_normal.inst.cfg b/resources/quality/anycubic_4max/hips/anycubic_4max_hips_normal.inst.cfg index c4701ae246..f4372939f5 100644 --- a/resources/quality/anycubic_4max/hips/anycubic_4max_hips_normal.inst.cfg +++ b/resources/quality/anycubic_4max/hips/anycubic_4max_hips_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 1 +weight = 0 material = generic_hips [values] diff --git a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_draft.inst.cfg b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_draft.inst.cfg index 5e0c3e204a..124bd487b0 100644 --- a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_draft.inst.cfg +++ b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_draft.inst.cfg @@ -4,10 +4,10 @@ name = Draft definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 material = generic_petg [values] diff --git a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_high.inst.cfg b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_high.inst.cfg index 57a89c4ec2..eeaaac6270 100644 --- a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_high.inst.cfg +++ b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_high.inst.cfg @@ -4,10 +4,10 @@ name = High definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 2 +weight = 1 material = generic_petg [values] diff --git a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_normal.inst.cfg b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_normal.inst.cfg index 14a4607ceb..ec0579015a 100644 --- a/resources/quality/anycubic_4max/petg/anycubic_4max_petg_normal.inst.cfg +++ b/resources/quality/anycubic_4max/petg/anycubic_4max_petg_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 1 +weight = 0 material = generic_petg [values] diff --git a/resources/quality/anycubic_4max/pla/anycubic_4max_pla_draft.inst.cfg b/resources/quality/anycubic_4max/pla/anycubic_4max_pla_draft.inst.cfg index eae9e3b5ef..b72ce43e29 100644 --- a/resources/quality/anycubic_4max/pla/anycubic_4max_pla_draft.inst.cfg +++ b/resources/quality/anycubic_4max/pla/anycubic_4max_pla_draft.inst.cfg @@ -4,10 +4,10 @@ name = Draft definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 material = generic_pla [values] diff --git a/resources/quality/anycubic_4max/pla/anycubic_4max_pla_high.inst.cfg b/resources/quality/anycubic_4max/pla/anycubic_4max_pla_high.inst.cfg index c856fc66a7..4386159a66 100644 --- a/resources/quality/anycubic_4max/pla/anycubic_4max_pla_high.inst.cfg +++ b/resources/quality/anycubic_4max/pla/anycubic_4max_pla_high.inst.cfg @@ -4,10 +4,10 @@ name = High definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 2 +weight = 1 material = generic_pla [values] diff --git a/resources/quality/anycubic_4max/pla/anycubic_4max_pla_normal.inst.cfg b/resources/quality/anycubic_4max/pla/anycubic_4max_pla_normal.inst.cfg index be33bfe53a..9998fff2ad 100644 --- a/resources/quality/anycubic_4max/pla/anycubic_4max_pla_normal.inst.cfg +++ b/resources/quality/anycubic_4max/pla/anycubic_4max_pla_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = anycubic_4max [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 1 +weight = 0 material = generic_pla [values] diff --git a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg index bb47f68574..ba99d30de6 100644 --- a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg +++ b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_draft.inst.cfg @@ -4,10 +4,11 @@ name = Draft definition = anycubic_i3_mega [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 +global_quality = True [values] acceleration_enabled = True diff --git a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg index a3ae98deba..b1092b115c 100644 --- a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg +++ b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_high.inst.cfg @@ -4,10 +4,11 @@ name = High definition = anycubic_i3_mega [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 2 +weight = 1 +global_quality = True [values] acceleration_enabled = True diff --git a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg index 13846b9702..d088d650a0 100644 --- a/resources/quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg +++ b/resources/quality/anycubic_i3_mega/anycubic_i3_mega_normal.inst.cfg @@ -4,10 +4,11 @@ name = Normal definition = anycubic_i3_mega [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 1 +weight = 0 +global_quality = True [values] acceleration_enabled = True diff --git a/resources/quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg index 10c8bc553f..491d24c919 100644 --- a/resources/quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_BVOH_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -1 diff --git a/resources/quality/builder_premium/bp_BVOH_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_BVOH_High_Quality.inst.cfg index b09ceb8872..3ff0f07ac1 100644 --- a/resources/quality/builder_premium/bp_BVOH_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_BVOH_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High Quality definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg index c2425a6d86..cf67185706 100644 --- a/resources/quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_BVOH_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg index 038fd02fff..aedb45a2b1 100644 --- a/resources/quality/builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_Innoflex60_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -1 diff --git a/resources/quality/builder_premium/bp_Innoflex60_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_Innoflex60_High_Quality.inst.cfg index e9512e30f8..08fb395a36 100644 --- a/resources/quality/builder_premium/bp_Innoflex60_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_Innoflex60_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High Quality definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg index fb6ec6c89f..008de91758 100644 --- a/resources/quality/builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_Innoflex60_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg index 572e83d4b3..0e2c26812b 100644 --- a/resources/quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PET_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -1 diff --git a/resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg index f4a45dd43a..8217ca9156 100644 --- a/resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PET_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High Quality definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/builder_premium/bp_PET_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_PET_Normal_Quality.inst.cfg index d927ab0851..48b2df0cae 100644 --- a/resources/quality/builder_premium/bp_PET_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PET_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg index fc877df05d..6834cbb2c4 100644 --- a/resources/quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PLA_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -1 diff --git a/resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg index 586133a500..9fc5426cf9 100644 --- a/resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PLA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High Quality definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg index e84b2eaa87..161bee24df 100644 --- a/resources/quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg index f661e58b6d..149b938bac 100644 --- a/resources/quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PVA_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -1 diff --git a/resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg index 31b9c094df..ba310a0890 100644 --- a/resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PVA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High Quality definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg index 8c3ca85124..4ab949957f 100644 --- a/resources/quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_PVA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/builder_premium/bp_global_Coarse_Quality.inst.cfg b/resources/quality/builder_premium/bp_global_Coarse_Quality.inst.cfg index a1d80774a1..9a85c924ee 100644 --- a/resources/quality/builder_premium/bp_global_Coarse_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_global_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -1 diff --git a/resources/quality/builder_premium/bp_global_High_Quality.inst.cfg b/resources/quality/builder_premium/bp_global_High_Quality.inst.cfg index 465ea6090a..ca2f8c843f 100644 --- a/resources/quality/builder_premium/bp_global_High_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_global_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High Quality definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/builder_premium/bp_global_Normal_Quality.inst.cfg b/resources/quality/builder_premium/bp_global_Normal_Quality.inst.cfg index e872561b90..3b24f9963d 100644 --- a/resources/quality/builder_premium/bp_global_Normal_Quality.inst.cfg +++ b/resources/quality/builder_premium/bp_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = builder_premium_small [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg index 5626ed58de..f19635331d 100644 --- a/resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.25_abs_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg index f74918ef4f..14babfa93d 100644 --- a/resources/quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.25_abs_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_abs variant = 0.25mm thermoplastic extruder diff --git a/resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg index d4dd85b09d..99e1290c77 100644 --- a/resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.4_abs_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg index ab72092035..32c306ba71 100644 --- a/resources/quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.4_abs_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_abs variant = 0.4mm thermoplastic extruder diff --git a/resources/quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg index d15efb770f..5496468fd6 100644 --- a/resources/quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.8_abs_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = 3 diff --git a/resources/quality/cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg index 7467da765f..360397ddc9 100644 --- a/resources/quality/cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.8_abs_extra_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = 4 diff --git a/resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg index caa6b71a4a..82e0afa853 100644 --- a/resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.8_abs_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg b/resources/quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg index 9eea2177a8..20ba9b777d 100644 --- a/resources/quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg +++ b/resources/quality/cartesio/abs/cartesio_0.8_abs_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_abs variant = 0.8mm thermoplastic extruder diff --git a/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg b/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg index 17f2acd8d1..fa89b4c3aa 100644 --- a/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg +++ b/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg b/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg index 8215eb2f50..63abbf1cc5 100644 --- a/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg +++ b/resources/quality/cartesio/arnitel/cartesio_0.4_arnitel2045_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = dsm_arnitel2045_175 variant = 0.4mm thermoplastic extruder diff --git a/resources/quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg b/resources/quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg index f92fc49981..7ce1111dd8 100644 --- a/resources/quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg +++ b/resources/quality/cartesio/cartesio_global_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -3 diff --git a/resources/quality/cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg b/resources/quality/cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg index 1681e83279..0369c74e2a 100644 --- a/resources/quality/cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg +++ b/resources/quality/cartesio/cartesio_global_Extra_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = -4 diff --git a/resources/quality/cartesio/cartesio_global_High_Quality.inst.cfg b/resources/quality/cartesio/cartesio_global_High_Quality.inst.cfg index 95d1f3b37e..dafe5ef621 100644 --- a/resources/quality/cartesio/cartesio_global_High_Quality.inst.cfg +++ b/resources/quality/cartesio/cartesio_global_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/cartesio_global_Normal_Quality.inst.cfg b/resources/quality/cartesio/cartesio_global_Normal_Quality.inst.cfg index 6bb348282e..100da3c70a 100644 --- a/resources/quality/cartesio/cartesio_global_Normal_Quality.inst.cfg +++ b/resources/quality/cartesio/cartesio_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg index 3e212b2446..93e04e1514 100644 --- a/resources/quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.25_hips_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg index 0cf82847a0..ba3f88ce13 100644 --- a/resources/quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.25_hips_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_hips variant = 0.25mm thermoplastic extruder diff --git a/resources/quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg index a9664cf9d1..91b1627650 100644 --- a/resources/quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.4_hips_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg index 8101fb6dd8..a2f817aef2 100644 --- a/resources/quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.4_hips_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_hips variant = 0.4mm thermoplastic extruder diff --git a/resources/quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg index f009383ad8..6b84c5e864 100644 --- a/resources/quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.8_hips_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = 3 diff --git a/resources/quality/cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg index 1adbbb0fb9..16f299813b 100644 --- a/resources/quality/cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.8_hips_extra_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = 4 diff --git a/resources/quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg index d3e6df227f..686759bc4d 100644 --- a/resources/quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.8_hips_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg b/resources/quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg index 0b019d555f..654564f291 100644 --- a/resources/quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg +++ b/resources/quality/cartesio/hips/cartesio_0.8_hips_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_hips variant = 0.8mm thermoplastic extruder diff --git a/resources/quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg index 9eb5d5c4e9..bd2dca940f 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.25_nylon_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg index e0100d37ec..55d22623bb 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.25_nylon_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_nylon variant = 0.25mm thermoplastic extruder diff --git a/resources/quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg index d4b261b99f..05e9abbe8f 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.4_nylon_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg index 7d899ae927..51327c844a 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.4_nylon_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_nylon variant = 0.4mm thermoplastic extruder diff --git a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg index 21e6d357b0..279e2d98bf 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = 3 diff --git a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg index 15128584e1..69f9a8caad 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_extra_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = 4 diff --git a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg index 1d78bd0f1d..ff4d152ef2 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg index 95be159ff2..f181244796 100644 --- a/resources/quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg +++ b/resources/quality/cartesio/nylon/cartesio_0.8_nylon_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_nylon variant = 0.8mm thermoplastic extruder diff --git a/resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg index c45194e18b..15c7f17451 100644 --- a/resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.25_pc_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg index 248517d769..91676e65f0 100644 --- a/resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.25_pc_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_pc variant = 0.25mm thermoplastic extruder diff --git a/resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg index 8c46693c91..73e1ff6bc5 100644 --- a/resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.4_pc_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg index a0b71f1f0a..d217756cb4 100644 --- a/resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.4_pc_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_pc variant = 0.4mm thermoplastic extruder diff --git a/resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg index 04f01db6ba..cba868e95e 100644 --- a/resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.8_pc_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = 3 diff --git a/resources/quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg index 53e21ec4d0..4aff24ed02 100644 --- a/resources/quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.8_pc_extra_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = 4 diff --git a/resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg index 0b2b9dcb26..f00e83f63e 100644 --- a/resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.8_pc_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg b/resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg index 173ad406f3..2f8ed80751 100644 --- a/resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg +++ b/resources/quality/cartesio/pc/cartesio_0.8_pc_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_pc variant = 0.8mm thermoplastic extruder diff --git a/resources/quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg index 9dc7adfc88..3c8dcc7af6 100644 --- a/resources/quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.25_petg_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg index 019af9d905..7aedc76af9 100644 --- a/resources/quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.25_petg_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_petg variant = 0.25mm thermoplastic extruder diff --git a/resources/quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg index 93388787e6..3788a4dd51 100644 --- a/resources/quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.4_petg_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg index ed17ccce31..4805ca55bb 100644 --- a/resources/quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.4_petg_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_petg variant = 0.4mm thermoplastic extruder diff --git a/resources/quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg index 754c55caf5..d7d6e35a3c 100644 --- a/resources/quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.8_petg_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = 3 diff --git a/resources/quality/cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg index 81b1de32a2..784bd0d6af 100644 --- a/resources/quality/cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.8_petg_extra_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = 4 diff --git a/resources/quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg index 86e93c8a32..bced328a9c 100644 --- a/resources/quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.8_petg_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg b/resources/quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg index 08f918f59b..2a9da4f164 100644 --- a/resources/quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg +++ b/resources/quality/cartesio/petg/cartesio_0.8_petg_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_petg variant = 0.8mm thermoplastic extruder diff --git a/resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg index 4841f9f368..15456a0b78 100644 --- a/resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.25_pla_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg index 3ba36f9436..bfa792f133 100644 --- a/resources/quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.25_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg index 7c785a750a..e64b67b59b 100644 --- a/resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.4_pla_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg index b24394daf0..704a974b63 100644 --- a/resources/quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.4_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg index 6443f2d526..b8ff99c256 100644 --- a/resources/quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.8_pla_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -3 diff --git a/resources/quality/cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg index 51a93f76d9..da613e6e1a 100644 --- a/resources/quality/cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.8_pla_extra_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = -4 diff --git a/resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg index 2f72d9d158..05c0f72686 100644 --- a/resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.8_pla_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg b/resources/quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg index 431f7c0fff..8434f4abc6 100644 --- a/resources/quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg +++ b/resources/quality/cartesio/pla/cartesio_0.8_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg index fe21c17e22..7df550917f 100644 --- a/resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.25_pva_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg index 6525991986..1f1d9549fb 100644 --- a/resources/quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.25_pva_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_pva variant = 0.25mm thermoplastic extruder diff --git a/resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg index cdf8f8cae7..faf1633ce2 100644 --- a/resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.4_pva_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg index e7267735e4..1dc24190c6 100644 --- a/resources/quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.4_pva_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_pva variant = 0.4mm thermoplastic extruder diff --git a/resources/quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg index fc35e14fc6..35b2d1690d 100644 --- a/resources/quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.8_pva_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = 3 diff --git a/resources/quality/cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg index 0e1b8b1241..3d41308a5d 100644 --- a/resources/quality/cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.8_pva_extra_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = 4 diff --git a/resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg index 249cf6485e..0293ee9acb 100644 --- a/resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.8_pva_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg b/resources/quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg index a6c0a89fcc..ae3d51a03f 100644 --- a/resources/quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg +++ b/resources/quality/cartesio/pva/cartesio_0.8_pva_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = cartesio [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_pva variant = 0.8mm thermoplastic extruder diff --git a/resources/quality/coarse.inst.cfg b/resources/quality/coarse.inst.cfg index e9b8156a70..77b9004aa6 100644 --- a/resources/quality/coarse.inst.cfg +++ b/resources/quality/coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = fdmprinter [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -3 diff --git a/resources/quality/dagoma/dagoma_discoeasy200_pla_fast.inst.cfg b/resources/quality/dagoma/dagoma_discoeasy200_pla_fast.inst.cfg index a302f5b513..b12a92dc1c 100644 --- a/resources/quality/dagoma/dagoma_discoeasy200_pla_fast.inst.cfg +++ b/resources/quality/dagoma/dagoma_discoeasy200_pla_fast.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = dagoma_discoeasy200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/dagoma/dagoma_discoeasy200_pla_fine.inst.cfg b/resources/quality/dagoma/dagoma_discoeasy200_pla_fine.inst.cfg index b26eb1d910..055b3e30d6 100644 --- a/resources/quality/dagoma/dagoma_discoeasy200_pla_fine.inst.cfg +++ b/resources/quality/dagoma/dagoma_discoeasy200_pla_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = dagoma_discoeasy200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/dagoma/dagoma_discoeasy200_pla_standard.inst.cfg b/resources/quality/dagoma/dagoma_discoeasy200_pla_standard.inst.cfg index 9ec56f696a..7c244b3f18 100644 --- a/resources/quality/dagoma/dagoma_discoeasy200_pla_standard.inst.cfg +++ b/resources/quality/dagoma/dagoma_discoeasy200_pla_standard.inst.cfg @@ -4,7 +4,7 @@ name = Standard definition = dagoma_discoeasy200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/dagoma/dagoma_global_fast.inst.cfg b/resources/quality/dagoma/dagoma_global_fast.inst.cfg index 28569387f2..f0d312e0a7 100644 --- a/resources/quality/dagoma/dagoma_global_fast.inst.cfg +++ b/resources/quality/dagoma/dagoma_global_fast.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = dagoma_discoeasy200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/dagoma/dagoma_global_fine.inst.cfg b/resources/quality/dagoma/dagoma_global_fine.inst.cfg index 1f7d577c1b..bf0a173ec3 100644 --- a/resources/quality/dagoma/dagoma_global_fine.inst.cfg +++ b/resources/quality/dagoma/dagoma_global_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = dagoma_discoeasy200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/dagoma/dagoma_global_standard.inst.cfg b/resources/quality/dagoma/dagoma_global_standard.inst.cfg index 167062c1d7..afeb925e96 100644 --- a/resources/quality/dagoma/dagoma_global_standard.inst.cfg +++ b/resources/quality/dagoma/dagoma_global_standard.inst.cfg @@ -4,7 +4,7 @@ name = Standard definition = dagoma_discoeasy200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/dagoma/dagoma_magis_pla_fast.inst.cfg b/resources/quality/dagoma/dagoma_magis_pla_fast.inst.cfg index d87c913eb6..8387ff2401 100644 --- a/resources/quality/dagoma/dagoma_magis_pla_fast.inst.cfg +++ b/resources/quality/dagoma/dagoma_magis_pla_fast.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = dagoma_magis [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/dagoma/dagoma_magis_pla_fine.inst.cfg b/resources/quality/dagoma/dagoma_magis_pla_fine.inst.cfg index d046726e0e..60c0cae7ec 100644 --- a/resources/quality/dagoma/dagoma_magis_pla_fine.inst.cfg +++ b/resources/quality/dagoma/dagoma_magis_pla_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = dagoma_magis [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/dagoma/dagoma_magis_pla_standard.inst.cfg b/resources/quality/dagoma/dagoma_magis_pla_standard.inst.cfg index 39961ea93b..b406d43cb1 100644 --- a/resources/quality/dagoma/dagoma_magis_pla_standard.inst.cfg +++ b/resources/quality/dagoma/dagoma_magis_pla_standard.inst.cfg @@ -4,7 +4,7 @@ name = Standard definition = dagoma_magis [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/dagoma/dagoma_neva_pla_fast.inst.cfg b/resources/quality/dagoma/dagoma_neva_pla_fast.inst.cfg index efdf2f7d32..c0e8d7fe94 100644 --- a/resources/quality/dagoma/dagoma_neva_pla_fast.inst.cfg +++ b/resources/quality/dagoma/dagoma_neva_pla_fast.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = dagoma_neva [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/dagoma/dagoma_neva_pla_fine.inst.cfg b/resources/quality/dagoma/dagoma_neva_pla_fine.inst.cfg index 50915db112..b6d6966c81 100644 --- a/resources/quality/dagoma/dagoma_neva_pla_fine.inst.cfg +++ b/resources/quality/dagoma/dagoma_neva_pla_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = dagoma_neva [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/dagoma/dagoma_neva_pla_standard.inst.cfg b/resources/quality/dagoma/dagoma_neva_pla_standard.inst.cfg index ed67800eac..eff587c908 100644 --- a/resources/quality/dagoma/dagoma_neva_pla_standard.inst.cfg +++ b/resources/quality/dagoma/dagoma_neva_pla_standard.inst.cfg @@ -4,7 +4,7 @@ name = Standard definition = dagoma_neva [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/deltacomb/deltacomb_abs_Draft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_Draft_Quality.inst.cfg index f540400575..9316a84175 100644 --- a/resources/quality/deltacomb/deltacomb_abs_Draft_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fast (beta) definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/deltacomb/deltacomb_abs_Fast_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_Fast_Quality.inst.cfg index 2214813913..a2c67ff890 100644 --- a/resources/quality/deltacomb/deltacomb_abs_Fast_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal (beta) definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/deltacomb/deltacomb_abs_High_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_High_Quality.inst.cfg index c196209553..be428bb8f4 100644 --- a/resources/quality/deltacomb/deltacomb_abs_High_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_High_Quality.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fine (beta) definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 material = generic_abs [values] diff --git a/resources/quality/deltacomb/deltacomb_abs_Normal_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_Normal_Quality.inst.cfg index 332e1890c6..1f4184f3ad 100644 --- a/resources/quality/deltacomb/deltacomb_abs_Normal_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine (beta) definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/deltacomb/deltacomb_abs_Verydraft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_abs_Verydraft_Quality.inst.cfg index 674174c0bd..37925e0e4c 100644 --- a/resources/quality/deltacomb/deltacomb_abs_Verydraft_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_abs_Verydraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast (beta) definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/deltacomb/deltacomb_global_Draft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_Draft_Quality.inst.cfg index f8887810d5..072f0435f6 100755 --- a/resources/quality/deltacomb/deltacomb_global_Draft_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_global_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/deltacomb/deltacomb_global_Fast_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_Fast_Quality.inst.cfg index 99030a084b..eef96e35b8 100755 --- a/resources/quality/deltacomb/deltacomb_global_Fast_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_global_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/deltacomb/deltacomb_global_High_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_High_Quality.inst.cfg index d6d853466a..becd10ea65 100755 --- a/resources/quality/deltacomb/deltacomb_global_High_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_global_High_Quality.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fine definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 global_quality = True [values] diff --git a/resources/quality/deltacomb/deltacomb_global_Normal_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_Normal_Quality.inst.cfg index a3bafadeec..4c95c74cfa 100755 --- a/resources/quality/deltacomb/deltacomb_global_Normal_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/deltacomb/deltacomb_global_Verydraft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_global_Verydraft_Quality.inst.cfg index 84c6e66f61..0ba6ca588f 100755 --- a/resources/quality/deltacomb/deltacomb_global_Verydraft_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_global_Verydraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/deltacomb/deltacomb_pla_Draft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_Draft_Quality.inst.cfg index c4f884486e..e0e695570d 100644 --- a/resources/quality/deltacomb/deltacomb_pla_Draft_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/deltacomb/deltacomb_pla_Fast_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_Fast_Quality.inst.cfg index 714d4e3517..3f43871a8f 100644 --- a/resources/quality/deltacomb/deltacomb_pla_Fast_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/deltacomb/deltacomb_pla_High_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_High_Quality.inst.cfg index 774b8969c0..b3924431af 100644 --- a/resources/quality/deltacomb/deltacomb_pla_High_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_High_Quality.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fine definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 material = generic_pla [values] diff --git a/resources/quality/deltacomb/deltacomb_pla_Normal_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_Normal_Quality.inst.cfg index 58470ed650..98ec4f46cd 100644 --- a/resources/quality/deltacomb/deltacomb_pla_Normal_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/deltacomb/deltacomb_pla_Verydraft_Quality.inst.cfg b/resources/quality/deltacomb/deltacomb_pla_Verydraft_Quality.inst.cfg index 9c00877c24..f67a2d8a26 100644 --- a/resources/quality/deltacomb/deltacomb_pla_Verydraft_Quality.inst.cfg +++ b/resources/quality/deltacomb/deltacomb_pla_Verydraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = deltacomb [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/draft.inst.cfg b/resources/quality/draft.inst.cfg index ac1d9ec52f..a605b9c83c 100644 --- a/resources/quality/draft.inst.cfg +++ b/resources/quality/draft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = fdmprinter [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/extra_coarse.inst.cfg b/resources/quality/extra_coarse.inst.cfg index 2a1a203d22..bf22b7ac3c 100644 --- a/resources/quality/extra_coarse.inst.cfg +++ b/resources/quality/extra_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse definition = fdmprinter [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = -4 diff --git a/resources/quality/extra_fast.inst.cfg b/resources/quality/extra_fast.inst.cfg index da890f1653..eb1e7b3a42 100644 --- a/resources/quality/extra_fast.inst.cfg +++ b/resources/quality/extra_fast.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = fdmprinter [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg b/resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg index 95e8b93b36..036d49a94f 100644 --- a/resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_abs_fast.inst.cfg @@ -4,7 +4,7 @@ definition = fabtotum name = Fast Quality [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/fabtotum/fabtotum_abs_high.inst.cfg b/resources/quality/fabtotum/fabtotum_abs_high.inst.cfg index baedf0ed2b..f3d6f33952 100644 --- a/resources/quality/fabtotum/fabtotum_abs_high.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_abs_high.inst.cfg @@ -4,7 +4,7 @@ definition = fabtotum name = High Quality [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg b/resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg index 58933486ee..d01599a392 100644 --- a/resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_abs_normal.inst.cfg @@ -4,7 +4,7 @@ definition = fabtotum name = Normal Quality [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg b/resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg index 00f0737227..1f0c050126 100644 --- a/resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_nylon_fast.inst.cfg @@ -4,7 +4,7 @@ name = Fast Quality definition = fabtotum [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg b/resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg index bd7f32c9ba..4e234f62f8 100644 --- a/resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_nylon_high.inst.cfg @@ -4,7 +4,7 @@ name = High Quality definition = fabtotum [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg b/resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg index 6a450e7ffe..67998dea38 100644 --- a/resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_nylon_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal Quality definition = fabtotum [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg b/resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg index afac0b0884..e27477e8de 100644 --- a/resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_pla_fast.inst.cfg @@ -4,7 +4,7 @@ definition = fabtotum name = Fast Quality [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/fabtotum/fabtotum_pla_high.inst.cfg b/resources/quality/fabtotum/fabtotum_pla_high.inst.cfg index 89dc6d9b33..bab6d5fc82 100644 --- a/resources/quality/fabtotum/fabtotum_pla_high.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_pla_high.inst.cfg @@ -4,7 +4,7 @@ definition = fabtotum name = High Quality [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg b/resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg index e5496a13d4..7bd3bc024e 100644 --- a/resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_pla_normal.inst.cfg @@ -4,7 +4,7 @@ definition = fabtotum name = Normal Quality [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg b/resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg index 7917c92514..5668d4a5b9 100644 --- a/resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_tpu_fast.inst.cfg @@ -5,7 +5,7 @@ name = Fast Quality [metadata] type = quality -setting_version = 5 +setting_version = 6 material = generic_tpu quality_type = fast weight = -1 diff --git a/resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg b/resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg index 1c31967d79..6af9e88f00 100644 --- a/resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_tpu_high.inst.cfg @@ -5,7 +5,7 @@ name = High Quality [metadata] type = quality -setting_version = 5 +setting_version = 6 material = generic_tpu quality_type = high weight = 1 diff --git a/resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg b/resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg index 0a3821f953..13faf5bc2f 100644 --- a/resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg +++ b/resources/quality/fabtotum/fabtotum_tpu_normal.inst.cfg @@ -5,7 +5,7 @@ name = Normal Quality [metadata] type = quality -setting_version = 5 +setting_version = 6 material = generic_tpu quality_type = normal weight = 0 diff --git a/resources/quality/fast.inst.cfg b/resources/quality/fast.inst.cfg index 7568c42e8f..94a7961320 100644 --- a/resources/quality/fast.inst.cfg +++ b/resources/quality/fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = fdmprinter [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/gmax15plus/gmax15plus_pla_dual_normal.inst.cfg b/resources/quality/gmax15plus/gmax15plus_global_dual_normal.inst.cfg similarity index 96% rename from resources/quality/gmax15plus/gmax15plus_pla_dual_normal.inst.cfg rename to resources/quality/gmax15plus/gmax15plus_global_dual_normal.inst.cfg index 7fd2ab2296..3c9c9c0dfd 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_dual_normal.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_global_dual_normal.inst.cfg @@ -4,10 +4,11 @@ name = gMax 1.5+ Dual Normal Layers definition = gmax15plus_dual [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = -1 +weight = 0 +global_quality = True [values] layer_height = 0.2 @@ -64,7 +65,6 @@ ooze_shield_enabled = True prime_tower_enable = False prime_tower_position_x = 350 prime_tower_position_y = 350 -prime_tower_min_volume = 18 switch_extruder_retraction_amount = 6 switch_extruder_retraction_speeds = 60 diff --git a/resources/quality/gmax15plus/gmax15plus_pla_dual_thick.inst.cfg b/resources/quality/gmax15plus/gmax15plus_global_dual_thick.inst.cfg similarity index 96% rename from resources/quality/gmax15plus/gmax15plus_pla_dual_thick.inst.cfg rename to resources/quality/gmax15plus/gmax15plus_global_dual_thick.inst.cfg index 30a99ef243..24740362af 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_dual_thick.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_global_dual_thick.inst.cfg @@ -4,10 +4,11 @@ name = gMax 1.5+ Dual Thick Layers definition = gmax15plus_dual [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = course weight = -2 +global_quality = True [values] layer_height = 0.28 @@ -64,7 +65,6 @@ ooze_shield_enabled = True prime_tower_enable = False prime_tower_position_x = 350 prime_tower_position_y = 350 -prime_tower_min_volume = 18 switch_extruder_retraction_amount = 6 switch_extruder_retraction_speeds = 60 diff --git a/resources/quality/gmax15plus/gmax15plus_pla_dual_thin.inst.cfg b/resources/quality/gmax15plus/gmax15plus_global_dual_thin.inst.cfg similarity index 96% rename from resources/quality/gmax15plus/gmax15plus_pla_dual_thin.inst.cfg rename to resources/quality/gmax15plus/gmax15plus_global_dual_thin.inst.cfg index decafac241..845a1c2c39 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_dual_thin.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_global_dual_thin.inst.cfg @@ -4,10 +4,11 @@ name = gMax 1.5+ Dual Thin Layers definition = gmax15plus_dual [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 +global_quality = True [values] layer_height = 0.16 @@ -64,7 +65,6 @@ ooze_shield_enabled = True prime_tower_enable = False prime_tower_position_x = 350 prime_tower_position_y = 350 -prime_tower_min_volume = 18 switch_extruder_retraction_amount = 6 switch_extruder_retraction_speeds = 60 diff --git a/resources/quality/gmax15plus/gmax15plus_pla_dual_very_thick.inst.cfg b/resources/quality/gmax15plus/gmax15plus_global_dual_very_thick.inst.cfg similarity index 96% rename from resources/quality/gmax15plus/gmax15plus_pla_dual_very_thick.inst.cfg rename to resources/quality/gmax15plus/gmax15plus_global_dual_very_thick.inst.cfg index a74bdfdd78..4dbd81255a 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_dual_very_thick.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_global_dual_very_thick.inst.cfg @@ -4,10 +4,11 @@ name = gMax 1.5+ Dual Very Thick Layers definition = gmax15plus_dual [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra_course weight = -3 +global_quality = True [values] layer_height = 0.32 @@ -63,7 +64,6 @@ ooze_shield_enabled = True prime_tower_enable = False prime_tower_position_x = 350 prime_tower_position_y = 350 -prime_tower_min_volume = 18 switch_extruder_retraction_amount = 6 switch_extruder_retraction_speeds = 60 diff --git a/resources/quality/gmax15plus/gmax15plus_pla_normal.inst.cfg b/resources/quality/gmax15plus/gmax15plus_global_normal.inst.cfg similarity index 95% rename from resources/quality/gmax15plus/gmax15plus_pla_normal.inst.cfg rename to resources/quality/gmax15plus/gmax15plus_global_normal.inst.cfg index ddf5a4c491..8b91006184 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_normal.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_global_normal.inst.cfg @@ -4,10 +4,11 @@ name = gMax 1.5+ Normal Layers definition = gmax15plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = -1 +weight = 0 +global_quality = True [values] layer_height = 0.2 @@ -57,3 +58,5 @@ top_thickness = 1 bottom_layers = 2 wall_line_count = 2 z_seam_corner = z_seam_corner_none + + diff --git a/resources/quality/gmax15plus/gmax15plus_pla_thick.inst.cfg b/resources/quality/gmax15plus/gmax15plus_global_thick.inst.cfg similarity index 93% rename from resources/quality/gmax15plus/gmax15plus_pla_thick.inst.cfg rename to resources/quality/gmax15plus/gmax15plus_global_thick.inst.cfg index e6cb2b5854..c5ef9fdf83 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_thick.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_global_thick.inst.cfg @@ -4,10 +4,11 @@ name = gMax 1.5+ Thick Layers definition = gmax15plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = course weight = -2 +global_quality = True [values] layer_height = 0.28 @@ -56,4 +57,4 @@ top_layers = 3 top_thickness = 1 bottom_layers = 2 wall_line_count = 2 -z_seam_corner = z_seam_corner_none +z_seam_corner = z_seam_corner_none \ No newline at end of file diff --git a/resources/quality/gmax15plus/gmax15plus_pla_thin.inst.cfg b/resources/quality/gmax15plus/gmax15plus_global_thin.inst.cfg similarity index 92% rename from resources/quality/gmax15plus/gmax15plus_pla_thin.inst.cfg rename to resources/quality/gmax15plus/gmax15plus_global_thin.inst.cfg index d119539d32..b3a2ed8d82 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_thin.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_global_thin.inst.cfg @@ -4,10 +4,11 @@ name = gMax 1.5+ Thin Layers definition = gmax15plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 +global_quality = True [values] layer_height = 0.16 @@ -56,4 +57,4 @@ top_layers = 5 top_thickness = 1 bottom_layers = 3 wall_line_count = 2 -z_seam_corner = z_seam_corner_none +z_seam_corner = z_seam_corner_none \ No newline at end of file diff --git a/resources/quality/gmax15plus/gmax15plus_pla_very_thick.inst.cfg b/resources/quality/gmax15plus/gmax15plus_global_very_thick.inst.cfg similarity index 93% rename from resources/quality/gmax15plus/gmax15plus_pla_very_thick.inst.cfg rename to resources/quality/gmax15plus/gmax15plus_global_very_thick.inst.cfg index 884029a4ae..5ebcf5e12d 100644 --- a/resources/quality/gmax15plus/gmax15plus_pla_very_thick.inst.cfg +++ b/resources/quality/gmax15plus/gmax15plus_global_very_thick.inst.cfg @@ -4,10 +4,11 @@ name = gMax 1.5+ Very Thick Layers definition = gmax15plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra_course weight = -3 +global_quality = True [values] layer_height = 0.32 @@ -55,4 +56,4 @@ top_layers = 3 top_thickness = 1 bottom_layers = 2 wall_line_count = 2 -z_seam_corner = z_seam_corner_none +z_seam_corner = z_seam_corner_none \ No newline at end of file diff --git a/resources/quality/high.inst.cfg b/resources/quality/high.inst.cfg index 1b687bf5e4..2ef1aba9e1 100644 --- a/resources/quality/high.inst.cfg +++ b/resources/quality/high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = fdmprinter [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg b/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg index 6a50e24678..e299e675e0 100644 --- a/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg index 2c8a43874a..7123c6440a 100644 --- a/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_petg_0.4_coarse_2-fans.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg b/resources/quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg index 264c95c933..297531f989 100644 --- a/resources/quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_petg_0.4_medium.inst.cfg @@ -4,7 +4,7 @@ name = Medium definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg index dfdfc2458c..d15c4a3b2d 100644 --- a/resources/quality/imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_petg_0.4_medium_2-fans.inst.cfg @@ -4,7 +4,7 @@ name = Medium definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg index 68eec0c753..9ff4e6d49e 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg index 46f81d0c1a..88635bb56d 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_coarse_2-fans.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg index f614b7cc3c..89dcca901c 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg index 5525899ea7..c7fd702eeb 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_fine_2-fans.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg index 28b4307cea..7f030b53e2 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_medium.inst.cfg @@ -4,7 +4,7 @@ name = Medium definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg index 52a8594505..2759a24a8d 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_medium_2-fans.inst.cfg @@ -4,7 +4,7 @@ name = Medium definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg index bf3d409050..b74b9434b7 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine.inst.cfg @@ -4,7 +4,7 @@ name = UltraFine definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultrahigh weight = 2 diff --git a/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg b/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg index 676ea84825..21df5445ab 100644 --- a/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg +++ b/resources/quality/imade3d_jellybox/generic_pla_0.4_ultrafine_2-fans.inst.cfg @@ -4,7 +4,7 @@ name = UltraFine definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultrahigh weight = 2 diff --git a/resources/quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg b/resources/quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg index 819501c727..1c6ef69145 100644 --- a/resources/quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg +++ b/resources/quality/imade3d_jellybox/imade3d_jellybox_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg b/resources/quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg index 0f312aa62d..702c5182c9 100644 --- a/resources/quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg +++ b/resources/quality/imade3d_jellybox/imade3d_jellybox_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg b/resources/quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg index 25d0e65d74..87256a9af7 100644 --- a/resources/quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg +++ b/resources/quality/imade3d_jellybox/imade3d_jellybox_normal.inst.cfg @@ -4,7 +4,7 @@ name = Medium definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg b/resources/quality/imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg index ebe5ab620c..ffa7ed4550 100644 --- a/resources/quality/imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg +++ b/resources/quality/imade3d_jellybox/imade3d_jellybox_ultrafine.inst.cfg @@ -4,7 +4,7 @@ name = UltraFine definition = imade3d_jellybox [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultrahigh weight = 2 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg index edba5e79ce..e4b6411ef6 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_draft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -3 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg index 899af00b78..faeaee854d 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_extra_fine.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg index 9b7ae123df..1ee9821018 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg index 96888821e3..c47239ee4a 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_low.inst.cfg @@ -4,7 +4,7 @@ name = Low definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg index c8f27f6a8f..8eac1515ca 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_abs_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg index a121d921cc..e51e3f6cd8 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_draft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -3 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg index 211da57f0c..f3d9aa9409 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_extra_fine.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg index 5879a76012..92d1a98e2b 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg index 0b437327d8..3fa48b32a6 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_low.inst.cfg @@ -4,7 +4,7 @@ name = Low definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg index ca5ac5bd0e..277ddc7ec5 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_beta_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = kemiq_q2_beta [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg index cd6ee5356e..e73ff9b982 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_draft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = kemiq_q2_gama [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -3 diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg index 345fdc2f0d..0175eb8ffa 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_extra_fine.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = kemiq_q2_gama [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg index bafc8f0016..415fbef684 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_fine.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = kemiq_q2_gama [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg index c8aa72def2..94aa963911 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_low.inst.cfg @@ -4,7 +4,7 @@ name = Low definition = kemiq_q2_gama [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg index 62c43104e1..cc69216ecd 100644 --- a/resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg +++ b/resources/quality/kemiq_q2/kemiq_q2_gama_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = kemiq_q2_gama [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg index 5bb967b78a..d54f0071cd 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg index 30641b863a..bdd9a1ccb8 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg index 746b579c70..7a4722d599 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_high.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg index e4ab115bc5..4cd3f34466 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg index d8a7607c5c..bd349b6d72 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_superdraft.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg index 44cad5a198..a01282748b 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_thickerdraft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg index 995074f330..ac82e263a7 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_ultra.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg b/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg index 373908b2bd..5e3afcb633 100644 --- a/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg +++ b/resources/quality/malyan_m200/abs/malyan_m200_abs_verydraft.inst.cfg @@ -4,10 +4,10 @@ name = Low Detail Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 material = generic_abs [values] diff --git a/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg index e53aa86a94..aa1f30d0b3 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg index 4379d9fdcb..8cbbdac2e4 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg index a9a5720e14..a56a5771d8 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg index 96b982e86a..f24faf98f0 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg index 0550efd603..ff0d97b1cc 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_SuperDraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg index 9a0454fc75..623b48acff 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_ThickerDraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg index 76eaa3463f..ec04f9055b 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_Ultra_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg b/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg index 42c670920f..85b5d0df6b 100644 --- a/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg +++ b/resources/quality/malyan_m200/malyan_m200_global_VeryDraft_Quality.inst.cfg @@ -4,10 +4,10 @@ name = Low Detail Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 global_quality = True [values] diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg index 96144c193f..6f36402470 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg index f390034a1f..ff14d6a96e 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg index 693c6efc08..74ab347def 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_high.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg index 09c5c2b14d..0862f96460 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg index 0faec6b357..df50ebcc42 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_superdraft.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg index 988082f783..3697573e0e 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_thickerdraft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg index 4eb84672e7..c9858b63c7 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_ultra.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg b/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg index 2f33760afa..b88d57ab76 100644 --- a/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg +++ b/resources/quality/malyan_m200/petg/malyan_m200_petg_verydraft.inst.cfg @@ -4,8 +4,8 @@ name = Low Detail Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 material = generic_petg diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg index 9a26d1b2a1..7a3af8285a 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg index ef4d002ce3..f813e062dd 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg index 6ff347a7cc..5fe854ddab 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_high.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg index b6aa938b94..cce3508550 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg index 8a4b63691f..477256a933 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_superdraft.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg index 98a8363c85..1841b91d3d 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_thickerdraft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg index 5a334bd9c1..24717cda19 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_ultra.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg b/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg index 7d96a9f56d..9e638d67c5 100644 --- a/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg +++ b/resources/quality/malyan_m200/pla/malyan_m200_pla_verydraft.inst.cfg @@ -4,10 +4,10 @@ name = Low Detail Draft definition = malyan_m200 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 material = generic_pla [values] diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg index ef579a567e..e8959a1235 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg index 33296bf677..256eea1976 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg index e282847f14..6d0250121f 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_high.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg index 2979f574a4..88c12a38f0 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg index 2d4d3c7461..2eacd312f4 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_superdraft.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg index ed43dec3ae..4b311bcfed 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_thickerdraft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg index eb556fe862..e9857b76b3 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_ultra.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = 2 diff --git a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg index 279f58d64f..aa29220d34 100644 --- a/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/abs/monoprice_select_mini_v2_abs_verydraft.inst.cfg @@ -4,10 +4,10 @@ name = Low Detail Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 material = generic_abs [values] diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg index 1d81d7535e..add2590cce 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg index 6a5a041244..2feddbd32a 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg index 65925a1ea4..263bd8544c 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg index 0ac150c117..52e2ec79f3 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg index b02910cf12..dfbd2d4d3d 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_SuperDraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg index 46434555ad..f05617c4f0 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_ThickerDraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg index dfb4942b29..e6d835d683 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_Ultra_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg index 79d9c8abb9..f44b085be1 100644 --- a/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/monoprice_select_mini_v2_global_VeryDraft_Quality.inst.cfg @@ -4,10 +4,10 @@ name = Low Detail Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 global_quality = True [values] diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg index 4d7d1cd848..c7701b56d3 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg index 1a18df9651..dbe3b03148 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg index ac0ca29caa..4612b19638 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_high.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg index 32c5e33f0d..7b887afb8d 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg index 26f260f861..c696c71fd5 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_superdraft.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg index b5bcc7d455..c561bcda04 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_thickerdraft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg index 6fc41e34b6..e16e044708 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_ultra.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg index 8f568d3948..9bf829c778 100644 --- a/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/nylon/monoprice_select_mini_v2_nylon_verydraft.inst.cfg @@ -4,8 +4,8 @@ name = Low Detail Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 material = generic_nylon diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg index 76b210eba1..6cc27cd3e8 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg index 53a099f42d..95ef667be9 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg index 1a6193fbaf..c874fc5c42 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_high.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg index 72e94d1828..62fb4046aa 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg index 13914d07e7..e1c88805e7 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_superdraft.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg index d02a793b25..0cec8831bf 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_thickerdraft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg index 41b3821727..6aaf8680f5 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_ultra.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg index 23b72a3a3b..7a63b896c3 100644 --- a/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pc/monoprice_select_mini_v2_pc_verydraft.inst.cfg @@ -4,10 +4,10 @@ name = Low Detail Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 material = generic_pc [values] diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg index c2c8889127..4e31a46fbd 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg index 881311d395..e0d7d393c5 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg index f9f1e169cb..64451b0788 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_high.inst.cfg @@ -4,7 +4,7 @@ name = Finer definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg index 026279f012..1f5b6c956c 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg index 3ff71bf416..9b269ee95b 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_superdraft.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg index 5524ec59ea..e180b50a89 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_thickerdraft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg index 99d1da45c7..fe77254c56 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_ultra.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg index 99874f0571..9505b2b15b 100644 --- a/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/petg/monoprice_select_mini_v2_petg_verydraft.inst.cfg @@ -4,8 +4,8 @@ name = Low Detail Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -4 +weight = -3 material = generic_petg diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg index a64020a89e..8333cd10ac 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg index 994d6ff0fd..ab83dacbe8 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = 0 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg index 9f64ce57f0..13f31a614e 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_high.inst.cfg @@ -4,8 +4,8 @@ name = Finer definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 material = generic_pla diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg index afbc03d5af..57fb63fdea 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg index ec30cfe2b9..77c3a18b54 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_superdraft.inst.cfg @@ -4,7 +4,7 @@ name = Lowest Quality Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -5 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg index 916285385d..52b871217b 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_thickerdraft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = thickerdraft weight = -3 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg index 5d627b6d35..36ef492905 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_ultra.inst.cfg @@ -4,7 +4,7 @@ name = Ultra Fine definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = ultra weight = 2 diff --git a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg index 9f22fb3692..e1d636b2b1 100644 --- a/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg +++ b/resources/quality/monoprice_select_mini_v2/pla/monoprice_select_mini_v2_pla_verydraft.inst.cfg @@ -4,7 +4,7 @@ name = Low Detail Draft definition = monoprice_select_mini_v2 [metadata] -setting_version = 5 +setting_version = 6 type = quality material = generic_pla weight = 0 diff --git a/resources/quality/normal.inst.cfg b/resources/quality/normal.inst.cfg index f32c87bc60..02b9ebf621 100644 --- a/resources/quality/normal.inst.cfg +++ b/resources/quality/normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = fdmprinter [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg index ac4f9ee81d..9ca6cec759 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg @@ -4,7 +4,7 @@ name = Coarse definition = peopoly_moai [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = 3 diff --git a/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg index 2d21b1f7e0..72953e5305 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg @@ -4,10 +4,10 @@ name = Draft definition = peopoly_moai [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 4 +weight = -2 [values] layer_height = 0.1 diff --git a/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg index 796c2cff3c..30d41aa7f8 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra High definition = peopoly_moai [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra_high weight = 0 diff --git a/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg index b36163d9f1..37442ed20c 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = peopoly_moai [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg index cf67591ab2..33bb5673ae 100644 --- a/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg +++ b/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = peopoly_moai [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 [values] layer_height = 0.06 diff --git a/resources/quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg b/resources/quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg index be83533e0b..13f12ef643 100644 --- a/resources/quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg +++ b/resources/quality/tevo_blackwidow/tevo_blackwidow_draft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = tevo_blackwidow [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg b/resources/quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg index 5ca8a6e4ef..0f0ccf64c6 100644 --- a/resources/quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg +++ b/resources/quality/tevo_blackwidow/tevo_blackwidow_high.inst.cfg @@ -4,7 +4,7 @@ name = High definition = tevo_blackwidow [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg b/resources/quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg index f542952fab..ebd5997027 100644 --- a/resources/quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg +++ b/resources/quality/tevo_blackwidow/tevo_blackwidow_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = tevo_blackwidow [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/tizyx_k25/tizyx_k25_normal.inst.cfg b/resources/quality/tizyx_k25/tizyx_k25_normal.inst.cfg index 8b066f139f..f259ad1b34 100644 --- a/resources/quality/tizyx_k25/tizyx_k25_normal.inst.cfg +++ b/resources/quality/tizyx_k25/tizyx_k25_normal.inst.cfg @@ -5,7 +5,7 @@ definition = tizyx_k25 [metadata] quality_type = normal -setting_version = 5 +setting_version = 6 type = quality global_quality = True diff --git a/resources/quality/ultimaker2/um2_draft.inst.cfg b/resources/quality/ultimaker2/um2_draft.inst.cfg index 8c34d2c09d..7d38ba6bf4 100644 --- a/resources/quality/ultimaker2/um2_draft.inst.cfg +++ b/resources/quality/ultimaker2/um2_draft.inst.cfg @@ -4,7 +4,7 @@ name = Draft definition = ultimaker2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker2/um2_fast.inst.cfg b/resources/quality/ultimaker2/um2_fast.inst.cfg index 084ed05f92..39cd4da4ef 100644 --- a/resources/quality/ultimaker2/um2_fast.inst.cfg +++ b/resources/quality/ultimaker2/um2_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2/um2_high.inst.cfg b/resources/quality/ultimaker2/um2_high.inst.cfg index 83bb6bb972..142440d53e 100644 --- a/resources/quality/ultimaker2/um2_high.inst.cfg +++ b/resources/quality/ultimaker2/um2_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2/um2_normal.inst.cfg b/resources/quality/ultimaker2/um2_normal.inst.cfg index febee8581f..b5a87f07f3 100644 --- a/resources/quality/ultimaker2/um2_normal.inst.cfg +++ b/resources/quality/ultimaker2/um2_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg index ff830ae660..d27a136765 100644 --- a/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.25_normal.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg index 94ea62a7ca..5bc62e5fd0 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg index 03de437ee2..2847ab8c15 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg index 836d866eab..009fcf7877 100644 --- a/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.4_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg index de55623c0f..7c492f2ec0 100644 --- a/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.6_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg index c96260d52f..1b6cee0e1d 100644 --- a/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/pla_0.8_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg index 886daf58e2..f55567f986 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.25_normal.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg index b727acc510..63904632dc 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg index 20e217315b..f76efeb7b2 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg index 853a87c751..fd7dfc86a7 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.4_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg index 6d3ef94b9d..aba3222412 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.6_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg index 7b39ce966a..23618e2e1d 100644 --- a/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_abs_0.8_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg index eca5070eb9..db184abe54 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.25_normal.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = -1 +weight = 1 material = generic_cpe variant = 0.25 mm diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg index 1e181e23d1..2dc076b012 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg index 9ffb8a05bb..300d5242e2 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg index ee7101f2ec..17a9f1a579 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.4_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg index d2de84eae6..6807a1a86a 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.6_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg index 581dc0368d..7a15ed53ec 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpe_0.8_normal.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg index 7549c0081d..cc68478dd8 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.4_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg index b1e5552562..0d0e0e2043 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.4_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg index 616f13f110..e08a7fc357 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.6_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg index d28dc76af8..7c8589f09e 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.6_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg index 1c4fa746ad..1c42d28128 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.8_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg index e40d6efc58..072081e092 100644 --- a/resources/quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_cpep_0.8_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_global_Coarse_Quality.inst.cfg b/resources/quality/ultimaker2_plus/um2p_global_Coarse_Quality.inst.cfg index a10cb4030c..2a4fe17a24 100644 --- a/resources/quality/ultimaker2_plus/um2p_global_Coarse_Quality.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_global_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse Quality definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -4 diff --git a/resources/quality/ultimaker2_plus/um2p_global_Draft_Quality.inst.cfg b/resources/quality/ultimaker2_plus/um2p_global_Draft_Quality.inst.cfg index 5645bbee0b..bdf79827b2 100644 --- a/resources/quality/ultimaker2_plus/um2p_global_Draft_Quality.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_global_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Draft Quality definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker2_plus/um2p_global_Extra_Coarse_Quality.inst.cfg b/resources/quality/ultimaker2_plus/um2p_global_Extra_Coarse_Quality.inst.cfg index d9afc804ba..e5338c0e34 100644 --- a/resources/quality/ultimaker2_plus/um2p_global_Extra_Coarse_Quality.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_global_Extra_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse Quality definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = -3 diff --git a/resources/quality/ultimaker2_plus/um2p_global_Fast_Quality.inst.cfg b/resources/quality/ultimaker2_plus/um2p_global_Fast_Quality.inst.cfg index 7fd6d54c87..453def0668 100644 --- a/resources/quality/ultimaker2_plus/um2p_global_Fast_Quality.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_global_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_global_High_Quality.inst.cfg b/resources/quality/ultimaker2_plus/um2p_global_High_Quality.inst.cfg index ade183d14a..20b9e7ba16 100644 --- a/resources/quality/ultimaker2_plus/um2p_global_High_Quality.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_global_High_Quality.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 global_quality = True [values] diff --git a/resources/quality/ultimaker2_plus/um2p_global_Normal_Quality.inst.cfg b/resources/quality/ultimaker2_plus/um2p_global_Normal_Quality.inst.cfg index 76c7b8163c..c901687f22 100644 --- a/resources/quality/ultimaker2_plus/um2p_global_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg index 2cab693c74..512f9e499b 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.25_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg index f61a29a35a..ce607f7a83 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.25_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg index 341dc7422f..7b06d5205c 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.4_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg index 63bc156e15..b65f694e11 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.4_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg index 8aea23fb50..6caa1d2e82 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.6_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg index 28ccd6ffcf..3dad97297f 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.6_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg index f868313ba9..fe5749aeff 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.8_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg index c30d849553..3e16229ad1 100644 --- a/resources/quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_nylon_0.8_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg index 08b60eeb20..0195a6170f 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.25_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg index dbc36f0c25..fe15f050c7 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.25_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg index 18f299b64d..1268e4f5a5 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.4_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg index 9ebb46c4d3..31a55131bd 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.4_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg index 47f84fe790..a4b0e7865e 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.6_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg index 2c857435c5..9fef7be2f8 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.6_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg index 6450d9fe56..cfbd0795ab 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.8_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg index 91c990712e..fd24f29c40 100644 --- a/resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pc_0.8_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg index 4266bcd46b..8e320bef25 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.4_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg index b995c92922..94d7a22965 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.4_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg index a9e4917fa2..aee8437e39 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.6_draft.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg index 2fec539e2f..f1e709495b 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.6_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg index 2bba1be3d4..0e84d2c2e4 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.8_draft.inst.cfg @@ -4,10 +4,10 @@ name = Fast definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast -weight = -2 +weight = -1 material = generic_pp variant = 0.8 mm diff --git a/resources/quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg b/resources/quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg index 15f7577bdb..905c147e41 100644 --- a/resources/quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_pp_0.8_verydraft.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fast definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = -3 +weight = -2 material = generic_pp variant = 0.8 mm diff --git a/resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg b/resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg index e0c016abee..47bf078c2f 100644 --- a/resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_tpu_0.25_high.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg b/resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg index 127f281913..d8543f1f8a 100644 --- a/resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_tpu_0.4_normal.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg b/resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg index c39ea9cec3..1983878a79 100644 --- a/resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg +++ b/resources/quality/ultimaker2_plus/um2p_tpu_0.6_fast.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg index 5139a1fea8..dda9fd3891 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_ABS_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg index 4e81b4f39e..922366d716 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_CPE_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg index 04dc2ec79b..3535bc4cba 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_Nylon_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg index e08fa27dc9..f24c53aaee 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_PC_Normal_Quality.inst.cfg @@ -4,12 +4,13 @@ name = Fine - Experimental definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 material = generic_pc variant = AA 0.25 +is_experimental = True [values] acceleration_enabled = True diff --git a/resources/quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg index 8dbca3cd05..a59c404754 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_PLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg index 6e9bbdce27..6f9734511b 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_PP_Normal_Quality.inst.cfg @@ -4,12 +4,13 @@ name = Fine - Experimental definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 material = generic_pp variant = AA 0.25 +is_experimental = True [values] acceleration_enabled = True diff --git a/resources/quality/ultimaker3/um3_aa0.25_TPLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.25_TPLA_Normal_Quality.inst.cfg index 768864bfef..af9bea762a 100644 --- a/resources/quality/ultimaker3/um3_aa0.25_TPLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.25_TPLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg index 8877912a33..a6ba0a666b 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_ABS_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg index 926cfd6995..4bd04e36af 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_ABS_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg index 9ceab110e9..6ef2fa3cb4 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_ABS_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 @@ -17,6 +17,7 @@ machine_nozzle_cool_down_speed = 0.8 machine_nozzle_heat_up_speed = 1.5 material_standby_temperature = 100 material_print_temperature = =default_material_print_temperature - 5 +material_print_temperature_layer_0 = =material_print_temperature + 15 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 prime_tower_enable = False diff --git a/resources/quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg index e5b699c35f..e0862a137c 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_ABS_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 @@ -14,6 +14,7 @@ variant = AA 0.4 [values] machine_nozzle_cool_down_speed = 0.85 machine_nozzle_heat_up_speed = 1.5 +material_print_temperature_layer_0 = =material_print_temperature + 10 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 material_standby_temperature = 100 diff --git a/resources/quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg index df7f0fdf02..3de7252b86 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_BAM_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg index cf330dc984..28bce4eb15 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_BAM_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg index 705c9c4105..0f15931e59 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_BAM_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg index 4e94789a6b..c27fc027fb 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg index d93915d721..6a035522f1 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg index 082152c50f..3387430d26 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg index 889b94e001..8d0283a20f 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPEP_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg index 1891a274c8..a8d5c26315 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPE_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg index e4cfdb67fc..e4b4e2e21b 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPE_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg index cec4b950cf..3964608aec 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPE_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg index 892083b264..b0e7234c90 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_CPE_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg index 2e4b8f8dcc..5bfa29fd61 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg index 9b271c47cd..eaec1cdbdb 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg index 16c0b6febb..7a0a04b6c2 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_Nylon_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg index 17661efbb8..8b18ee20df 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_Nylon_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg index 96acf403a5..fafb839f17 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg index f9159b5fca..57527f928c 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg index d175e99ad6..37e31c5863 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg index 557a449022..0961b3ccd6 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PC_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg index 16626dc544..c24c2cacdf 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PLA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg index 7f50a2a6f0..d20a06a94a 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PLA_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg index 507afc5526..bd365c56ae 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PLA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg index 05febab06d..a291357e58 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg index 4efa5199cb..6dbb444454 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg index ad03df5d86..60c304794b 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg index d8d51dd716..92d53d6295 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_PP_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPLA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPLA_Draft_Print.inst.cfg index 9959a39457..6d8c6690a2 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPLA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPLA_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPLA_Fast_Print.inst.cfg index 5c68557e9b..c8fbe827e3 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPLA_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPLA_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPLA_Normal_Quality.inst.cfg index 90556ea487..d1a1bc994c 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg index 9b9dca3a16..13bc7c0b7e 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg index e6233a8184..cb3692a84f 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg index e725615854..a5264ce6ec 100644 --- a/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.4_TPU_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg index e71ea07531..474b24a462 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_ABS_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg index 39aa103631..e9c4f9e3e9 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_ABS_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg index 3a08643086..213298653a 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_ABS_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg index 73df9637f7..bb2aa2d6ef 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Fast_Print.inst.cfg @@ -4,12 +4,13 @@ name = Fast - Experimental definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 material = generic_cpe_plus variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg index d59bfe7cea..98086b2bf1 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Superdraft_Print.inst.cfg @@ -4,12 +4,13 @@ name = Sprint - Experimental definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 material = generic_cpe_plus variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg index 368317019f..0684b9ac1e 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPEP_Verydraft_Print.inst.cfg @@ -4,12 +4,13 @@ name = Extra Fast - Experimental definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 material = generic_cpe_plus variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg index 170643275c..05294737b6 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPE_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg index 5b3cb52f18..555d6da1bf 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPE_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg index fff96ba9fc..da71c679ff 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_CPE_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg index e9b0873716..ab11f0fe86 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg index 7518acc7f0..46f5a87a1b 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg index 040632efec..12d96e9f7d 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_Nylon_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg index 5b81532977..8005618066 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Fast_Print.inst.cfg @@ -4,12 +4,13 @@ name = Fast - Experimental definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 material = generic_pc variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg index 317b89ea85..601a68ef46 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Superdraft_Print.inst.cfg @@ -4,12 +4,13 @@ name = Sprint - Experimental definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft -weight = -2 +weight = -4 material = generic_pc variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg index 2fd6bd7609..0d5b579846 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PC_Verydraft_Print.inst.cfg @@ -4,12 +4,13 @@ name = Extra Fast - Experimental definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -1 +weight = -3 material = generic_pc variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg index 9b861030d8..c5000b0a43 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PLA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg index 42a499f22c..e03663bc2b 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PLA_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg index d1f3937244..06bf4cf224 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PLA_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg index 19496565bc..b577ba8185 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg index aeee3b4e09..c0917a9e8e 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PP_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg index fcd4fcd999..00eb39a400 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_PP_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPLA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPLA_Draft_Print.inst.cfg index 3f679870fd..30ce94000f 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPLA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPLA_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPLA_Superdraft_Print.inst.cfg index 17dbd1faf9..ea3525c7ee 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPLA_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPLA_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPLA_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPLA_Verydraft_Print.inst.cfg index 624496a9ec..1027f52b38 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPLA_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPLA_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg index 90b5103f20..83fb56a84d 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg index a9fab40d4e..36e38654db 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg index e2ced0a364..96b1406adb 100644 --- a/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_aa0.8_TPU_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg index 7010d292b2..a41b0c0210 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg index 325609362f..d7a8885bf9 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg index a0507299fb..be4eedadc8 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg index 086f811b36..ae576790a8 100644 --- a/resources/quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.4_PVA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg index 28556ca7bf..247e7f12c6 100644 --- a/resources/quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.8_PVA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg index 9ad5499f18..8a4c0cc992 100644 --- a/resources/quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.8_PVA_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg b/resources/quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg index e616214704..c931e6ad5d 100644 --- a/resources/quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker3/um3_bb0.8_PVA_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg index a421203220..b95ddb1aa9 100644 --- a/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg index 2ecf7526a2..3510a05343 100644 --- a/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg index ce5497bd39..55fe2bdfda 100644 --- a/resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_High_Quality.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 global_quality = True [values] diff --git a/resources/quality/ultimaker3/um3_global_Normal_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Normal_Quality.inst.cfg index afadda378a..cffacfd312 100644 --- a/resources/quality/ultimaker3/um3_global_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg index f88f5df85f..5fd966bb9f 100644 --- a/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Superdraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg b/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg index df626dc724..7e65a6c4c4 100644 --- a/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg +++ b/resources/quality/ultimaker3/um3_global_Verydraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_original/umo_global_Coarse_Quality.inst.cfg b/resources/quality/ultimaker_original/umo_global_Coarse_Quality.inst.cfg index 34f3a2a901..6125d0f687 100644 --- a/resources/quality/ultimaker_original/umo_global_Coarse_Quality.inst.cfg +++ b/resources/quality/ultimaker_original/umo_global_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Coarse Quality definition = ultimaker_original [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = coarse weight = -3 diff --git a/resources/quality/ultimaker_original/umo_global_Draft_Quality.inst.cfg b/resources/quality/ultimaker_original/umo_global_Draft_Quality.inst.cfg index ed8c0ddb97..ebabe4dd46 100644 --- a/resources/quality/ultimaker_original/umo_global_Draft_Quality.inst.cfg +++ b/resources/quality/ultimaker_original/umo_global_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Draft Quality definition = ultimaker_original [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_original/umo_global_Extra_Coarse_Quality.inst.cfg b/resources/quality/ultimaker_original/umo_global_Extra_Coarse_Quality.inst.cfg index 1ad10ac4db..b625ec45ea 100644 --- a/resources/quality/ultimaker_original/umo_global_Extra_Coarse_Quality.inst.cfg +++ b/resources/quality/ultimaker_original/umo_global_Extra_Coarse_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Coarse Quality definition = ultimaker_original [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extra coarse weight = -4 diff --git a/resources/quality/ultimaker_original/umo_global_Fast_Quality.inst.cfg b/resources/quality/ultimaker_original/umo_global_Fast_Quality.inst.cfg index 6c83239164..e2bceeae7e 100644 --- a/resources/quality/ultimaker_original/umo_global_Fast_Quality.inst.cfg +++ b/resources/quality/ultimaker_original/umo_global_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_original [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_original/umo_global_High_Quality.inst.cfg b/resources/quality/ultimaker_original/umo_global_High_Quality.inst.cfg index 19752f07bf..883048f557 100644 --- a/resources/quality/ultimaker_original/umo_global_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_original/umo_global_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_original [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_original/umo_global_Normal_Quality.inst.cfg b/resources/quality/ultimaker_original/umo_global_Normal_Quality.inst.cfg index a7dedc9b88..2cec4bfbda 100644 --- a/resources/quality/ultimaker_original/umo_global_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_original/umo_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_original [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_ABS_Normal_Quality.inst.cfg index f2e05b08e8..be8e56d133 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_ABS_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_CPE_Normal_Quality.inst.cfg index 2068ed51c0..3eaeda67d5 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_CPE_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 @@ -12,6 +12,7 @@ material = generic_cpe variant = AA 0.25 [values] +retraction_combing_max_distance = 50 retraction_extrusion_window = 0.5 speed_infill = =math.ceil(speed_print * 40 / 55) speed_topbottom = =math.ceil(speed_print * 30 / 55) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_Nylon_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_Nylon_Normal_Quality.inst.cfg index 3a8ed8e773..9407fb72b0 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_Nylon_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_Nylon_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_PC_Normal_Quality.inst.cfg index 55d53c6c71..7cde76a1e1 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_PC_Normal_Quality.inst.cfg @@ -4,12 +4,13 @@ name = Fine - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 material = generic_pc variant = AA 0.25 +is_experimental = True [values] acceleration_enabled = True diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_PLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_PLA_Normal_Quality.inst.cfg index a06f2158fe..ab45d82a3b 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_PLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_PP_Normal_Quality.inst.cfg index c925845dc1..1474cad5c1 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_PP_Normal_Quality.inst.cfg @@ -4,12 +4,13 @@ name = Fine - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 material = generic_pp variant = AA 0.25 +is_experimental = True [values] acceleration_enabled = True diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.25_TPLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.25_TPLA_Normal_Quality.inst.cfg index e9628225bc..ea4375b854 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.25_TPLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.25_TPLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Draft_Print.inst.cfg index b86c61b3a2..6d26c2bb97 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Fast_Print.inst.cfg index f3c099724a..e2e8bd82e5 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_High_Quality.inst.cfg index 8d016a2ee4..fc39383f04 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Normal_Quality.inst.cfg index 6ce623b66e..8ec7e6453b 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_ABS_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Draft_Print.inst.cfg index 254afbc109..93665c36de 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Fast_Print.inst.cfg index 39bedce77f..478df58f43 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Normal_Quality.inst.cfg index c87d590650..e936d0f131 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_BAM_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Draft_Print.inst.cfg index 421fcdf095..da639d22c9 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 @@ -29,7 +29,7 @@ material_print_temperature_layer_0 = =material_print_temperature multiple_mesh_overlap = 0 prime_tower_enable = True prime_tower_wipe_enabled = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_extrusion_window = 1 retraction_hop = 0.2 retraction_hop_enabled = False diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Fast_Print.inst.cfg index 536c6c97b8..2c2eb99fb0 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 @@ -29,7 +29,7 @@ material_print_temperature_layer_0 = =material_print_temperature multiple_mesh_overlap = 0 prime_tower_enable = True prime_tower_wipe_enabled = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_extrusion_window = 1 retraction_hop = 0.2 retraction_hop_enabled = False diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_High_Quality.inst.cfg index 77182c21e1..20fbcd9430 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 @@ -31,7 +31,7 @@ material_print_temperature_layer_0 = =material_print_temperature multiple_mesh_overlap = 0 prime_tower_enable = True prime_tower_wipe_enabled = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_extrusion_window = 1 retraction_hop = 0.2 retraction_hop_enabled = False diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Normal_Quality.inst.cfg index d779baf315..e40949fc7d 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPEP_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 @@ -31,7 +31,7 @@ material_print_temperature_layer_0 = =material_print_temperature multiple_mesh_overlap = 0 prime_tower_enable = True prime_tower_wipe_enabled = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_extrusion_window = 1 retraction_hop = 0.2 retraction_hop_enabled = False diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Draft_Print.inst.cfg index c51e5652e1..7ccfe4f786 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 @@ -15,6 +15,7 @@ variant = AA 0.4 material_print_temperature = =default_material_print_temperature + 10 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 +retraction_combing_max_distance = 50 skin_overlap = 20 speed_print = 60 speed_layer_0 = =math.ceil(speed_print * 20 / 60) @@ -24,5 +25,5 @@ speed_wall_0 = =math.ceil(speed_wall * 35 / 45) wall_thickness = 1 -infill_pattern = zigzag +infill_pattern = triangles speed_infill = =math.ceil(speed_print * 50 / 60) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Fast_Print.inst.cfg index b80d3ccf22..f12c90bc05 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 @@ -16,11 +16,12 @@ cool_min_speed = 7 material_print_temperature = =default_material_print_temperature + 5 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 +retraction_combing_max_distance = 50 speed_print = 60 speed_layer_0 = =math.ceil(speed_print * 20 / 60) speed_topbottom = =math.ceil(speed_print * 30 / 60) speed_wall = =math.ceil(speed_print * 40 / 60) speed_wall_0 = =math.ceil(speed_wall * 30 / 40) -infill_pattern = zigzag +infill_pattern = triangles speed_infill = =math.ceil(speed_print * 50 / 60) \ No newline at end of file diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_High_Quality.inst.cfg index c90eedaec3..04957025f1 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 @@ -18,10 +18,11 @@ machine_nozzle_heat_up_speed = 1.5 material_print_temperature = =default_material_print_temperature - 5 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 +retraction_combing_max_distance = 50 speed_print = 50 speed_layer_0 = =math.ceil(speed_print * 20 / 50) speed_topbottom = =math.ceil(speed_print * 30 / 50) speed_wall = =math.ceil(speed_print * 30 / 50) -infill_pattern = zigzag +infill_pattern = triangles speed_infill = =math.ceil(speed_print * 40 / 50) \ No newline at end of file diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Normal_Quality.inst.cfg index e098b0ffb4..b0a5fb820f 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_CPE_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 @@ -16,10 +16,11 @@ machine_nozzle_cool_down_speed = 0.85 machine_nozzle_heat_up_speed = 1.5 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 +retraction_combing_max_distance = 50 speed_print = 55 speed_layer_0 = =math.ceil(speed_print * 20 / 55) speed_topbottom = =math.ceil(speed_print * 30 / 55) speed_wall = =math.ceil(speed_print * 30 / 55) -infill_pattern = zigzag +infill_pattern = triangles speed_infill = =math.ceil(speed_print * 45 / 55) \ No newline at end of file diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Draft_Print.inst.cfg index 991ad30a5a..1a198f3e03 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Fast_Print.inst.cfg index 695ce2c8fb..e6b882d2af 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_High_Quality.inst.cfg index e55867efe5..292ef73a4c 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Normal_Quality.inst.cfg index 41e28c51d5..2b71a01e0d 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_Nylon_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Draft_Print.inst.cfg index 5d03e1c980..e27a6894e3 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Fast_Print.inst.cfg index b630ab6232..db1ecee3bc 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_High_Quality.inst.cfg index 1c080c3b47..ca80494f3d 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Normal_Quality.inst.cfg index 79ce686da5..d2d5171fed 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PC_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Draft_Print.inst.cfg index c7a4864328..9bf58d4f39 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Fast_Print.inst.cfg index 42048fa297..017bf46bd8 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_High_Quality.inst.cfg index b7ad8bd5c4..314f7fe0bb 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Normal_Quality.inst.cfg index 911fa9a0a8..2bb0d31d76 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Draft_Print.inst.cfg index 68558bcf93..8b8bdfd999 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Fast_Print.inst.cfg index 1145d1900f..0fd70e5973 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Normal_Quality.inst.cfg index c0b094f0a2..0d683a9f87 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_PP_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Draft_Print.inst.cfg index 280e5c4bfb..df45c190e1 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Fast_Print.inst.cfg index 304c170b55..96b77ebca9 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_High_Quality.inst.cfg index cd5c598d4f..3a2cf495a3 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Normal_Quality.inst.cfg index 2522c0f20f..2d93d1e980 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Draft_Print.inst.cfg index 9b4ab52543..30a1e0c29f 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Fast_Print.inst.cfg index 35cf66a93b..3b57900a46 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Normal_Quality.inst.cfg index 4357d765df..368bfd9e48 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_TPU_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Draft_Print.inst.cfg index c8d64f9dcb..a2b7aa7b87 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Fast_Print.inst.cfg index c7fa604e89..8e82e27210 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_High_Quality.inst.cfg index 187023d3c0..7e4f17cbf1 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Normal_Quality.inst.cfg index 81cb27f060..959d9241c7 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_ABS_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Draft_Print.inst.cfg index 46e3483a6a..c9083cf2ab 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 @@ -30,7 +30,7 @@ material_print_temperature_layer_0 = =material_print_temperature multiple_mesh_overlap = 0 prime_tower_enable = True prime_tower_wipe_enabled = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_extrusion_window = 1 retraction_hop = 0.2 retraction_hop_enabled = False diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Fast_Print.inst.cfg index 5c235b656a..9d7663b6e1 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 @@ -30,7 +30,7 @@ material_print_temperature_layer_0 = =material_print_temperature multiple_mesh_overlap = 0 prime_tower_enable = True prime_tower_wipe_enabled = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_extrusion_window = 1 retraction_hop = 0.2 retraction_hop_enabled = False diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_High_Quality.inst.cfg index 326a730fe4..ba796da940 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 @@ -32,7 +32,7 @@ material_print_temperature_layer_0 = =material_print_temperature multiple_mesh_overlap = 0 prime_tower_enable = True prime_tower_wipe_enabled = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_extrusion_window = 1 retraction_hop = 0.2 retraction_hop_enabled = False diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Normal_Quality.inst.cfg index d40b2db90e..96ec8d9e36 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPEP_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 @@ -32,7 +32,7 @@ material_print_temperature_layer_0 = =material_print_temperature multiple_mesh_overlap = 0 prime_tower_enable = True prime_tower_wipe_enabled = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_extrusion_window = 1 retraction_hop = 0.2 retraction_hop_enabled = False diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Draft_Print.inst.cfg index c812066e0c..bae8b09016 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 @@ -16,6 +16,7 @@ buildplate = Aluminum material_print_temperature = =default_material_print_temperature + 10 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 +retraction_combing_max_distance = 50 skin_overlap = 20 speed_print = 60 speed_layer_0 = 20 @@ -25,7 +26,7 @@ speed_wall_0 = =math.ceil(speed_wall * 35 / 45) wall_thickness = 1 -infill_pattern = zigzag +infill_pattern = triangles speed_infill = =math.ceil(speed_print * 50 / 60) prime_tower_purge_volume = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Fast_Print.inst.cfg index ef634316da..f585c2a787 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 @@ -17,13 +17,14 @@ cool_min_speed = 7 material_print_temperature = =default_material_print_temperature + 5 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 +retraction_combing_max_distance = 50 speed_print = 60 speed_layer_0 = 20 speed_topbottom = =math.ceil(speed_print * 30 / 60) speed_wall = =math.ceil(speed_print * 40 / 60) speed_wall_0 = =math.ceil(speed_wall * 30 / 40) -infill_pattern = zigzag +infill_pattern = triangles speed_infill = =math.ceil(speed_print * 50 / 60) prime_tower_purge_volume = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_High_Quality.inst.cfg index cda97e6ab3..a580a27176 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 @@ -19,12 +19,13 @@ machine_nozzle_heat_up_speed = 1.5 material_print_temperature = =default_material_print_temperature - 5 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 +retraction_combing_max_distance = 50 speed_print = 50 speed_layer_0 = 20 speed_topbottom = =math.ceil(speed_print * 30 / 50) speed_wall = =math.ceil(speed_print * 30 / 50) -infill_pattern = zigzag +infill_pattern = triangles speed_infill = =math.ceil(speed_print * 40 / 50) prime_tower_purge_volume = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Normal_Quality.inst.cfg index 5a75f3b6e3..3db4053d2a 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_CPE_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 @@ -17,12 +17,13 @@ machine_nozzle_cool_down_speed = 0.85 machine_nozzle_heat_up_speed = 1.5 material_initial_print_temperature = =material_print_temperature - 5 material_final_print_temperature = =material_print_temperature - 10 +retraction_combing_max_distance = 50 speed_print = 55 speed_layer_0 = 20 speed_topbottom = =math.ceil(speed_print * 30 / 55) speed_wall = =math.ceil(speed_print * 30 / 55) -infill_pattern = zigzag +infill_pattern = triangles speed_infill = =math.ceil(speed_print * 45 / 55) prime_tower_purge_volume = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Draft_Print.inst.cfg index f05ecddc25..e86c3b363b 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Fast_Print.inst.cfg index 6103519f1c..0da88626b6 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_High_Quality.inst.cfg index 130afb8c91..d7552ba921 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Normal_Quality.inst.cfg index 9e1bf394d4..638ce2323e 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PC_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Draft_Print.inst.cfg index 6124dff257..c0ca84281d 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Fast_Print.inst.cfg index 2791e9f5d5..43b77f6492 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Normal_Quality.inst.cfg index f78b4048fb..04abd0d18b 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.4_aluminum_PP_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Draft_Print.inst.cfg index 911fc6e78e..fb786c7759 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Superdraft_Print.inst.cfg index 0fcdac4a85..cfacaebad0 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Verydraft_Print.inst.cfg index e3346bbd1d..18ce266cd6 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_ABS_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Fast_Print.inst.cfg index e78006689b..a4a7a5e08c 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Fast_Print.inst.cfg @@ -4,12 +4,13 @@ name = Fast - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 material = generic_cpe_plus variant = AA 0.8 +is_experimental = True [values] brim_width = 14 @@ -22,7 +23,7 @@ material_print_temperature = =default_material_print_temperature - 10 material_print_temperature_layer_0 = =material_print_temperature material_standby_temperature = 100 prime_tower_enable = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_hop = 0.1 retraction_hop_enabled = False skin_overlap = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Superdraft_Print.inst.cfg index c6d0962157..e4f330099b 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Superdraft_Print.inst.cfg @@ -4,12 +4,13 @@ name = Sprint - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 material = generic_cpe_plus variant = AA 0.8 +is_experimental = True [values] brim_width = 14 @@ -22,7 +23,7 @@ material_print_temperature = =default_material_print_temperature - 5 material_print_temperature_layer_0 = =material_print_temperature material_standby_temperature = 100 prime_tower_enable = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_hop = 0.1 retraction_hop_enabled = False skin_overlap = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Verydraft_Print.inst.cfg index b80f773594..0685b27b8a 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPEP_Verydraft_Print.inst.cfg @@ -4,12 +4,13 @@ name = Extra Fast - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 material = generic_cpe_plus variant = AA 0.8 +is_experimental = True [values] brim_width = 14 @@ -22,7 +23,7 @@ material_print_temperature = =default_material_print_temperature - 7 material_print_temperature_layer_0 = =material_print_temperature material_standby_temperature = 100 prime_tower_enable = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_hop = 0.1 retraction_hop_enabled = False skin_overlap = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Draft_Print.inst.cfg index 532aacabf7..a57bde98b1 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 @@ -17,6 +17,7 @@ line_width = =machine_nozzle_size * 0.875 material_print_temperature = =default_material_print_temperature + 15 material_standby_temperature = 100 prime_tower_enable = True +retraction_combing_max_distance = 50 speed_print = 40 speed_topbottom = =math.ceil(speed_print * 25 / 40) speed_wall = =math.ceil(speed_print * 30 / 40) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Superdraft_Print.inst.cfg index 55b9ae8315..2f0851d9fb 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 @@ -17,6 +17,7 @@ line_width = =machine_nozzle_size * 0.875 material_print_temperature = =default_material_print_temperature + 20 material_standby_temperature = 100 prime_tower_enable = True +retraction_combing_max_distance = 50 speed_print = 45 speed_topbottom = =math.ceil(speed_print * 30 / 45) speed_wall = =math.ceil(speed_print * 40 / 45) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Verydraft_Print.inst.cfg index 01761062a4..6ccca75b44 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_CPE_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 @@ -17,6 +17,7 @@ line_width = =machine_nozzle_size * 0.875 material_print_temperature = =default_material_print_temperature + 17 material_standby_temperature = 100 prime_tower_enable = True +retraction_combing_max_distance = 50 speed_print = 40 speed_topbottom = =math.ceil(speed_print * 25 / 40) speed_wall = =math.ceil(speed_print * 30 / 40) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Draft_Print.inst.cfg index 2108839d3f..5d04892443 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Superdraft_Print.inst.cfg index 0702d174a0..5c31e26bd6 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Verydraft_Print.inst.cfg index d02d410ed6..d04482c94c 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_Nylon_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Fast_Print.inst.cfg index 0ed4e3d994..97afe62e07 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Fast_Print.inst.cfg @@ -4,12 +4,13 @@ name = Fast - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 material = generic_pc variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Superdraft_Print.inst.cfg index 53bf1d3107..3f296c0300 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Superdraft_Print.inst.cfg @@ -4,12 +4,13 @@ name = Sprint - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft -weight = -2 +weight = -4 material = generic_pc variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Verydraft_Print.inst.cfg index d9c45c2634..5eec532f22 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PC_Verydraft_Print.inst.cfg @@ -4,12 +4,13 @@ name = Extra Fast - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -1 +weight = -3 material = generic_pc variant = AA 0.8 +is_experimental = True [values] brim_width = 14 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Draft_Print.inst.cfg index 7db4e96311..1410290859 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Superdraft_Print.inst.cfg index c59f015b5d..2c65968d77 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Verydraft_Print.inst.cfg index 6fdff8bf8d..9b6e7c2ed9 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PLA_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Draft_Print.inst.cfg index fee58b367d..c5b01ab1b1 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Superdraft_Print.inst.cfg index aaa810e864..5c83f24395 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Verydraft_Print.inst.cfg index 5b8aa6d2e1..f182d5c6cb 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_PP_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Draft_Print.inst.cfg index 50dead746b..5b39508f3c 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Superdraft_Print.inst.cfg index 0bdb088f8c..b07a78419a 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Verydraft_Print.inst.cfg index c7cb5902a2..46a61bb79f 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPLA_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Draft_Print.inst.cfg index e8276d54c5..088414fa34 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Superdraft_Print.inst.cfg index 7da73a200d..d74309c476 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Verydraft_Print.inst.cfg index 60dbbf38e6..deb2b55dbb 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_TPU_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Draft_Print.inst.cfg index 37dceff349..062fcfdd5b 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Superdraft_Print.inst.cfg index eac339baa8..38c341af28 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Verydraft_Print.inst.cfg index 590496df0f..8a38bb9aa3 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_ABS_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Fast_Print.inst.cfg index 3e74390840..d9dd09c7b6 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Fast_Print.inst.cfg @@ -4,13 +4,14 @@ name = Fast - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 material = generic_cpe_plus variant = AA 0.8 buildplate = Aluminum +is_experimental = True [values] brim_width = 14 @@ -23,7 +24,7 @@ material_print_temperature = =default_material_print_temperature - 10 material_print_temperature_layer_0 = =material_print_temperature material_standby_temperature = 100 prime_tower_enable = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_hop = 0.1 retraction_hop_enabled = False skin_overlap = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Superdraft_Print.inst.cfg index 4c1b807430..bc6a04ae55 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 @@ -23,7 +23,7 @@ material_print_temperature = =default_material_print_temperature - 5 material_print_temperature_layer_0 = =material_print_temperature material_standby_temperature = 100 prime_tower_enable = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_hop = 0.1 retraction_hop_enabled = False skin_overlap = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Verydraft_Print.inst.cfg index 11aefc90cd..b384bd7083 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPEP_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 @@ -23,7 +23,7 @@ material_print_temperature = =default_material_print_temperature - 7 material_print_temperature_layer_0 = =material_print_temperature material_standby_temperature = 100 prime_tower_enable = True -retraction_combing = off +retraction_combing_max_distance = 50 retraction_hop = 0.1 retraction_hop_enabled = False skin_overlap = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Draft_Print.inst.cfg index 80c0585061..28409d4181 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 @@ -18,6 +18,7 @@ line_width = =machine_nozzle_size * 0.875 material_print_temperature = =default_material_print_temperature + 15 material_standby_temperature = 100 prime_tower_enable = True +retraction_combing_max_distance = 50 speed_print = 40 speed_topbottom = =math.ceil(speed_print * 25 / 40) speed_wall = =math.ceil(speed_print * 30 / 40) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Superdraft_Print.inst.cfg index 5dcc454173..33c5d73a59 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 @@ -18,6 +18,7 @@ line_width = =machine_nozzle_size * 0.875 material_print_temperature = =default_material_print_temperature + 20 material_standby_temperature = 100 prime_tower_enable = True +retraction_combing_max_distance = 50 speed_print = 45 speed_topbottom = =math.ceil(speed_print * 30 / 45) speed_wall = =math.ceil(speed_print * 40 / 45) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Verydraft_Print.inst.cfg index 8423e109e8..8db23c11c2 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_CPE_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 @@ -18,6 +18,7 @@ line_width = =machine_nozzle_size * 0.875 material_print_temperature = =default_material_print_temperature + 17 material_standby_temperature = 100 prime_tower_enable = True +retraction_combing_max_distance = 50 speed_print = 40 speed_topbottom = =math.ceil(speed_print * 25 / 40) speed_wall = =math.ceil(speed_print * 30 / 40) diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Fast_Print.inst.cfg index 747e2fe8a5..c0af70748a 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Fast_Print.inst.cfg @@ -4,13 +4,14 @@ name = Fast - Experimental definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = 0 +weight = -2 material = generic_pc variant = AA 0.8 buildplate = Aluminum +is_experimental = True [values] brim_width = 10 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Superdraft_Print.inst.cfg index 689652dc06..bba2dfa92f 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Superdraft_Print.inst.cfg @@ -4,10 +4,10 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft -weight = -2 +weight = -4 material = generic_pc variant = AA 0.8 buildplate = Aluminum diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Verydraft_Print.inst.cfg index 0480ee5620..3987c01ecc 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PC_Verydraft_Print.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft -weight = -1 +weight = -3 material = generic_pc variant = AA 0.8 buildplate = Aluminum diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Draft_Print.inst.cfg index b80af1b75f..5a2c3005c9 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Superdraft_Print.inst.cfg index 970e0971a9..aaa8cbfcd3 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Verydraft_Print.inst.cfg index e51ba3207b..782cadce6b 100644 --- a/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_aa0.8_aluminum_PP_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Draft_Print.inst.cfg index 73639be0b6..34b078278c 100644 --- a/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Fast_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Fast_Print.inst.cfg index 5da25be32d..5677c5931c 100644 --- a/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Fast_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Fast_Print.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_High_Quality.inst.cfg index 36634af2c8..b9e32cb7c5 100644 --- a/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Normal_Quality.inst.cfg index f76c4c944a..081ee2261e 100644 --- a/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_bb0.4_PVA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Draft_Print.inst.cfg index e4e3ab772a..0193081db6 100644 --- a/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Draft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Superdraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Superdraft_Print.inst.cfg index 5e78e51014..121b32f903 100644 --- a/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Superdraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Superdraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Verydraft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Verydraft_Print.inst.cfg index 5af09aebcc..f0296c9279 100644 --- a/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Verydraft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_bb0.8_PVA_Verydraft_Print.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/ultimaker_s5/um_s5_cc0.6_CFFCPE_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_cc0.6_CFFCPE_Draft_Print.inst.cfg index 99b4b142fa..35da5b113e 100644 --- a/resources/quality/ultimaker_s5/um_s5_cc0.6_CFFCPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_cc0.6_CFFCPE_Draft_Print.inst.cfg @@ -4,10 +4,10 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = -3 +weight = -2 material = generic_cffcpe variant = CC 0.6 diff --git a/resources/quality/ultimaker_s5/um_s5_cc0.6_CFFPA_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_cc0.6_CFFPA_Draft_Print.inst.cfg index 80c383aa8d..67400daf9f 100644 --- a/resources/quality/ultimaker_s5/um_s5_cc0.6_CFFPA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_cc0.6_CFFPA_Draft_Print.inst.cfg @@ -4,10 +4,10 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = -3 +weight = -2 material = generic_cffpa variant = CC 0.6 diff --git a/resources/quality/ultimaker_s5/um_s5_cc0.6_GFFCPE_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_cc0.6_GFFCPE_Draft_Print.inst.cfg index c94d239c81..0c4f55bddf 100644 --- a/resources/quality/ultimaker_s5/um_s5_cc0.6_GFFCPE_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_cc0.6_GFFCPE_Draft_Print.inst.cfg @@ -4,10 +4,10 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = -3 +weight = -2 material = generic_gffcpe variant = CC 0.6 diff --git a/resources/quality/ultimaker_s5/um_s5_cc0.6_GFFPA_Draft_Print.inst.cfg b/resources/quality/ultimaker_s5/um_s5_cc0.6_GFFPA_Draft_Print.inst.cfg index e7d4d1955b..8a6f9d2ac8 100644 --- a/resources/quality/ultimaker_s5/um_s5_cc0.6_GFFPA_Draft_Print.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_cc0.6_GFFPA_Draft_Print.inst.cfg @@ -4,10 +4,10 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft -weight = -3 +weight = -2 material = generic_gffpa variant = CC 0.6 diff --git a/resources/quality/ultimaker_s5/um_s5_global_Draft_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_global_Draft_Quality.inst.cfg index ed5303637b..f0121fa4d7 100644 --- a/resources/quality/ultimaker_s5/um_s5_global_Draft_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_global_Draft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = draft weight = -2 diff --git a/resources/quality/ultimaker_s5/um_s5_global_Fast_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_global_Fast_Quality.inst.cfg index ee9c6a8409..b9bb0beff6 100644 --- a/resources/quality/ultimaker_s5/um_s5_global_Fast_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_global_Fast_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = -1 diff --git a/resources/quality/ultimaker_s5/um_s5_global_High_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_global_High_Quality.inst.cfg index cd1c269b1d..aa2420e465 100644 --- a/resources/quality/ultimaker_s5/um_s5_global_High_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_global_High_Quality.inst.cfg @@ -4,10 +4,10 @@ name = Extra Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high -weight = 0 +weight = 1 global_quality = True [values] diff --git a/resources/quality/ultimaker_s5/um_s5_global_Normal_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_global_Normal_Quality.inst.cfg index 099ba7c584..8bb8f7f282 100644 --- a/resources/quality/ultimaker_s5/um_s5_global_Normal_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Fine definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/ultimaker_s5/um_s5_global_Superdraft_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_global_Superdraft_Quality.inst.cfg index 4c0bd40bd1..ec46668b61 100644 --- a/resources/quality/ultimaker_s5/um_s5_global_Superdraft_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_global_Superdraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Sprint definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = superdraft weight = -4 diff --git a/resources/quality/ultimaker_s5/um_s5_global_Verydraft_Quality.inst.cfg b/resources/quality/ultimaker_s5/um_s5_global_Verydraft_Quality.inst.cfg index ec4ec910ff..dd6c7bb4b8 100644 --- a/resources/quality/ultimaker_s5/um_s5_global_Verydraft_Quality.inst.cfg +++ b/resources/quality/ultimaker_s5/um_s5_global_Verydraft_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extra Fast definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = verydraft weight = -3 diff --git a/resources/quality/vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg index 70aac3f666..370cc149a2 100644 --- a/resources/quality/vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_ABS_Extreme_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extreme definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extreme weight = 2 diff --git a/resources/quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg index 564b330132..6c96b47169 100644 --- a/resources/quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_ABS_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg index e2f740a60a..19150baab9 100644 --- a/resources/quality/vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_ABS_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/vertex_delta_k8800/k8800_Global_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_Global_Extreme_Quality.inst.cfg index 48e80b5512..00d626d72c 100644 --- a/resources/quality/vertex_delta_k8800/k8800_Global_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_Global_Extreme_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extreme definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extreme weight = 2 diff --git a/resources/quality/vertex_delta_k8800/k8800_Global_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_Global_High_Quality.inst.cfg index 496144772c..0bd519affe 100644 --- a/resources/quality/vertex_delta_k8800/k8800_Global_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_Global_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/vertex_delta_k8800/k8800_Global_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_Global_Normal_Quality.inst.cfg index 75ae5f15e6..2b18891998 100644 --- a/resources/quality/vertex_delta_k8800/k8800_Global_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_Global_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg index 8309106d9f..8715e573ab 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PET_Extreme_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extreme definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extreme weight = 2 diff --git a/resources/quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg index 6efaa3299f..0c94cc5ca4 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PET_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg index bd3b0c35fb..40698f134d 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PET_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg index d10b4c3f8d..f81c82fa9b 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PLA_Extreme_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extreme definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extreme weight = 2 diff --git a/resources/quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg index ede77b0dfe..e4b4771b0e 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PLA_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg index a75cff6968..41950da7a1 100644 --- a/resources/quality/vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_PLA_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg index bee6b3bf11..32077f6cc1 100644 --- a/resources/quality/vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_TPU_Extreme_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Extreme definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = extreme weight = 2 diff --git a/resources/quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg index 8b0f87cc77..a7ef7d8cc8 100644 --- a/resources/quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_TPU_High_Quality.inst.cfg @@ -4,7 +4,7 @@ name = High definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = high weight = 1 diff --git a/resources/quality/vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg b/resources/quality/vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg index bd4e04744f..17a09f366f 100644 --- a/resources/quality/vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg +++ b/resources/quality/vertex_delta_k8800/k8800_TPU_Normal_Quality.inst.cfg @@ -4,7 +4,7 @@ name = Normal definition = vertex_delta_k8800 [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal weight = 0 diff --git a/resources/quality/zyyx/zyyx_agile_global_fast.inst.cfg b/resources/quality/zyyx/zyyx_agile_global_fast.inst.cfg index 67e350b39e..19cda650d3 100644 --- a/resources/quality/zyyx/zyyx_agile_global_fast.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_global_fast.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = 1 diff --git a/resources/quality/zyyx/zyyx_agile_global_fine.inst.cfg b/resources/quality/zyyx/zyyx_agile_global_fine.inst.cfg index 58e13b22c5..f2f127f483 100644 --- a/resources/quality/zyyx/zyyx_agile_global_fine.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_global_fine.inst.cfg @@ -4,10 +4,10 @@ name = Fine definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fine -weight = 3 +weight = 1 global_quality = True [values] diff --git a/resources/quality/zyyx/zyyx_agile_global_normal.inst.cfg b/resources/quality/zyyx/zyyx_agile_global_normal.inst.cfg index cb4e042e7b..d9cbdc691e 100644 --- a/resources/quality/zyyx/zyyx_agile_global_normal.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_global_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 global_quality = True [values] diff --git a/resources/quality/zyyx/zyyx_agile_pro_flex_fast.inst.cfg b/resources/quality/zyyx/zyyx_agile_pro_flex_fast.inst.cfg index 188bdd25e5..d6f715c09f 100644 --- a/resources/quality/zyyx/zyyx_agile_pro_flex_fast.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_pro_flex_fast.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = 1 diff --git a/resources/quality/zyyx/zyyx_agile_pro_flex_fine.inst.cfg b/resources/quality/zyyx/zyyx_agile_pro_flex_fine.inst.cfg index 6654889c10..a0aa1996ac 100644 --- a/resources/quality/zyyx/zyyx_agile_pro_flex_fine.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_pro_flex_fine.inst.cfg @@ -4,10 +4,10 @@ name = Fine definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fine -weight = 3 +weight = 1 material = generic_tpu [values] diff --git a/resources/quality/zyyx/zyyx_agile_pro_flex_normal.inst.cfg b/resources/quality/zyyx/zyyx_agile_pro_flex_normal.inst.cfg index f56355100c..a70b1dd19a 100644 --- a/resources/quality/zyyx/zyyx_agile_pro_flex_normal.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_pro_flex_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_tpu [values] diff --git a/resources/quality/zyyx/zyyx_agile_pro_pla_fast.inst.cfg b/resources/quality/zyyx/zyyx_agile_pro_pla_fast.inst.cfg index 7ae4be06b0..5b32c3f07b 100644 --- a/resources/quality/zyyx/zyyx_agile_pro_pla_fast.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_pro_pla_fast.inst.cfg @@ -4,7 +4,7 @@ name = Fast definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fast weight = 1 diff --git a/resources/quality/zyyx/zyyx_agile_pro_pla_fine.inst.cfg b/resources/quality/zyyx/zyyx_agile_pro_pla_fine.inst.cfg index 64c7d4afc8..a3849bf5e2 100644 --- a/resources/quality/zyyx/zyyx_agile_pro_pla_fine.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_pro_pla_fine.inst.cfg @@ -4,10 +4,10 @@ name = Fine definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = fine -weight = 3 +weight = 1 material = generic_pla [values] diff --git a/resources/quality/zyyx/zyyx_agile_pro_pla_normal.inst.cfg b/resources/quality/zyyx/zyyx_agile_pro_pla_normal.inst.cfg index dbdd600ece..d126308660 100644 --- a/resources/quality/zyyx/zyyx_agile_pro_pla_normal.inst.cfg +++ b/resources/quality/zyyx/zyyx_agile_pro_pla_normal.inst.cfg @@ -4,10 +4,10 @@ name = Normal definition = zyyx_agile [metadata] -setting_version = 5 +setting_version = 6 type = quality quality_type = normal -weight = 2 +weight = 0 material = generic_pla [values] diff --git a/resources/themes/cura-dark/icons/tab_status_unknown.svg b/resources/themes/cura-dark/icons/tab_status_unknown.svg deleted file mode 100644 index d20218bc00..0000000000 --- a/resources/themes/cura-dark/icons/tab_status_unknown.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Unknown - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/resources/themes/cura-dark/images/logo.svg b/resources/themes/cura-dark/images/logo.svg deleted file mode 100644 index 92ffe4ca0c..0000000000 --- a/resources/themes/cura-dark/images/logo.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 39546b6370..6b29073475 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -5,7 +5,9 @@ }, "colors": { - "sidebar": [39, 44, 48, 255], + "main_background": [39, 44, 48, 255], + "wide_lining": [31, 36, 39, 255], + "thick_lining": [255, 255, 255, 30], "lining": [64, 69, 72, 255], "viewport_overlay": [0, 6, 9, 222], @@ -13,14 +15,20 @@ "primary_hover": [48, 182, 231, 255], "primary_text": [255, 255, 255, 204], "border": [127, 127, 127, 255], - "secondary": [241, 242, 242, 255], + "secondary": [95, 95, 95, 255], - "topbar_background_color": [0, 0, 0, 0], - "topbar_background_color_monitoring": [31, 36, 39, 255], + "icon": [204, 204, 204, 255], + "toolbar_background": [39, 44, 48, 255], + "toolbar_button_active": [95, 95, 95, 255], + "toolbar_button_hover": [95, 95, 95, 255], + "toolbar_button_active_hover": [95, 95, 95, 255], - "topbar_button_text_active": [255, 255, 255, 255], - "topbar_button_text_inactive": [128, 128, 128, 255], - "topbar_button_text_hovered": [255, 255, 255, 255], + "main_window_header_button_text_inactive": [128, 128, 128, 255], + "main_window_header_button_text_hovered": [255, 255, 255, 255], + + "machine_selector_bar": [39, 44, 48, 255], + "machine_selector_active": [39, 44, 48, 255], + "machine_selector_printer_icon": [204, 204, 204, 255], "text": [255, 255, 255, 204], "text_detail": [255, 255, 255, 172], @@ -33,17 +41,10 @@ "text_scene": [255, 255, 255, 162], "text_scene_hover": [255, 255, 255, 204], + "printer_type_label_background": [95, 95, 95, 255], + "error": [212, 31, 53, 255], - "sidebar_header_bar": [39, 44, 48, 255], - "sidebar_header_active": [39, 44, 48, 255], - "sidebar_header_hover": [68, 72, 75, 255], - "sidebar_header_highlight": [68, 192, 255, 255], - "sidebar_header_highlight_hover": [68, 192, 255, 255], - "sidebar_header_text_active": [255, 255, 255, 255], - "sidebar_header_text_hover": [255, 255, 255, 255], - "sidebar_header_text_inactive": [255, 255, 255, 127], - "sidebar_lining": [31, 36, 39, 255], - "sidebar_lining_thin": [255, 255, 255, 30], + "disabled": [32, 32, 32, 255], "button": [39, 44, 48, 255], "button_hover": [39, 44, 48, 255], @@ -101,11 +102,11 @@ "scrollbar_handle_hover": [255, 255, 255, 255], "scrollbar_handle_down": [255, 255, 255, 255], - "setting_category": [39, 44, 48, 255], - "setting_category_disabled": [39, 44, 48, 255], - "setting_category_hover": [39, 44, 48, 255], - "setting_category_active": [39, 44, 48, 255], - "setting_category_active_hover": [39, 44, 48, 255], + "setting_category": [75, 80, 83, 255], + "setting_category_disabled": [75, 80, 83, 255], + "setting_category_hover": [75, 80, 83, 255], + "setting_category_active": [75, 80, 83, 255], + "setting_category_active_hover": [75, 80, 83, 255], "setting_category_text": [255, 255, 255, 152], "setting_category_disabled_text": [255, 255, 255, 101], "setting_category_hover_text": [255, 255, 255, 204], @@ -142,9 +143,7 @@ "slider_groove_border": [127, 127, 127, 255], "slider_groove_fill": [245, 245, 245, 255], "slider_handle": [255, 255, 255, 255], - "slider_handle_hover": [77, 182, 226, 255], "slider_handle_active": [68, 192, 255, 255], - "slider_handle_border": [39, 44, 48, 255], "slider_text_background": [255, 255, 255, 255], "checkbox": [43, 48, 52, 255], @@ -207,21 +206,14 @@ "layerview_support_interface": [64, 192, 255, 255], "layerview_nozzle": [181, 166, 66, 120], - "configuration_item": [0, 0, 0, 0], - "configuration_item_active": [12, 169, 227, 179], - "configuration_item_text": [255, 255, 255, 255], - "configuration_item_text_active": [255, 255, 255, 255], - "configuration_item_border": [255, 255, 255, 255], - "configuration_item_border_active": [12, 169, 227, 179], - "configuration_item_border_hover": [12, 169, 227, 179], - "material_compatibility_warning": [255, 255, 255, 255], "quality_slider_unavailable": [179, 179, 179, 255], "quality_slider_available": [255, 255, 255, 255], - "quality_slider_handle": [255, 255, 255, 255], - "quality_slider_handle_hover": [127, 127, 127, 255], - "quality_slider_text": [255, 255, 255, 255], + + "toolbox_header_button_text_active": [255, 255, 255, 255], + "toolbox_header_button_text_inactive": [128, 128, 128, 255], + "toolbox_header_button_text_hovered": [255, 255, 255, 255], "monitor_card_background_inactive": [43, 48, 52, 255], "monitor_card_background": [43, 48, 52, 255], diff --git a/resources/themes/cura-light/icons/buildplate.svg b/resources/themes/cura-light/icons/buildplate.svg index 9e61296958..7505c8204e 100644 --- a/resources/themes/cura-light/icons/buildplate.svg +++ b/resources/themes/cura-light/icons/buildplate.svg @@ -1,17 +1,9 @@ - - - icn_buildplate - Created with Sketch. - - - - - - - - - - + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/circle_outline.svg b/resources/themes/cura-light/icons/circle_outline.svg new file mode 100644 index 0000000000..3a8fb197f3 --- /dev/null +++ b/resources/themes/cura-light/icons/circle_outline.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/clock.svg b/resources/themes/cura-light/icons/clock.svg new file mode 100644 index 0000000000..0b6cb78881 --- /dev/null +++ b/resources/themes/cura-light/icons/clock.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/themes/cura-light/icons/connected.svg b/resources/themes/cura-light/icons/connected.svg deleted file mode 100644 index 18423bb6c4..0000000000 --- a/resources/themes/cura-light/icons/connected.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/resources/themes/cura-light/icons/disconnected.svg b/resources/themes/cura-light/icons/disconnected.svg deleted file mode 100644 index 019dff117e..0000000000 --- a/resources/themes/cura-light/icons/disconnected.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/resources/themes/cura-light/icons/external_link.svg b/resources/themes/cura-light/icons/external_link.svg new file mode 100644 index 0000000000..a2130fb97b --- /dev/null +++ b/resources/themes/cura-light/icons/external_link.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/extruder_button.svg b/resources/themes/cura-light/icons/extruder_button.svg index e3c01b6a0a..c79ba5c5df 100644 --- a/resources/themes/cura-light/icons/extruder_button.svg +++ b/resources/themes/cura-light/icons/extruder_button.svg @@ -1,64 +1,9 @@ - - - - - - image/svg+xml - - Artboard 3 Copy - - - - - - Artboard 3 Copy - Created with Sketch. - - - + + + + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/grip_lines.svg b/resources/themes/cura-light/icons/grip_lines.svg new file mode 100644 index 0000000000..253d1fb486 --- /dev/null +++ b/resources/themes/cura-light/icons/grip_lines.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/info.svg b/resources/themes/cura-light/icons/info.svg new file mode 100644 index 0000000000..9896b3dac8 --- /dev/null +++ b/resources/themes/cura-light/icons/info.svg @@ -0,0 +1,13 @@ + + + + Icon/ info + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/printer_cloud_connected.svg b/resources/themes/cura-light/icons/printer_cloud_connected.svg new file mode 100644 index 0000000000..3bc94a05e7 --- /dev/null +++ b/resources/themes/cura-light/icons/printer_cloud_connected.svg @@ -0,0 +1,11 @@ + + + + Artboard Copy 2 + Created with Sketch. + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/tab_status_connected.svg b/resources/themes/cura-light/icons/printer_connected.svg similarity index 100% rename from resources/themes/cura-light/icons/tab_status_connected.svg rename to resources/themes/cura-light/icons/printer_connected.svg diff --git a/resources/themes/cura-light/icons/printer_group.svg b/resources/themes/cura-light/icons/printer_group.svg index 614bea90b8..5e439faca4 100644 --- a/resources/themes/cura-light/icons/printer_group.svg +++ b/resources/themes/cura-light/icons/printer_group.svg @@ -1,12 +1,20 @@ - - - icn_groupPrinters + + + Icon/ group printer/ disconnected Created with Sketch. - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/printer_single.svg b/resources/themes/cura-light/icons/printer_single.svg index f7dc83987d..69c4e212bc 100644 --- a/resources/themes/cura-light/icons/printer_single.svg +++ b/resources/themes/cura-light/icons/printer_single.svg @@ -1,13 +1,12 @@ - - - icn_singlePrinter + + + Icon/ single printer/ disconnected Created with Sketch. - - - - - + + + + diff --git a/resources/themes/cura-light/icons/search.svg b/resources/themes/cura-light/icons/search.svg index 8272991300..a9ccb612fd 100644 --- a/resources/themes/cura-light/icons/search.svg +++ b/resources/themes/cura-light/icons/search.svg @@ -1,4 +1,21 @@ - - - + + + + Shape + Created with Sketch. + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/spool.svg b/resources/themes/cura-light/icons/spool.svg new file mode 100644 index 0000000000..0d8ae42d9d --- /dev/null +++ b/resources/themes/cura-light/icons/spool.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/themes/cura-light/icons/star_empty.svg b/resources/themes/cura-light/icons/star_empty.svg new file mode 100644 index 0000000000..39b5791e91 --- /dev/null +++ b/resources/themes/cura-light/icons/star_empty.svg @@ -0,0 +1,11 @@ + + + + Star Copy 8 + Created with Sketch. + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/star_filled.svg b/resources/themes/cura-light/icons/star_filled.svg new file mode 100644 index 0000000000..d4e161f6c6 --- /dev/null +++ b/resources/themes/cura-light/icons/star_filled.svg @@ -0,0 +1,11 @@ + + + + Star Copy 7 + Created with Sketch. + + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/icons/tab_status_busy.svg b/resources/themes/cura-light/icons/tab_status_busy.svg deleted file mode 100644 index debe4f6360..0000000000 --- a/resources/themes/cura-light/icons/tab_status_busy.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Busy - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/resources/themes/cura-light/icons/tab_status_finished.svg b/resources/themes/cura-light/icons/tab_status_finished.svg deleted file mode 100644 index 2519f2f862..0000000000 --- a/resources/themes/cura-light/icons/tab_status_finished.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Wait cleanup - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/resources/themes/cura-light/icons/tab_status_paused.svg b/resources/themes/cura-light/icons/tab_status_paused.svg deleted file mode 100644 index bab6c9ca6b..0000000000 --- a/resources/themes/cura-light/icons/tab_status_paused.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - paused - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/resources/themes/cura-light/icons/tab_status_stopped.svg b/resources/themes/cura-light/icons/tab_status_stopped.svg deleted file mode 100644 index c9b150db3a..0000000000 --- a/resources/themes/cura-light/icons/tab_status_stopped.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Aborted - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/resources/themes/cura-light/icons/tab_status_unknown.svg b/resources/themes/cura-light/icons/tab_status_unknown.svg deleted file mode 100644 index 9f413baffc..0000000000 --- a/resources/themes/cura-light/icons/tab_status_unknown.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Unknown - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/resources/themes/cura-light/icons/warning.svg b/resources/themes/cura-light/icons/warning.svg index ae8a7a6430..14b7d797d0 100644 --- a/resources/themes/cura-light/icons/warning.svg +++ b/resources/themes/cura-light/icons/warning.svg @@ -1,4 +1,11 @@ - - - + + + + Icon/warning-s + Created with Sketch. + + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/images/avatar_default.svg b/resources/themes/cura-light/images/avatar_default.svg new file mode 100644 index 0000000000..7ec704bc8c --- /dev/null +++ b/resources/themes/cura-light/images/avatar_default.svg @@ -0,0 +1,76 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/themes/cura-light/images/avatar_no_user.svg b/resources/themes/cura-light/images/avatar_no_user.svg new file mode 100644 index 0000000000..bef9cb52db --- /dev/null +++ b/resources/themes/cura-light/images/avatar_no_user.svg @@ -0,0 +1,76 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/themes/cura-light/images/logo.svg b/resources/themes/cura-light/images/logo.svg index 5fa5895443..55842ef530 100644 --- a/resources/themes/cura-light/images/logo.svg +++ b/resources/themes/cura-light/images/logo.svg @@ -1,4 +1,6 @@ + + + id="svg8" + inkscape:version="0.92.2 (5c3e80d, 2017-08-06)" + sodipodi:docname="logo.svg"> + + + id="metadata5"> image/svg+xml - + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/themes/cura-light/images/logo_about.svg b/resources/themes/cura-light/images/logo_about.svg new file mode 100644 index 0000000000..34301fd6c9 --- /dev/null +++ b/resources/themes/cura-light/images/logo_about.svg @@ -0,0 +1,172 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/themes/cura-light/styles.qml b/resources/themes/cura-light/styles.qml index b71ddd2d86..121f604362 100755 --- a/resources/themes/cura-light/styles.qml +++ b/resources/themes/cura-light/styles.qml @@ -1,16 +1,20 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. -import QtQuick 2.1 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 +import QtQuick 2.10 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import UM 1.1 as UM -QtObject { - property Component sidebar_header_button: Component { - ButtonStyle { - background: Rectangle { +QtObject +{ + property Component print_setup_header_button: Component + { + ButtonStyle + { + background: Rectangle + { color: { if(control.enabled) @@ -34,6 +38,7 @@ QtObject { } } + radius: UM.Theme.getSize("setting_control_radius").width border.width: Theme.getSize("default_lining").width border.color: { @@ -61,20 +66,21 @@ QtObject { return Theme.getColor("setting_control_disabled_border"); } } - UM.RecolorImage { + UM.RecolorImage + { id: downArrow anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: Theme.getSize("default_margin").width width: Theme.getSize("standard_arrow").width height: Theme.getSize("standard_arrow").height - sourceSize.width: width sourceSize.height: width - color: control.enabled ? Theme.getColor("setting_category_text") : Theme.getColor("setting_category_disabled_text") + color: control.enabled ? Theme.getColor("setting_control_button") : Theme.getColor("setting_category_disabled_text") source: Theme.getIcon("arrow_bottom") } - Label { - id: sidebarComboBoxLabel + Label + { + id: printSetupComboBoxLabel color: control.enabled ? Theme.getColor("setting_control_text") : Theme.getColor("setting_control_disabled_text") text: control.text; elide: Text.ElideRight; @@ -90,178 +96,92 @@ QtObject { } } - property Component topbar_header_tab_no_overlay: Component { - ButtonStyle { - background: Rectangle { - implicitHeight: Theme.getSize("topbar_button").height - implicitWidth: Theme.getSize("topbar_button").width - color: "transparent" - anchors.fill: parent + property Component main_window_header_tab: Component + { + ButtonStyle + { + // This property will be back-propagated when the width of the label is calculated + property var buttonWidth: 0 + background: Item + { + implicitHeight: control.height + implicitWidth: buttonWidth Rectangle { - id: underline + id: buttonFace + implicitHeight: parent.height + implicitWidth: parent.width + radius: UM.Theme.getSize("action_button_radius").width - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom - width: parent.width - height: Theme.getSize("sidebar_header_highlight").height - color: control.checked ? UM.Theme.getColor("sidebar_header_highlight") : UM.Theme.getColor("sidebar_header_highlight_hover") - visible: control.hovered || control.checked - } - } - - label: Rectangle { - implicitHeight: Theme.getSize("topbar_button_icon").height - implicitWidth: Theme.getSize("topbar_button").width - color: "transparent" - anchors.fill: parent - - Item - { - anchors.centerIn: parent - width: Math.round(textLabel.width + icon.width + Theme.getSize("default_margin").width / 2) - Label + color: { - id: textLabel - text: control.text - anchors.right: icon.visible ? icon.left : parent.right - anchors.rightMargin: icon.visible ? Math.round(Theme.getSize("default_margin").width / 2) : 0 - anchors.verticalCenter: parent.verticalCenter; - font: control.checked ? UM.Theme.getFont("large") : UM.Theme.getFont("large_nonbold") - color: + if (control.checked) { - if(control.hovered) - { - return UM.Theme.getColor("topbar_button_text_hovered"); - } - if(control.checked) - { - return UM.Theme.getColor("topbar_button_text_active"); - } - else - { - return UM.Theme.getColor("topbar_button_text_inactive"); - } + return UM.Theme.getColor("main_window_header_button_background_active") + } + else + { + if (control.hovered) + { + return UM.Theme.getColor("main_window_header_button_background_hovered") + } + return UM.Theme.getColor("main_window_header_button_background_inactive") } - } - Image - { - id: icon - visible: control.iconSource != "" - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - opacity: !control.enabled ? 0.2 : 1.0 - source: control.iconSource - width: visible ? Theme.getSize("topbar_button_icon").width : 0 - height: Theme.getSize("topbar_button_icon").height - - sourceSize: Theme.getSize("topbar_button_icon") - } - } - } - } - } - - property Component topbar_header_tab: Component { - ButtonStyle { - background: Item { - implicitHeight: Theme.getSize("topbar_button").height - implicitWidth: Theme.getSize("topbar_button").width + Theme.getSize("topbar_button_icon").width - - Rectangle { - id: buttonFace; - anchors.fill: parent; - - color: "transparent" - Behavior on color { ColorAnimation { duration: 50; } } - - Rectangle { - id: underline; - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - width: Theme.getSize("topbar_button").width + Theme.getSize("topbar_button_icon").width - height: Theme.getSize("sidebar_header_highlight").height - color: control.checked ? UM.Theme.getColor("sidebar_header_highlight") : UM.Theme.getColor("sidebar_header_highlight_hover") - visible: control.hovered || control.checked } } } label: Item { - implicitHeight: Theme.getSize("topbar_button_icon").height - implicitWidth: Theme.getSize("topbar_button").width + Theme.getSize("topbar_button_icon").width - Item + id: contents + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + height: control.height + width: buttonLabel.width + 4 * UM.Theme.getSize("default_margin").width + + Label { + id: buttonLabel + text: control.text + anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter; - width: childrenRect.width - height: Theme.getSize("topbar_button_icon").height - Label + font: UM.Theme.getFont("medium") + color: { - id: button_label - text: control.text; - anchors.verticalCenter: parent.verticalCenter; - font: control.checked ? UM.Theme.getFont("large") : UM.Theme.getFont("large_nonbold") - color: + if (control.checked) { - if(control.hovered) + return UM.Theme.getColor("main_window_header_button_text_active") + } + else + { + if (control.hovered) { - return UM.Theme.getColor("topbar_button_text_hovered"); - } - if(control.checked) - { - return UM.Theme.getColor("topbar_button_text_active"); - } - else - { - return UM.Theme.getColor("topbar_button_text_inactive"); + return UM.Theme.getColor("main_window_header_button_text_hovered") } + return UM.Theme.getColor("main_window_header_button_text_inactive") } } - UM.RecolorImage - { - visible: control.iconSource != "" - id: icon - anchors.left: button_label.right - anchors.leftMargin: (icon.visible || overlayIcon.visible) ? Theme.getSize("default_margin").width : 0 - color: UM.Theme.getColor("text_emphasis") - opacity: !control.enabled ? 0.2 : 1.0 - source: control.iconSource - width: visible ? Theme.getSize("topbar_button_icon").width : 0 - height: Theme.getSize("topbar_button_icon").height - - sourceSize: Theme.getSize("topbar_button_icon") - } - UM.RecolorImage - { - id: overlayIcon - anchors.left: button_label.right - anchors.leftMargin: (icon.visible || overlayIcon.visible) ? Theme.getSize("default_margin").width : 0 - visible: control.overlayIconSource != "" && control.iconSource != "" - color: control.overlayColor - opacity: !control.enabled ? 0.2 : 1.0 - source: control.overlayIconSource - width: visible ? Theme.getSize("topbar_button_icon").width : 0 - height: Theme.getSize("topbar_button_icon").height - - sourceSize: Theme.getSize("topbar_button_icon") - } + } + Component.onCompleted: + { + buttonWidth = width } } } } - property Component tool_button: Component { - ButtonStyle { - background: Item { - implicitWidth: Theme.getSize("button").width; - implicitHeight: Theme.getSize("button").height; + property Component tool_button: Component + { + ButtonStyle + { + background: Item + { + implicitWidth: Theme.getSize("button").width + implicitHeight: Theme.getSize("button").height - UM.PointingRectangle { + UM.PointingRectangle + { id: button_tooltip anchors.left: parent.right @@ -280,23 +200,25 @@ QtObject { Behavior on width { NumberAnimation { duration: 100; } } Behavior on opacity { NumberAnimation { duration: 100; } } - Label { + Label + { id: button_tip anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter; + anchors.verticalCenter: parent.verticalCenter - text: control.text; - font: Theme.getFont("button_tooltip"); - color: Theme.getColor("tooltip_text"); + text: control.text + font: Theme.getFont("default") + color: Theme.getColor("tooltip_text") } } - Rectangle { - id: buttonFace; + Rectangle + { + id: buttonFace - anchors.fill: parent; - property bool down: control.pressed || (control.checkable && control.checked); + anchors.fill: parent + property bool down: control.pressed || (control.checkable && control.checked) color: { @@ -306,87 +228,35 @@ QtObject { } else if(control.checkable && control.checked && control.hovered) { - return Theme.getColor("button_active_hover"); + return Theme.getColor("toolbar_button_active_hover") } else if(control.pressed || (control.checkable && control.checked)) { - return Theme.getColor("button_active"); + return Theme.getColor("toolbar_button_active") } else if(control.hovered) { - return Theme.getColor("button_hover"); - } - else - { - return Theme.getColor("button"); + return Theme.getColor("toolbar_button_hover") } + return Theme.getColor("toolbar_background") } Behavior on color { ColorAnimation { duration: 50; } } - border.width: (control.hasOwnProperty("needBorder") && control.needBorder) ? 2 * screenScaleFactor : 0 - border.color: Theme.getColor("tool_button_border") - - UM.RecolorImage { - id: tool_button_arrow - anchors.right: parent.right; - anchors.rightMargin: Theme.getSize("button").width - Math.round(Theme.getSize("button_icon").width / 4) - anchors.bottom: parent.bottom; - anchors.bottomMargin: Theme.getSize("button").height - Math.round(Theme.getSize("button_icon").height / 4) - width: Theme.getSize("standard_arrow").width - height: Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: width - visible: control.menu != null; - color: - { - if(control.checkable && control.checked && control.hovered) - { - return Theme.getColor("button_text_active_hover"); - } - else if(control.pressed || (control.checkable && control.checked)) - { - return Theme.getColor("button_text_active"); - } - else if(control.hovered) - { - return Theme.getColor("button_text_hover"); - } - else - { - return Theme.getColor("button_text"); - } - } - source: Theme.getIcon("arrow_bottom") - } + border.width: (control.hasOwnProperty("needBorder") && control.needBorder) ? Theme.getSize("default_lining").width : 0 + border.color: Theme.getColor("lining") } } - label: Item { - UM.RecolorImage { - anchors.centerIn: parent; - opacity: !control.enabled ? 0.2 : 1.0 - source: control.iconSource; - width: Theme.getSize("button_icon").width; - height: Theme.getSize("button_icon").height; - color: - { - if(control.checkable && control.checked && control.hovered) - { - return Theme.getColor("button_text_active_hover"); - } - else if(control.pressed || (control.checkable && control.checked)) - { - return Theme.getColor("button_text_active"); - } - else if(control.hovered) - { - return Theme.getColor("button_text_hover"); - } - else - { - return Theme.getColor("button_text"); - } - } + label: Item + { + UM.RecolorImage + { + anchors.centerIn: parent + opacity: control.enabled ? 1.0 : 0.2 + source: control.iconSource + width: Theme.getSize("button_icon").width + height: Theme.getSize("button_icon").height + color: Theme.getColor("icon") sourceSize: Theme.getSize("button_icon") } @@ -394,119 +264,19 @@ QtObject { } } - property Component small_tool_button: Component { - ButtonStyle { - background: Item { - implicitWidth: Theme.getSize("small_button").width; - implicitHeight: Theme.getSize("small_button").height; - - Rectangle { - id: smallButtonFace; - - anchors.fill: parent; - property bool down: control.pressed || (control.checkable && control.checked); - - color: - { - if(control.customColor !== undefined && control.customColor !== null) - { - return control.customColor - } - else if(control.checkable && control.checked && control.hovered) - { - return Theme.getColor("small_button_active_hover"); - } - else if(control.pressed || (control.checkable && control.checked)) - { - return Theme.getColor("small_button_active"); - } - else if(control.hovered) - { - return Theme.getColor("small_button_hover"); - } - else - { - return Theme.getColor("small_button"); - } - } - Behavior on color { ColorAnimation { duration: 50; } } - - border.width: (control.hasOwnProperty("needBorder") && control.needBorder) ? 2 * screenScaleFactor : 0 - border.color: Theme.getColor("tool_button_border") - - UM.RecolorImage { - id: smallToolButtonArrow - - width: 5 - height: 5 - sourceSize.width: 5 - sourceSize.height: 5 - visible: control.menu != null; - color: - { - if(control.checkable && control.checked && control.hovered) - { - return Theme.getColor("small_button_text_active_hover"); - } - else if(control.pressed || (control.checkable && control.checked)) - { - return Theme.getColor("small_button_text_active"); - } - else if(control.hovered) - { - return Theme.getColor("small_button_text_hover"); - } - else - { - return Theme.getColor("small_button_text"); - } - } - source: Theme.getIcon("arrow_bottom") - } - } - } - - label: Item { - UM.RecolorImage { - anchors.centerIn: parent; - opacity: !control.enabled ? 0.2 : 1.0 - source: control.iconSource; - width: Theme.getSize("small_button_icon").width; - height: Theme.getSize("small_button_icon").height; - color: - { - if(control.checkable && control.checked && control.hovered) - { - return Theme.getColor("small_button_text_active_hover"); - } - else if(control.pressed || (control.checkable && control.checked)) - { - return Theme.getColor("small_button_text_active"); - } - else if(control.hovered) - { - return Theme.getColor("small_button_text_hover"); - } - else - { - return Theme.getColor("small_button_text"); - } - } - - sourceSize: Theme.getSize("small_button_icon") - } - } - } - } - - property Component progressbar: Component{ - ProgressBarStyle { - background: Rectangle { + property Component progressbar: Component + { + ProgressBarStyle + { + background: Rectangle + { implicitWidth: Theme.getSize("message").width - (Theme.getSize("default_margin").width * 2) implicitHeight: Theme.getSize("progressbar").height color: control.hasOwnProperty("backgroundColor") ? control.backgroundColor : Theme.getColor("progressbar_background") + radius: Theme.getSize("progressbar_radius").width } - progress: Rectangle { + progress: Rectangle + { color: { if(control.indeterminate) @@ -523,14 +293,16 @@ QtObject { } } radius: Theme.getSize("progressbar_radius").width - Rectangle{ + Rectangle + { radius: Theme.getSize("progressbar_radius").width color: control.hasOwnProperty("controlColor") ? control.controlColor : Theme.getColor("progressbar_control") width: Theme.getSize("progressbar_control").width height: Theme.getSize("progressbar_control").height visible: control.indeterminate - SequentialAnimation on x { + SequentialAnimation on x + { id: xAnim property int animEndPoint: Theme.getSize("message").width - Math.round((Theme.getSize("default_margin").width * 2.5)) - Theme.getSize("progressbar_control").width running: control.indeterminate && control.visible @@ -543,194 +315,41 @@ QtObject { } } - property Component sidebar_category: Component { - ButtonStyle { - background: Rectangle { - anchors.fill: parent; - anchors.left: parent.left - anchors.leftMargin: Theme.getSize("sidebar_margin").width - anchors.right: parent.right - anchors.rightMargin: Theme.getSize("sidebar_margin").width - implicitHeight: Theme.getSize("section").height; - color: { - if(control.color) { - return control.color; - } else if(!control.enabled) { - return Theme.getColor("setting_category_disabled"); - } else if(control.hovered && control.checkable && control.checked) { - return Theme.getColor("setting_category_active_hover"); - } else if(control.pressed || (control.checkable && control.checked)) { - return Theme.getColor("setting_category_active"); - } else if(control.hovered) { - return Theme.getColor("setting_category_hover"); - } else { - return Theme.getColor("setting_category"); - } - } - Behavior on color { ColorAnimation { duration: 50; } } - Rectangle { - height: Theme.getSize("default_lining").height - width: parent.width - anchors.bottom: parent.bottom - color: { - if(!control.enabled) { - return Theme.getColor("setting_category_disabled_border"); - } else if((control.hovered || control.activeFocus) && control.checkable && control.checked) { - return Theme.getColor("setting_category_active_hover_border"); - } else if(control.pressed || (control.checkable && control.checked)) { - return Theme.getColor("setting_category_active_border"); - } else if(control.hovered || control.activeFocus) { - return Theme.getColor("setting_category_hover_border"); - } else { - return Theme.getColor("setting_category_border"); - } - } - } - } - label: Item { - anchors.fill: parent; - anchors.left: parent.left - Item{ - id: icon; - anchors.left: parent.left - height: parent.height - width: Theme.getSize("section_icon_column").width - UM.RecolorImage { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Theme.getSize("sidebar_margin").width - color: - { - if(!control.enabled) - { - return Theme.getColor("setting_category_disabled_text"); - } - else if((control.hovered || control.activeFocus) && control.checkable && control.checked) - { - return Theme.getColor("setting_category_active_hover_text"); - } - else if(control.pressed || (control.checkable && control.checked)) - { - return Theme.getColor("setting_category_active_text"); - } - else if(control.hovered || control.activeFocus) - { - return Theme.getColor("setting_category_hover_text"); - } - else - { - return Theme.getColor("setting_category_text"); - } - } - source: control.iconSource; - width: Theme.getSize("section_icon").width; - height: Theme.getSize("section_icon").height; - sourceSize.width: width + 15 * screenScaleFactor - sourceSize.height: width + 15 * screenScaleFactor - } - } - - Label { - anchors { - left: icon.right; - leftMargin: Theme.getSize("default_margin").width; - right: parent.right; - verticalCenter: parent.verticalCenter; - } - text: control.text; - font: Theme.getFont("setting_category"); - color: - { - if(!control.enabled) - { - return Theme.getColor("setting_category_disabled_text"); - } - else if((control.hovered || control.activeFocus) && control.checkable && control.checked) - { - return Theme.getColor("setting_category_active_hover_text"); - } - else if(control.pressed || (control.checkable && control.checked)) - { - return Theme.getColor("setting_category_active_text"); - } - else if(control.hovered || control.activeFocus) - { - return Theme.getColor("setting_category_hover_text"); - } - else - { - return Theme.getColor("setting_category_text"); - } - } - fontSizeMode: Text.HorizontalFit; - minimumPointSize: 8 - } - UM.RecolorImage { - id: category_arrow - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: Theme.getSize("default_margin").width * 3 - Math.round(width / 2) - width: Theme.getSize("standard_arrow").width - height: Theme.getSize("standard_arrow").height - sourceSize.width: width - sourceSize.height: width - color: - { - if(!control.enabled) - { - return Theme.getColor("setting_category_disabled_text"); - } - else if((control.hovered || control.activeFocus) && control.checkable && control.checked) - { - return Theme.getColor("setting_category_active_hover_text"); - } - else if(control.pressed || (control.checkable && control.checked)) - { - return Theme.getColor("setting_category_active_text"); - } - else if(control.hovered || control.activeFocus) - { - return Theme.getColor("setting_category_hover_text"); - } - else - { - return Theme.getColor("setting_category_text"); - } - } - source: control.checked ? Theme.getIcon("arrow_bottom") : Theme.getIcon("arrow_left") - } - } - } - } - - property Component scrollview: Component { - ScrollViewStyle { + property Component scrollview: Component + { + ScrollViewStyle + { decrementControl: Item { } incrementControl: Item { } transientScrollBars: false - scrollBarBackground: Rectangle { + scrollBarBackground: Rectangle + { implicitWidth: Theme.getSize("scrollbar").width radius: Math.round(implicitWidth / 2) - color: Theme.getColor("scrollbar_background"); + color: Theme.getColor("scrollbar_background") } - handle: Rectangle { + handle: Rectangle + { id: scrollViewHandle - implicitWidth: Theme.getSize("scrollbar").width; + implicitWidth: Theme.getSize("scrollbar").width radius: Math.round(implicitWidth / 2) - color: styleData.pressed ? Theme.getColor("scrollbar_handle_down") : styleData.hovered ? Theme.getColor("scrollbar_handle_hover") : Theme.getColor("scrollbar_handle"); + color: styleData.pressed ? Theme.getColor("scrollbar_handle_down") : styleData.hovered ? Theme.getColor("scrollbar_handle_hover") : Theme.getColor("scrollbar_handle") Behavior on color { ColorAnimation { duration: 50; } } } } } - property Component combobox: Component { - ComboBoxStyle { + property Component combobox: Component + { + ComboBoxStyle + { - background: Rectangle { + background: Rectangle + { implicitHeight: Theme.getSize("setting_control").height; implicitWidth: Theme.getSize("setting_control").width; @@ -739,30 +358,33 @@ QtObject { border.width: Theme.getSize("default_lining").width; border.color: control.hovered ? Theme.getColor("setting_control_border_highlight") : Theme.getColor("setting_control_border"); + radius: UM.Theme.getSize("setting_control_radius").width } - label: Item { - - Label { - anchors.left: parent.left; + label: Item + { + Label + { + anchors.left: parent.left anchors.leftMargin: Theme.getSize("default_lining").width - anchors.right: downArrow.left; - anchors.rightMargin: Theme.getSize("default_lining").width; - anchors.verticalCenter: parent.verticalCenter; + anchors.right: downArrow.left + anchors.rightMargin: Theme.getSize("default_lining").width + anchors.verticalCenter: parent.verticalCenter - text: control.currentText; + text: control.currentText font: Theme.getFont("default"); - color: !enabled ? Theme.getColor("setting_control_disabled_text") : Theme.getColor("setting_control_text"); + color: !enabled ? Theme.getColor("setting_control_disabled_text") : Theme.getColor("setting_control_text") - elide: Text.ElideRight; - verticalAlignment: Text.AlignVCenter; + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter } - UM.RecolorImage { + UM.RecolorImage + { id: downArrow - anchors.right: parent.right; - anchors.rightMargin: Theme.getSize("default_lining").width * 2; - anchors.verticalCenter: parent.verticalCenter; + anchors.right: parent.right + anchors.rightMargin: Theme.getSize("default_lining").width * 2 + anchors.verticalCenter: parent.verticalCenter source: Theme.getIcon("arrow_bottom") width: Theme.getSize("standard_arrow").width @@ -770,26 +392,31 @@ QtObject { sourceSize.width: width + 5 * screenScaleFactor sourceSize.height: width + 5 * screenScaleFactor - color: Theme.getColor("setting_control_text"); + color: Theme.getColor("setting_control_button"); } } } } // Combobox with items with colored rectangles - property Component combobox_color: Component { + property Component combobox_color: Component + { - ComboBoxStyle { + ComboBoxStyle + { - background: Rectangle { + background: Rectangle + { color: !enabled ? UM.Theme.getColor("setting_control_disabled") : control._hovered ? UM.Theme.getColor("setting_control_highlight") : UM.Theme.getColor("setting_control") border.width: UM.Theme.getSize("default_lining").width border.color: !enabled ? UM.Theme.getColor("setting_control_disabled_border") : control._hovered ? UM.Theme.getColor("setting_control_border_highlight") : UM.Theme.getColor("setting_control_border") + radius: UM.Theme.getSize("setting_control_radius").width } - label: Item { - - Label { + label: Item + { + Label + { anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_lining").width anchors.right: swatch.left @@ -804,20 +431,23 @@ QtObject { verticalAlignment: Text.AlignVCenter } - Rectangle { + UM.RecolorImage + { id: swatch - height: Math.round(UM.Theme.getSize("setting_control").height / 2) + height: Math.round(control.height / 2) width: height anchors.right: downArrow.left anchors.verticalCenter: parent.verticalCenter - anchors.margins: Math.round(UM.Theme.getSize("default_margin").width / 4) - radius: Math.round(width / 2) - border.width: UM.Theme.getSize("default_lining").width - border.color: UM.Theme.getColor("lining") + anchors.rightMargin: UM.Theme.getSize("default_margin").width + + sourceSize.width: width + sourceSize.height: height + source: UM.Theme.getIcon("extruder_button") color: (control.color_override !== "") ? control.color_override : control.color } - UM.RecolorImage { + UM.RecolorImage + { id: downArrow anchors.right: parent.right anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2 @@ -829,33 +459,36 @@ QtObject { sourceSize.width: width + 5 * screenScaleFactor sourceSize.height: width + 5 * screenScaleFactor - color: UM.Theme.getColor("setting_control_text") + color: UM.Theme.getColor("setting_control_button") } } } } - property Component checkbox: Component { - CheckBoxStyle { + property Component checkbox: Component + { + CheckBoxStyle + { background: Item { } - indicator: Rectangle { - implicitWidth: Theme.getSize("checkbox").width; - implicitHeight: Theme.getSize("checkbox").height; + indicator: Rectangle + { + implicitWidth: Theme.getSize("checkbox").width + implicitHeight: Theme.getSize("checkbox").height - color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_hover") : Theme.getColor("checkbox"); + color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_hover") : (control.enabled ? Theme.getColor("checkbox") : Theme.getColor("checkbox_disabled")) Behavior on color { ColorAnimation { duration: 50; } } - radius: control.exclusiveGroup ? Math.round(Theme.getSize("checkbox").width / 2) : 0 + radius: control.exclusiveGroup ? Math.round(Theme.getSize("checkbox").width / 2) : Theme.getSize("checkbox_radius").width - border.width: Theme.getSize("default_lining").width; - border.color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_border_hover") : Theme.getColor("checkbox_border"); + border.width: Theme.getSize("default_lining").width + border.color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_border_hover") : Theme.getColor("checkbox_border") - UM.RecolorImage { + UM.RecolorImage + { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter width: Math.round(parent.width / 2.5) height: Math.round(parent.height / 2.5) - sourceSize.width: width sourceSize.height: width color: Theme.getColor("checkbox_mark") source: control.exclusiveGroup ? Theme.getIcon("dot") : Theme.getIcon("check") @@ -863,98 +496,74 @@ QtObject { Behavior on opacity { NumberAnimation { duration: 100; } } } } - label: Label { + label: Label + { text: control.text color: Theme.getColor("checkbox_text") font: Theme.getFont("default") elide: Text.ElideRight + renderType: Text.NativeRendering } } } - property Component partially_checkbox: Component { - CheckBoxStyle { + property Component partially_checkbox: Component + { + CheckBoxStyle + { background: Item { } - indicator: Rectangle { - implicitWidth: Theme.getSize("checkbox").width; - implicitHeight: Theme.getSize("checkbox").height; + indicator: Rectangle + { + implicitWidth: Theme.getSize("checkbox").width + implicitHeight: Theme.getSize("checkbox").height color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_hover") : Theme.getColor("checkbox"); Behavior on color { ColorAnimation { duration: 50; } } - radius: control.exclusiveGroup ? Math.round(Theme.getSize("checkbox").width / 2) : 0 + radius: control.exclusiveGroup ? Math.round(Theme.getSize("checkbox").width / 2) : UM.Theme.getSize("checkbox_radius").width border.width: Theme.getSize("default_lining").width; border.color: (control.hovered || control._hovered) ? Theme.getColor("checkbox_border_hover") : Theme.getColor("checkbox_border"); - UM.RecolorImage { + UM.RecolorImage + { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter width: Math.round(parent.width / 2.5) height: Math.round(parent.height / 2.5) - sourceSize.width: width sourceSize.height: width color: Theme.getColor("checkbox_mark") - source: { - if (control.checkbox_state == 2){ - return Theme.getIcon("solid") + source: + { + if (control.checkbox_state == 2) + { + return Theme.getIcon("solid"); } - else{ - return control.exclusiveGroup ? Theme.getIcon("dot") : Theme.getIcon("check") + else + { + return control.exclusiveGroup ? Theme.getIcon("dot") : Theme.getIcon("check"); } } opacity: control.checked Behavior on opacity { NumberAnimation { duration: 100; } } } } - label: Label { - text: control.text; - color: Theme.getColor("checkbox_text"); - font: Theme.getFont("default"); + label: Label + { + text: control.text + color: Theme.getColor("checkbox_text") + font: Theme.getFont("default") } } } - property Component slider: Component { - SliderStyle { - groove: Rectangle { - implicitWidth: control.width; - implicitHeight: Theme.getSize("slider_groove").height; - - color: Theme.getColor("slider_groove"); - border.width: Theme.getSize("default_lining").width; - border.color: Theme.getColor("slider_groove_border"); - - radius: Math.round(width / 2); - - Rectangle { - anchors { - left: parent.left; - top: parent.top; - bottom: parent.bottom; - } - color: Theme.getColor("slider_groove_fill"); - width: Math.round((control.value / (control.maximumValue - control.minimumValue)) * parent.width); - radius: Math.round(width / 2); - } - } - handle: Rectangle { - width: Theme.getSize("slider_handle").width; - height: Theme.getSize("slider_handle").height; - color: control.hovered ? Theme.getColor("slider_handle_hover") : Theme.getColor("slider_handle"); - border.width: Theme.getSize("default_lining").width - border.color: control.hovered ? Theme.getColor("slider_handle_hover_border") : Theme.getColor("slider_handle_border") - radius: Math.round(Theme.getSize("slider_handle").width / 2); //Round. - Behavior on color { ColorAnimation { duration: 50; } } - } - } - } - - property Component text_field: Component { - TextFieldStyle { - textColor: Theme.getColor("setting_control_text"); + property Component text_field: Component + { + TextFieldStyle + { + textColor: Theme.getColor("setting_control_text") placeholderTextColor: Theme.getColor("setting_control_text") - font: Theme.getFont("default"); + font: Theme.getFont("default") background: Rectangle { @@ -963,10 +572,12 @@ QtObject { border.width: Theme.getSize("default_lining").width; border.color: control.hovered ? Theme.getColor("setting_control_border_highlight") : Theme.getColor("setting_control_border"); + radius: UM.Theme.getSize("setting_control_radius").width color: Theme.getColor("setting_validation_ok"); - Label { + Label + { anchors.right: parent.right; anchors.rightMargin: Theme.getSize("setting_unit_margin").width; anchors.verticalCenter: parent.verticalCenter; @@ -974,12 +585,14 @@ QtObject { text: control.unit ? control.unit : "" color: Theme.getColor("setting_unit"); font: Theme.getFont("default"); + renderType: Text.NativeRendering } } } } - property Component sidebar_action_button: Component { + property Component print_setup_action_button: Component + { ButtonStyle { background: Rectangle @@ -988,28 +601,44 @@ QtObject { border.color: { if(!control.enabled) + { return UM.Theme.getColor("action_button_disabled_border"); + } else if(control.pressed) + { return UM.Theme.getColor("action_button_active_border"); + } else if(control.hovered) + { return UM.Theme.getColor("action_button_hovered_border"); + } else + { return UM.Theme.getColor("action_button_border"); + } } color: { if(!control.enabled) + { return UM.Theme.getColor("action_button_disabled"); + } else if(control.pressed) + { return UM.Theme.getColor("action_button_active"); + } else if(control.hovered) + { return UM.Theme.getColor("action_button_hovered"); + } else + { return UM.Theme.getColor("action_button"); + } } - Behavior on color { ColorAnimation { duration: 50; } } + Behavior on color { ColorAnimation { duration: 50 } } - implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("sidebar_margin").width * 2) + implicitWidth: actualLabel.contentWidth + (UM.Theme.getSize("thick_margin").width * 2) Label { @@ -1018,15 +647,23 @@ QtObject { color: { if(!control.enabled) + { return UM.Theme.getColor("action_button_disabled_text"); + } else if(control.pressed) + { return UM.Theme.getColor("action_button_active_text"); + } else if(control.hovered) + { return UM.Theme.getColor("action_button_hovered_text"); + } else + { return UM.Theme.getColor("action_button_text"); + } } - font: UM.Theme.getFont("action_button") + font: UM.Theme.getFont("medium") text: control.text } } @@ -1034,7 +671,8 @@ QtObject { } } - property Component toolbox_action_button: Component { + property Component toolbox_action_button: Component + { ButtonStyle { background: Rectangle @@ -1045,17 +683,17 @@ QtObject { { if (control.installed) { - return UM.Theme.getColor("action_button_disabled") + return UM.Theme.getColor("action_button_disabled"); } else { if (control.hovered) { - return UM.Theme.getColor("primary_hover") + return UM.Theme.getColor("primary_hover"); } else { - return UM.Theme.getColor("primary") + return UM.Theme.getColor("primary"); } } @@ -1068,17 +706,17 @@ QtObject { { if (control.installed) { - return UM.Theme.getColor("action_button_disabled_text") + return UM.Theme.getColor("action_button_disabled_text"); } else { if (control.hovered) { - return UM.Theme.getColor("button_text_hover") + return UM.Theme.getColor("button_text_hover"); } else { - return UM.Theme.getColor("button_text") + return UM.Theme.getColor("button_text"); } } } @@ -1088,4 +726,153 @@ QtObject { } } } + + property Component monitor_button_style: Component + { + ButtonStyle + { + background: Rectangle + { + border.width: UM.Theme.getSize("default_lining").width + border.color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled_border"); + } + else if(control.pressed) + { + return UM.Theme.getColor("action_button_active_border"); + } + else if(control.hovered) + { + return UM.Theme.getColor("action_button_hovered_border"); + } + return UM.Theme.getColor("action_button_border"); + } + color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled"); + } + else if(control.pressed) + { + return UM.Theme.getColor("action_button_active"); + } + else if(control.hovered) + { + return UM.Theme.getColor("action_button_hovered"); + } + return UM.Theme.getColor("action_button"); + } + Behavior on color + { + ColorAnimation + { + duration: 50 + } + } + } + + label: Item + { + UM.RecolorImage + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + width: Math.floor(control.width / 2) + height: Math.floor(control.height / 2) + sourceSize.height: width + color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled_text"); + } + else if(control.pressed) + { + return UM.Theme.getColor("action_button_active_text"); + } + else if(control.hovered) + { + return UM.Theme.getColor("action_button_hovered_text"); + } + return UM.Theme.getColor("action_button_text"); + } + source: control.iconSource + } + } + } + } + + property Component monitor_checkable_button_style: Component + { + ButtonStyle { + background: Rectangle { + border.width: control.checked ? UM.Theme.getSize("default_lining").width * 2 : UM.Theme.getSize("default_lining").width + border.color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled_border"); + } + else if (control.checked || control.pressed) + { + return UM.Theme.getColor("action_button_active_border"); + } + else if(control.hovered) + { + return UM.Theme.getColor("action_button_hovered_border"); + } + return UM.Theme.getColor("action_button_border"); + } + color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled"); + } + else if (control.checked || control.pressed) + { + return UM.Theme.getColor("action_button_active"); + } + else if (control.hovered) + { + return UM.Theme.getColor("action_button_hovered"); + } + return UM.Theme.getColor("action_button"); + } + Behavior on color { ColorAnimation { duration: 50; } } + Label { + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: UM.Theme.getSize("default_lining").width * 2 + anchors.rightMargin: UM.Theme.getSize("default_lining").width * 2 + color: + { + if(!control.enabled) + { + return UM.Theme.getColor("action_button_disabled_text"); + } + else if (control.checked || control.pressed) + { + return UM.Theme.getColor("action_button_active_text"); + } + else if (control.hovered) + { + return UM.Theme.getColor("action_button_hovered_text"); + } + return UM.Theme.getColor("action_button_text"); + } + font: UM.Theme.getFont("default") + text: control.text + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideMiddle + } + } + label: Item { } + } + } } diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 25c9a678c1..4938bd1aae 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -6,15 +6,45 @@ "fonts": { "large": { "size": 1.35, - "weight": 63, + "weight": 40, "family": "Noto Sans" }, - "large_nonbold": { + "large_ja_JP": { "size": 1.35, "weight": 50, "family": "Noto Sans" }, + "large_zh_CN": { + "size": 1.35, + "weight": 50, + "family": "Noto Sans" + }, + "large_zh_TW": { + "size": 1.35, + "weight": 50, + "family": "Noto Sans" + }, + "large_bold": { + "size": 1.35, + "weight": 63, + "family": "Noto Sans" + }, "medium": { + "size": 1.16, + "weight": 40, + "family": "Noto Sans" + }, + "medium_ja_JP": { + "size": 1.16, + "weight": 50, + "family": "Noto Sans" + }, + "medium_zh_CN": { + "size": 1.16, + "weight": 50, + "family": "Noto Sans" + }, + "medium_zh_TW": { "size": 1.16, "weight": 50, "family": "Noto Sans" @@ -25,43 +55,86 @@ "family": "Noto Sans" }, "default": { + "size": 0.95, + "weight": 40, + "family": "Noto Sans" + }, + "default_ja_JP": { + "size": 1.0, + "weight": 50, + "family": "Noto Sans" + }, + "default_zh_CN": { + "size": 1.0, + "weight": 50, + "family": "Noto Sans" + }, + "default_zh_TW": { "size": 1.0, "weight": 50, "family": "Noto Sans" }, "default_bold": { + "size": 0.95, + "weight": 63, + "family": "Noto Sans" + }, + "default_bold_ja_JP": { + "size": 1.0, + "weight": 63, + "family": "Noto Sans" + }, + "default_bold_zh_CN": { + "size": 1.0, + "weight": 63, + "family": "Noto Sans" + }, + "default_bold_zh_TW": { "size": 1.0, "weight": 63, "family": "Noto Sans" }, "default_italic": { - "size": 1.15, + "size": 0.95, + "weight": 40, + "italic": true, + "family": "Noto Sans" + }, + "default_italic_ja_JP": { + "size": 1.0, + "weight": 50, + "italic": true, + "family": "Noto Sans" + }, + "default_italic_zh_CN": { + "size": 1.0, + "weight": 50, + "italic": true, + "family": "Noto Sans" + }, + "default_italic_zh_TW": { + "size": 1.0, "weight": 50, "italic": true, "family": "Noto Sans" }, "small": { - "size": 1.0, - "weight": 63, + "size": 0.7, + "weight": 40, "family": "Noto Sans" }, - "very_small": { - "size": 1.0, + "small_ja_JP": { + "size": 0.7, "weight": 50, "family": "Noto Sans" }, - "button_tooltip": { - "size": 1.0, + "small_zh_CN": { + "size": 0.7, "weight": 50, "family": "Noto Sans" }, - "setting_category": { - "size": 1.15, - "weight": 63, - "family": "Noto Sans" - }, - "action_button": { - "size": 1.15, + "small_zh_TW": { + "size": 0.7, "weight": 50, "family": "Noto Sans" } @@ -69,46 +142,73 @@ "colors": { - "sidebar": [255, 255, 255, 255], + "main_background": [255, 255, 255, 255], + "wide_lining": [245, 245, 245, 255], + "thick_lining": [127, 127, 127, 255], "lining": [192, 193, 194, 255], "viewport_overlay": [0, 0, 0, 192], - "primary": [12, 169, 227, 255], + "primary": [50, 130, 255, 255], + "primary_shadow": [64, 47, 205, 255], "primary_hover": [48, 182, 231, 255], "primary_text": [255, 255, 255, 255], "border": [127, 127, 127, 255], - "secondary": [245, 245, 245, 255], + "secondary": [240, 240, 240, 255], + "secondary_shadow": [216, 216, 216, 255], - "topbar_background_color": [255, 255, 255, 0], - "topbar_background_color_monitoring": [255, 255, 255, 255], + "icon": [8, 7, 63, 255], - "topbar_button_text_active": [0, 0, 0, 255], - "topbar_button_text_inactive": [128, 128, 128, 255], - "topbar_button_text_hovered": [0, 0, 0, 255], + "primary_button": [38, 113, 231, 255], + "primary_button_shadow": [27, 95, 202, 255], + "primary_button_hover": [81, 145, 247, 255], + "primary_button_text": [255, 255, 255, 255], - "text": [0, 0, 0, 255], + "secondary_button": [240, 240, 240, 255], + "secondary_button_shadow": [216, 216, 216, 255], + "secondary_button_hover": [228, 228, 228, 255], + "secondary_button_text": [30, 102, 215, 255], + + "main_window_header_background": [8, 7, 63, 255], + "main_window_header_background_gradient": [25, 23, 91, 255], + "main_window_header_button_text_active": [8, 7, 63, 255], + "main_window_header_button_text_inactive": [255, 255, 255, 255], + "main_window_header_button_text_hovered": [255, 255, 255, 255], + "main_window_header_button_background_active": [255, 255, 255, 255], + "main_window_header_button_background_inactive": [255, 255, 255, 0], + "main_window_header_button_background_hovered": [117, 114, 159, 255], + + "account_widget_outline_active": [70, 66, 126, 255], + + "machine_selector_bar": [31, 36, 39, 255], + "machine_selector_active": [68, 72, 75, 255], + "machine_selector_hover": [68, 72, 75, 255], + "machine_selector_text_active": [255, 255, 255, 255], + "machine_selector_printer_icon": [8, 7, 63, 255], + + "action_panel_secondary": [27, 95, 202, 255], + + "toolbar_background": [255, 255, 255, 255], + + "printer_type_label_background": [228, 228, 242, 255], + + "text": [25, 25, 25, 255], "text_detail": [174, 174, 174, 128], - "text_link": [12, 169, 227, 255], + "text_link": [50, 130, 255, 255], "text_inactive": [174, 174, 174, 255], - "text_hover": [70, 84, 113, 255], - "text_pressed": [12, 169, 227, 255], + "text_pressed": [50, 130, 255, 255], "text_subtext": [0, 0, 0, 255], "text_medium": [128, 128, 128, 255], "text_emphasis": [255, 255, 255, 255], - "text_scene": [31, 36, 39, 255], - "text_scene_hover": [70, 84, 113, 255], + "text_scene": [102, 102, 102, 255], + "text_scene_hover": [123, 123, 113, 255], "error": [255, 140, 0, 255], - "sidebar_header_bar": [31, 36, 39, 255], - "sidebar_header_active": [68, 72, 75, 255], - "sidebar_header_hover": [68, 72, 75, 255], - "sidebar_header_highlight": [68, 192, 255, 255], - "sidebar_header_highlight_hover": [68, 192, 255, 255], - "sidebar_header_text_inactive": [255, 255, 255, 255], - "sidebar_header_text_active": [255, 255, 255, 255], - "sidebar_header_text_hover": [255, 255, 255, 255], - "sidebar_lining": [245, 245, 245, 255], - "sidebar_lining_thin": [127, 127, 127, 255], + "warning": [245, 166, 35, 255], + "disabled": [229, 229, 229, 255], + + "toolbar_button_hover": [232, 242, 252, 255], + "toolbar_button_active": [232, 242, 252, 255], + "toolbar_button_active_hover": [232, 242, 252, 255], "button": [31, 36, 39, 255], "button_hover": [68, 72, 75, 255], @@ -118,15 +218,13 @@ "button_text_hover": [255, 255, 255, 255], "button_text_active": [255, 255, 255, 255], "button_text_active_hover": [255, 255, 255, 255], - "button_disabled": [31, 36, 39, 255], - "button_disabled_text": [255, 255, 255, 101], - "small_button": [31, 36, 39, 0], - "small_button_hover": [68, 72, 75, 255], - "small_button_active": [68, 72, 75, 255], - "small_button_active_hover": [68, 72, 75, 255], - "small_button_text": [31, 36, 39, 197], - "small_button_text_hover": [255, 255, 255, 255], + "small_button": [0, 0, 0, 0], + "small_button_hover": [102, 102, 102, 255], + "small_button_active": [10, 8, 80, 255], + "small_button_active_hover": [10, 8, 80, 255], + "small_button_text": [102, 102, 102, 255], + "small_button_text_hover": [8, 7, 63, 255], "small_button_text_active": [255, 255, 255, 255], "small_button_text_active_hover": [255, 255, 255, 255], @@ -136,60 +234,55 @@ "extruder_button_material_border": [255, 255, 255, 255], + "rating_star": [90, 90, 90, 255], + "sync_button_text": [120, 120, 120, 255], "sync_button_text_hovered": [0, 0, 0, 255], "action_button": [255, 255, 255, 255], "action_button_text": [0, 0, 0, 255], "action_button_border": [127, 127, 127, 255], - "action_button_hovered": [255, 255, 255, 255], + "action_button_hovered": [232, 242, 252, 255], "action_button_hovered_text": [31, 36, 39, 255], - "action_button_hovered_border": [12, 169, 227, 255], + "action_button_hovered_border": [50, 130, 255, 255], "action_button_active": [255, 255, 255, 255], "action_button_active_text": [0, 0, 0, 255], - "action_button_active_border": [12, 169, 227, 255], + "action_button_active_border": [50, 130, 255, 255], "action_button_disabled": [245, 245, 245, 255], "action_button_disabled_text": [127, 127, 127, 255], "action_button_disabled_border": [245, 245, 245, 255], - - "print_button_ready": [12, 169, 227, 255], - "print_button_ready_border": [12, 169, 227, 255], - "print_button_ready_text": [255, 255, 255, 255], - "print_button_ready_hovered": [30, 186, 245, 243], - "print_button_ready_hovered_border": [30, 186, 245, 243], - "print_button_ready_pressed": [30, 186, 245, 243], - "print_button_ready_pressed_border": [30, 186, 245, 243], + "action_button_shadow": [223, 223, 223, 255], + "action_button_disabled_shadow": [228, 228, 228, 255], "scrollbar_background": [255, 255, 255, 255], - "scrollbar_handle": [31, 36, 39, 255], - "scrollbar_handle_hover": [12, 159, 227, 255], - "scrollbar_handle_down": [12, 159, 227, 255], + "scrollbar_handle": [10, 8, 80, 255], + "scrollbar_handle_hover": [50, 130, 255, 255], + "scrollbar_handle_down": [50, 130, 255, 255], - "setting_category": [245, 245, 245, 255], + "setting_category": [240, 240, 240, 255], "setting_category_disabled": [255, 255, 255, 255], - "setting_category_hover": [245, 245, 245, 255], - "setting_category_active": [245, 245, 245, 255], - "setting_category_active_hover": [245, 245, 245, 255], - "setting_category_text": [31, 36, 39, 255], + "setting_category_hover": [232, 242, 252, 255], + "setting_category_active": [240, 240, 240, 255], + "setting_category_active_hover": [232, 242, 252, 255], + "setting_category_text": [35, 35, 35, 255], "setting_category_disabled_text": [24, 41, 77, 101], - "setting_category_hover_text": [31, 36, 39, 255], - "setting_category_active_text": [31, 36, 39, 255], - "setting_category_active_hover_text": [31, 36, 39, 255], - "setting_category_border": [245, 245, 245, 255], - "setting_category_disabled_border": [245, 245, 245, 255], - "setting_category_hover_border": [12, 159, 227, 255], - "setting_category_active_border": [245, 245, 245, 255], - "setting_category_active_hover_border": [12, 159, 227, 255], + "setting_category_hover_text": [35, 35, 35, 255], + "setting_category_active_text": [35, 35, 35, 255], + "setting_category_active_hover_text": [35, 35, 35, 255], + "setting_category_border": [240, 240, 240, 255], + "setting_category_disabled_border": [240, 240, 240, 255], + "setting_category_hover_border": [50, 130, 255, 255], + "setting_category_active_border": [50, 130, 255, 255], + "setting_category_active_hover_border": [50, 130, 255, 255], "setting_control": [255, 255, 255, 255], "setting_control_selected": [31, 36, 39, 255], "setting_control_highlight": [255, 255, 255, 255], - "setting_control_border": [127, 127, 127, 255], - "setting_control_border_highlight": [12, 169, 227, 255], - "setting_control_text": [27, 27, 27, 255], - "setting_control_depth_line": [127, 127, 127, 255], - "setting_control_button": [127, 127, 127, 255], - "setting_control_button_hover": [70, 84, 113, 255], + "setting_control_border": [199, 199, 199, 255], + "setting_control_border_highlight": [50, 130, 255, 255], + "setting_control_text": [35, 35, 35, 255], + "setting_control_button": [102, 102, 102, 255], + "setting_control_button_hover": [8, 7, 63, 255], "setting_control_disabled": [245, 245, 245, 255], "setting_control_disabled_text": [127, 127, 127, 255], "setting_control_disabled_border": [127, 127, 127, 255], @@ -199,66 +292,53 @@ "setting_validation_warning_background": [255, 145, 62, 255], "setting_validation_warning": [127, 127, 127, 255], "setting_validation_ok": [255, 255, 255, 255], + "setting_filter_field" : [153, 153, 153, 255], "material_compatibility_warning": [0, 0, 0, 255], "progressbar_background": [245, 245, 245, 255], - "progressbar_control": [31, 36, 39, 255], + "progressbar_control": [50, 130, 255, 255], - "slider_groove": [245, 245, 245, 255], - "slider_groove_border": [127, 127, 127, 255], - "slider_groove_fill": [127, 127, 127, 255], - "slider_handle": [0, 0, 0, 255], - "slider_handle_hover": [77, 182, 226, 255], - "slider_handle_active": [68, 192, 255, 255], - "slider_handle_border": [39, 44, 48, 255], + "slider_groove": [223, 223, 223, 255], + "slider_groove_fill": [8, 7, 63, 255], + "slider_handle": [8, 7, 63, 255], + "slider_handle_active": [50, 130, 255, 255], "slider_text_background": [255, 255, 255, 255], "quality_slider_unavailable": [179, 179, 179, 255], "quality_slider_available": [0, 0, 0, 255], - "quality_slider_handle": [0, 0, 0, 255], - "quality_slider_handle_hover": [127, 127, 127, 255], - "quality_slider_text": [0, 0, 0, 255], "checkbox": [255, 255, 255, 255], "checkbox_hover": [255, 255, 255, 255], - "checkbox_border": [64, 69, 72, 255], - "checkbox_border_hover": [12, 169, 227, 255], - "checkbox_mark": [119, 122, 124, 255], - "checkbox_text": [27, 27, 27, 255], + "checkbox_border": [199, 199, 199, 255], + "checkbox_border_hover": [50, 130, 255, 255], + "checkbox_mark": [50, 130, 255, 255], + "checkbox_disabled": [223, 223, 223, 255], + "checkbox_text": [35, 35, 35, 255], - "mode_switch": [255, 255, 255, 255], - "mode_switch_hover": [255, 255, 255, 255], - "mode_switch_border": [127, 127, 127, 255], - "mode_switch_border_hover": [12, 169, 227, 255], - "mode_switch_handle": [31, 36, 39, 255], - "mode_switch_text": [31, 36, 39, 255], - "mode_switch_text_hover": [31, 36, 39, 255], - "mode_switch_text_checked": [12, 169, 227, 255], - - "tooltip": [68, 192, 255, 255], + "tooltip": [25, 25, 25, 255], "tooltip_text": [255, 255, 255, 255], - "tool_button_border": [255, 255, 255, 0], - "message_background": [255, 255, 255, 255], "message_shadow": [0, 0, 0, 120], - "message_border": [127, 127, 127, 255], + "message_border": [192, 193, 194, 255], "message_text": [0, 0, 0, 255], - "message_button": [12, 169, 227, 255], - "message_button_hover": [12, 169, 227, 255], - "message_button_active": [12, 169, 227, 255], + "message_close": [102, 102, 102, 255], + "message_close_hover": [8, 7, 63, 255], + "message_button": [38, 113, 231, 255], + "message_button_hover": [81, 145, 247, 255], + "message_button_active": [38, 113, 231, 255], "message_button_text": [255, 255, 255, 255], "message_button_text_hover": [255, 255, 255, 255], "message_button_text_active": [255, 255, 255, 255], - "message_progressbar_background": [200, 200, 200, 255], - "message_progressbar_control": [77, 182, 226, 255], + "message_progressbar_background": [245, 245, 245, 255], + "message_progressbar_control": [50, 130, 255, 255], "tool_panel_background": [255, 255, 255, 255], "status_offline": [0, 0, 0, 255], "status_ready": [0, 205, 0, 255], - "status_busy": [12, 169, 227, 255], + "status_busy": [50, 130, 255, 255], "status_paused": [255, 140, 0, 255], "status_stopped": [236, 82, 80, 255], "status_unknown": [127, 127, 127, 255], @@ -269,8 +349,8 @@ "z_axis": [0, 255, 0, 255], "all_axis": [255, 255, 255, 255], - "viewport_background": [245, 245, 245, 255], - "volume_outline": [12, 169, 227, 255], + "viewport_background": [250, 250, 250, 255], + "volume_outline": [50, 130, 255, 255], "buildplate": [244, 244, 244, 255], "buildplate_grid": [129, 131, 134, 255], "buildplate_grid_minor": [230, 230, 231, 255], @@ -283,40 +363,37 @@ "model_overhang": [255, 0, 0, 255], "model_unslicable": [122, 122, 122, 255], "model_unslicable_alt": [172, 172, 127, 255], - "model_selection_outline": [12, 169, 227, 255], + "model_selection_outline": [50, 130, 255, 255], "model_non_printing": [122, 122, 122, 255], "xray": [26, 26, 62, 255], "xray_error": [255, 0, 0, 255], "layerview_ghost": [32, 32, 32, 96], - "layerview_none": [255, 255, 255, 255], - "layerview_inset_0": [255, 0, 0, 255], - "layerview_inset_x": [0, 255, 0, 255], - "layerview_skin": [255, 255, 0, 255], - "layerview_support": [0, 255, 255, 255], - "layerview_skirt": [0, 255, 255, 255], - "layerview_infill": [255, 192, 0, 255], - "layerview_support_infill": [0, 255, 255, 255], - "layerview_move_combing": [0, 0, 255, 255], - "layerview_move_retraction": [128, 128, 255, 255], + "layerview_none": [255, 255, 255, 255], + "layerview_inset_0": [255, 0, 0, 255], + "layerview_inset_x": [0, 255, 0, 255], + "layerview_skin": [255, 255, 0, 255], + "layerview_support": [0, 255, 255, 255], + "layerview_skirt": [0, 255, 255, 255], + "layerview_infill": [255, 192, 0, 255], + "layerview_support_infill": [0, 255, 255, 255], + "layerview_move_combing": [0, 0, 255, 255], + "layerview_move_retraction": [128, 128, 255, 255], "layerview_support_interface": [64, 192, 255, 255], + "layerview_prime_tower": [0, 255, 255, 255], "layerview_nozzle": [181, 166, 66, 50], - "configuration_item": [255, 255, 255, 0], - "configuration_item_active": [12, 169, 227, 32], - "configuration_item_text": [0, 0, 0, 255], - "configuration_item_text_active": [0, 0, 0, 255], - "configuration_item_border": [127, 127, 127, 255], - "configuration_item_border_active": [12, 169, 227, 32], - "configuration_item_border_hover": [12, 169, 227, 255], - - "tab_status_connected": [12, 169, 227, 255], + "tab_status_connected": [50, 130, 255, 255], "tab_status_disconnected": [200, 200, 200, 255], - "printer_config_matched": [12, 169, 227, 255], + "printer_config_matched": [50, 130, 255, 255], "printer_config_mismatch": [127, 127, 127, 255], + "toolbox_header_button_text_active": [0, 0, 0, 255], + "toolbox_header_button_text_inactive": [0, 0, 0, 255], + "toolbox_header_button_text_hovered": [0, 0, 0, 255], + "favorites_header_bar": [245, 245, 245, 255], "favorites_header_hover": [245, 245, 245, 255], "favorites_header_text": [31, 36, 39, 255], @@ -334,12 +411,12 @@ "monitor_pill_background": [245, 245, 245, 255], "monitor_placeholder_image": [230, 230, 230, 255], "monitor_printer_icon_inactive": [154, 154, 154, 255], - "monitor_printer_icon": [12, 169, 227, 255], + "monitor_printer_icon": [50, 130, 255, 255], "monitor_progress_background_text": [0,0,0,255], "monitor_progress_background": [245, 245, 245, 255], "monitor_progress_fill_inactive": [154, 154, 154, 255], "monitor_progress_fill_text": [255,255,255,255], - "monitor_progress_fill": [12, 169, 227, 255], + "monitor_progress_fill": [50, 130, 255, 255], "monitor_shadow": [0, 0, 0, 63], "monitor_skeleton_fill": [245, 245, 245, 255], "monitor_skeleton_fill_dark": [216, 216, 216, 255], @@ -347,42 +424,67 @@ }, "sizes": { - "window_minimum_size": [70, 50], + "window_minimum_size": [100, 60], + "main_window_header": [0.0, 4.0], + "main_window_header_button": [8, 2.35], + "main_window_header_button_icon": [1.2, 1.2], + + "stage_menu": [0.0, 4.0], + + "account_button": [12, 3], + + "print_setup_widget": [38.0, 30.0], + "print_setup_mode_toggle": [0.0, 2.0], + "print_setup_item": [0.0, 2.0], + "print_setup_extruder_box": [0.0, 6.0], + "print_setup_slider_groove": [0.16, 0.16], + "print_setup_slider_handle": [1.0, 1.0], + "print_setup_slider_tickmarks": [0.32, 0.32], + "print_setup_big_item": [28, 2.5], + "print_setup_icon": [1.2, 1.2], + + "expandable_component_content_header": [0.0, 3.0], + + "configuration_selector": [35.0, 4.0], + "configuration_selector_mode_tabs": [0.0, 3.0], + + "action_panel_widget": [26.0, 0.0], + "action_panel_information_widget": [20.0, 0.0], + + "machine_selector_widget": [20.0, 4.0], + "machine_selector_widget_content": [25.0, 32.0], + "machine_selector_icon": [2.66, 2.66], + + "views_selector": [23.0, 4.0], + + "printer_type_label": [3.5, 1.5], + + "default_radius": [0.25, 0.25], + + "wide_lining": [0.5, 0.5], + "thick_lining": [0.2, 0.2], "default_lining": [0.08, 0.08], + "default_arrow": [0.8, 0.8], - "logo": [7.6, 1.6], + "logo": [8, 2.4], - "default_margin": [1.0, 1.0], "wide_margin": [2.0, 2.0], + "thick_margin": [1.71, 1.43], + "default_margin": [1.0, 1.0], + "thin_margin": [0.71, 0.71], "narrow_margin": [0.5, 0.5], - "window_margin": [1.0, 1.0], - "extruder_button_material_margin": [0.70, 0.9], - "extruder_button_material": [0.75, 0.75], + "extruder_icon": [2.33, 2.33], - "sidebar": [35.0, 10.0], - "sidebar_margin": [1.71, 1.43], - "sidebar_margin_thin": [0.71, 0.71], - "sidebar_header": [0.0, 4.0], - "sidebar_header_highlight": [0.25, 0.25], - "sidebar_header_mode_toggle": [0.0, 2.0], - "sidebar_header_mode_tabs": [0.0, 3.0], - "sidebar_lining": [0.5, 0.5], - "sidebar_lining_thin": [0.2, 0.2], - "sidebar_setup": [0.0, 2.0], - "sidebar_tabs": [0.0, 3.5], - "sidebar_inputfields": [0.0, 2.0], - "sidebar_extruder_box": [0.0, 6.0], - "simple_mode_infill_caption": [0.0, 5.0], - "simple_mode_infill_height": [0.0, 8.0], - - "section": [0.0, 2.2], + "section": [0.0, 2], "section_icon": [1.6, 1.6], "section_icon_column": [2.8, 0.0], + "rating_star": [1.0, 1.0], "setting": [25.0, 1.8], - "setting_control": [10.0, 2.0], + "setting_control": [11.0, 2.0], + "setting_control_radius": [0.15, 0.15], "setting_control_depth_margin": [1.4, 0.0], "setting_preferences_button_margin": [4, 0.0], "setting_control_margin": [0.0, 0.0], @@ -390,13 +492,16 @@ "setting_text_maxwidth": [40.0, 0.0], "standard_list_lineheight": [1.5, 1.5], - "standard_list_input": [20.0, 25.0], - "standard_arrow": [0.8, 0.8], + "standard_arrow": [1.0, 1.0], "button": [4, 4], "button_icon": [2.5, 2.5], "button_lining": [0, 0], + "action_button": [15.0, 3.0], + "action_button_icon": [1.0, 1.0], + "action_button_radius": [0.15, 0.15], + "small_button": [2, 2], "small_button_icon": [1.5, 1.5], @@ -404,42 +509,32 @@ "favorites_button": [2, 2], "favorites_button_icon": [1.2, 1.2], - "printer_status_icon": [1.8, 1.8], + "printer_status_icon": [1.0, 1.0], "printer_sync_icon": [1.2, 1.2], - "topbar_logo_right_margin": [3, 0], - "topbar_button": [8, 4], - "topbar_button_icon": [1.2, 1.2], - "button_tooltip": [1.0, 1.3], "button_tooltip_arrow": [0.25, 0.25], "tool_button_border": [1.0, 0], - "progressbar": [26.0, 0.4], - "progressbar_radius": [0, 0], - "progressbar_control": [8.0, 0.4], + "progressbar": [26.0, 0.75], + "progressbar_radius": [0.15, 0.15], + "progressbar_control": [8.0, 0.75], "scrollbar": [0.75, 0.5], - "quality_slider_bar": [1, 0.2], + "slider_groove": [0.5, 0.5], + "slider_groove_radius": [0.15, 0.15], + "slider_handle": [1.5, 1.5], + "slider_layerview_size": [1.0, 26.0], - "slider_groove": [0.3, 0.3], - "slider_handle": [1.0, 1.0], - "slider_layerview_size": [1.0, 22.0], - "slider_layerview_background": [4.0, 0.0], - "slider_layerview_margin": [1.0, 1.5], - - "layerview_menu_size": [15, 20], - "layerview_menu_size_material_color_mode": [15, 16], - "layerview_menu_size_collapsed": [15, 6], - "layerview_menu_size_compatibility": [22, 22.0], - "layerview_menu_size_compatibility_collapsed": [15, 3.5], + "layerview_menu_size": [16.0, 4.0], "layerview_legend_size": [1.0, 1.0], "layerview_row": [11.0, 1.5], "layerview_row_spacing": [0.0, 0.5], - "checkbox": [2.0, 2.0], + "checkbox": [1.5, 1.5], + "checkbox_radius": [0.08, 0.08], "tooltip": [20.0, 10.0], "tooltip_margins": [1.0, 1.0], @@ -463,6 +558,8 @@ "message_shadow": [0, 0], "message_margin": [0, 1.0], "message_inner_margin": [1.5, 1.5], + "message_radius": [0.25, 0.25], + "message_button_radius": [0.15, 0.15], "infill_button_margin": [0.5, 0.5], @@ -483,16 +580,19 @@ "toolbox_detail_header": [1.0, 14.0], "toolbox_detail_tile": [1.0, 8.0], "toolbox_back_column": [6.0, 1.0], - "toolbox_back_button": [4.0, 2.0], + "toolbox_back_button": [6.0, 2.0], "toolbox_installed_tile": [1.0, 8.0], "toolbox_property_label": [1.0, 2.0], - "toolbox_heading_label": [1.0, 4.0], + "toolbox_heading_label": [1.0, 3.8], "toolbox_header": [1.0, 4.0], + "toolbox_header_highlight": [0.25, 0.25], "toolbox_progress_bar": [8.0, 0.5], "toolbox_chart_row": [1.0, 2.0], "toolbox_action_button": [8.0, 2.5], "toolbox_loader": [2.0, 2.0], + "avatar_image": [6.8, 6.8], + "monitor_config_override_box": [1.0, 14.0], "monitor_extruder_circle": [2.75, 2.75], "monitor_text_line": [1.16, 1.16], diff --git a/resources/variants/cartesio_0.25.inst.cfg b/resources/variants/cartesio_0.25.inst.cfg index b3aae8a393..53048622f2 100644 --- a/resources/variants/cartesio_0.25.inst.cfg +++ b/resources/variants/cartesio_0.25.inst.cfg @@ -5,7 +5,7 @@ definition = cartesio [metadata] author = Cartesio -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/cartesio_0.4.inst.cfg b/resources/variants/cartesio_0.4.inst.cfg index 5cea5823c4..3ad6b3f3d9 100644 --- a/resources/variants/cartesio_0.4.inst.cfg +++ b/resources/variants/cartesio_0.4.inst.cfg @@ -5,7 +5,7 @@ definition = cartesio [metadata] author = Cartesio -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/cartesio_0.8.inst.cfg b/resources/variants/cartesio_0.8.inst.cfg index b4009cf9ed..f19c4d58d4 100644 --- a/resources/variants/cartesio_0.8.inst.cfg +++ b/resources/variants/cartesio_0.8.inst.cfg @@ -5,7 +5,7 @@ definition = cartesio [metadata] author = Cartesio -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/fabtotum_hyb35.inst.cfg b/resources/variants/fabtotum_hyb35.inst.cfg index d3f0077792..5ed9eca26a 100644 --- a/resources/variants/fabtotum_hyb35.inst.cfg +++ b/resources/variants/fabtotum_hyb35.inst.cfg @@ -5,7 +5,7 @@ definition = fabtotum [metadata] author = FABtotum -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/fabtotum_lite04.inst.cfg b/resources/variants/fabtotum_lite04.inst.cfg index 226c136564..7b52bf5c29 100644 --- a/resources/variants/fabtotum_lite04.inst.cfg +++ b/resources/variants/fabtotum_lite04.inst.cfg @@ -5,7 +5,7 @@ definition = fabtotum [metadata] author = FABtotum -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/fabtotum_lite06.inst.cfg b/resources/variants/fabtotum_lite06.inst.cfg index 62e3014b60..f518f60ce9 100644 --- a/resources/variants/fabtotum_lite06.inst.cfg +++ b/resources/variants/fabtotum_lite06.inst.cfg @@ -5,7 +5,7 @@ definition = fabtotum [metadata] author = FABtotum -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/fabtotum_pro02.inst.cfg b/resources/variants/fabtotum_pro02.inst.cfg index 3e4661ee2c..897bd5aea9 100644 --- a/resources/variants/fabtotum_pro02.inst.cfg +++ b/resources/variants/fabtotum_pro02.inst.cfg @@ -5,7 +5,7 @@ definition = fabtotum [metadata] author = FABtotum -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/fabtotum_pro04.inst.cfg b/resources/variants/fabtotum_pro04.inst.cfg index 3fe140f8be..d27be2f3b8 100644 --- a/resources/variants/fabtotum_pro04.inst.cfg +++ b/resources/variants/fabtotum_pro04.inst.cfg @@ -5,7 +5,7 @@ definition = fabtotum [metadata] author = FABtotum -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/fabtotum_pro06.inst.cfg b/resources/variants/fabtotum_pro06.inst.cfg index fcb5c71ef0..25b9d7c710 100644 --- a/resources/variants/fabtotum_pro06.inst.cfg +++ b/resources/variants/fabtotum_pro06.inst.cfg @@ -5,7 +5,7 @@ definition = fabtotum [metadata] author = FABtotum -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/fabtotum_pro08.inst.cfg b/resources/variants/fabtotum_pro08.inst.cfg index bef04734eb..627e26e2a2 100644 --- a/resources/variants/fabtotum_pro08.inst.cfg +++ b/resources/variants/fabtotum_pro08.inst.cfg @@ -5,7 +5,7 @@ definition = fabtotum [metadata] author = FABtotum -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/felixtec4_0.25.inst.cfg b/resources/variants/felixtec4_0.25.inst.cfg index 7d8bca94b0..3dda15171b 100644 --- a/resources/variants/felixtec4_0.25.inst.cfg +++ b/resources/variants/felixtec4_0.25.inst.cfg @@ -6,7 +6,7 @@ definition = felixtec4dual [metadata] author = kerog777 type = variant -setting_version = 5 +setting_version = 6 hardware_type = nozzle [values] diff --git a/resources/variants/felixtec4_0.35.inst.cfg b/resources/variants/felixtec4_0.35.inst.cfg index f061aa1cbc..db79c3bad4 100644 --- a/resources/variants/felixtec4_0.35.inst.cfg +++ b/resources/variants/felixtec4_0.35.inst.cfg @@ -6,7 +6,7 @@ definition = felixtec4dual [metadata] author = kerog777 type = variant -setting_version = 5 +setting_version = 6 hardware_type = nozzle [values] diff --git a/resources/variants/felixtec4_0.50.inst.cfg b/resources/variants/felixtec4_0.50.inst.cfg index 3c68c42dae..6d52881ee5 100644 --- a/resources/variants/felixtec4_0.50.inst.cfg +++ b/resources/variants/felixtec4_0.50.inst.cfg @@ -7,7 +7,7 @@ definition = felixtec4dual author = kerog777 type = variant hardware_type = nozzle -setting_version = 5 +setting_version = 6 [values] machine_nozzle_size = 0.5 diff --git a/resources/variants/felixtec4_0.70.inst.cfg b/resources/variants/felixtec4_0.70.inst.cfg index 3a52644714..4edeebbc84 100644 --- a/resources/variants/felixtec4_0.70.inst.cfg +++ b/resources/variants/felixtec4_0.70.inst.cfg @@ -7,7 +7,7 @@ definition = felixtec4dual author = kerog777 type = variant hardware_type = nozzle -setting_version = 5 +setting_version = 6 [values] machine_nozzle_size = 0.70 diff --git a/resources/variants/gmax15plus_025_e3d.inst.cfg b/resources/variants/gmax15plus_025_e3d.inst.cfg index 8a6b37067d..a085be0526 100644 --- a/resources/variants/gmax15plus_025_e3d.inst.cfg +++ b/resources/variants/gmax15plus_025_e3d.inst.cfg @@ -5,7 +5,7 @@ definition = gmax15plus [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/gmax15plus_04_e3d.inst.cfg b/resources/variants/gmax15plus_04_e3d.inst.cfg index a2f779f426..05473dafd2 100644 --- a/resources/variants/gmax15plus_04_e3d.inst.cfg +++ b/resources/variants/gmax15plus_04_e3d.inst.cfg @@ -5,9 +5,9 @@ definition = gmax15plus [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle [values] -machine_nozzle_size = 0.4 +machine_nozzle_size = 0.4 \ No newline at end of file diff --git a/resources/variants/gmax15plus_05_e3d.inst.cfg b/resources/variants/gmax15plus_05_e3d.inst.cfg index 68ee111aa1..f3324382ba 100644 --- a/resources/variants/gmax15plus_05_e3d.inst.cfg +++ b/resources/variants/gmax15plus_05_e3d.inst.cfg @@ -5,9 +5,9 @@ definition = gmax15plus [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle [values] -machine_nozzle_size = 0.5 +machine_nozzle_size = 0.5 \ No newline at end of file diff --git a/resources/variants/gmax15plus_05_jhead.inst.cfg b/resources/variants/gmax15plus_05_jhead.inst.cfg index 6d0b084969..d480b47367 100644 --- a/resources/variants/gmax15plus_05_jhead.inst.cfg +++ b/resources/variants/gmax15plus_05_jhead.inst.cfg @@ -5,7 +5,7 @@ definition = gmax15plus [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/gmax15plus_06_e3d.inst.cfg b/resources/variants/gmax15plus_06_e3d.inst.cfg index 987e882a09..732870f044 100644 --- a/resources/variants/gmax15plus_06_e3d.inst.cfg +++ b/resources/variants/gmax15plus_06_e3d.inst.cfg @@ -5,9 +5,9 @@ definition = gmax15plus [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle [values] -machine_nozzle_size = 0.6 +machine_nozzle_size = 0.6 \ No newline at end of file diff --git a/resources/variants/gmax15plus_08_e3d.inst.cfg b/resources/variants/gmax15plus_08_e3d.inst.cfg index bf59b47da0..0c4137a018 100644 --- a/resources/variants/gmax15plus_08_e3d.inst.cfg +++ b/resources/variants/gmax15plus_08_e3d.inst.cfg @@ -5,9 +5,9 @@ definition = gmax15plus [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle [values] -machine_nozzle_size = 0.8 +machine_nozzle_size = 0.8 \ No newline at end of file diff --git a/resources/variants/gmax15plus_10_jhead.inst.cfg b/resources/variants/gmax15plus_10_jhead.inst.cfg index 47355f344c..8ae93fc93c 100644 --- a/resources/variants/gmax15plus_10_jhead.inst.cfg +++ b/resources/variants/gmax15plus_10_jhead.inst.cfg @@ -5,9 +5,9 @@ definition = gmax15plus [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle [values] -machine_nozzle_size = 0.5 +machine_nozzle_size = 0.5 \ No newline at end of file diff --git a/resources/variants/gmax15plus_12_e3d.inst.cfg b/resources/variants/gmax15plus_12_e3d.inst.cfg new file mode 100644 index 0000000000..016f48c1a3 --- /dev/null +++ b/resources/variants/gmax15plus_12_e3d.inst.cfg @@ -0,0 +1,13 @@ +[general] +name = 1.2mm E3D Volcano +version = 4 +definition = gmax15plus + +[metadata] +author = gcreate +setting_version = 6 +type = variant +hardware_type = nozzle + +[values] +machine_nozzle_size = 1.2 \ No newline at end of file diff --git a/resources/variants/gmax15plus_dual_025_e3d.inst.cfg b/resources/variants/gmax15plus_dual_025_e3d.inst.cfg index 750a5381b3..185166d3b5 100644 --- a/resources/variants/gmax15plus_dual_025_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_025_e3d.inst.cfg @@ -5,7 +5,7 @@ definition = gmax15plus_dual [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/gmax15plus_dual_04_e3d.inst.cfg b/resources/variants/gmax15plus_dual_04_e3d.inst.cfg index 4b5a71c53b..1c534f13e0 100644 --- a/resources/variants/gmax15plus_dual_04_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_04_e3d.inst.cfg @@ -5,9 +5,9 @@ definition = gmax15plus_dual [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle [values] -machine_nozzle_size = 0.4 +machine_nozzle_size = 0.4 \ No newline at end of file diff --git a/resources/variants/gmax15plus_dual_05_e3d.inst.cfg b/resources/variants/gmax15plus_dual_05_e3d.inst.cfg index 05d9a88d54..f1d67509a9 100644 --- a/resources/variants/gmax15plus_dual_05_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_05_e3d.inst.cfg @@ -5,7 +5,7 @@ definition = gmax15plus_dual [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/gmax15plus_dual_05_jhead.inst.cfg b/resources/variants/gmax15plus_dual_05_jhead.inst.cfg index 54a237e848..bc72c4ae20 100644 --- a/resources/variants/gmax15plus_dual_05_jhead.inst.cfg +++ b/resources/variants/gmax15plus_dual_05_jhead.inst.cfg @@ -5,7 +5,7 @@ definition = gmax15plus_dual [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/gmax15plus_dual_06_e3d.inst.cfg b/resources/variants/gmax15plus_dual_06_e3d.inst.cfg index 39c41be968..545cfcb238 100644 --- a/resources/variants/gmax15plus_dual_06_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_06_e3d.inst.cfg @@ -5,7 +5,7 @@ definition = gmax15plus_dual [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/gmax15plus_dual_08_e3d.inst.cfg b/resources/variants/gmax15plus_dual_08_e3d.inst.cfg index 1f2d7b9790..1923aac7f7 100644 --- a/resources/variants/gmax15plus_dual_08_e3d.inst.cfg +++ b/resources/variants/gmax15plus_dual_08_e3d.inst.cfg @@ -5,7 +5,7 @@ definition = gmax15plus_dual [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/gmax15plus_dual_10_jhead.inst.cfg b/resources/variants/gmax15plus_dual_10_jhead.inst.cfg index cf615bb874..de0776ad9b 100644 --- a/resources/variants/gmax15plus_dual_10_jhead.inst.cfg +++ b/resources/variants/gmax15plus_dual_10_jhead.inst.cfg @@ -5,9 +5,9 @@ definition = gmax15plus_dual [metadata] author = gcreate -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle [values] -machine_nozzle_size = 0.5 +machine_nozzle_size = 1.0 diff --git a/resources/variants/imade3d_jellybox_0.4.inst.cfg b/resources/variants/imade3d_jellybox_0.4.inst.cfg index 2bd0f578cf..1623e6755c 100644 --- a/resources/variants/imade3d_jellybox_0.4.inst.cfg +++ b/resources/variants/imade3d_jellybox_0.4.inst.cfg @@ -5,7 +5,7 @@ definition = imade3d_jellybox [metadata] author = IMADE3D -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg b/resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg index 6a93cdf13d..2f1cb002b4 100644 --- a/resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg +++ b/resources/variants/imade3d_jellybox_0.4_2-fans.inst.cfg @@ -5,7 +5,7 @@ definition = imade3d_jellybox [metadata] author = IMADE3D -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/tizyx_k25_0.2.inst.cfg b/resources/variants/tizyx_k25_0.2.inst.cfg index cd9f1bcbd1..c616579911 100644 --- a/resources/variants/tizyx_k25_0.2.inst.cfg +++ b/resources/variants/tizyx_k25_0.2.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = tizyx_k25 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/tizyx_k25_0.3.inst.cfg b/resources/variants/tizyx_k25_0.3.inst.cfg index 8b34d23bf6..180d831cca 100644 --- a/resources/variants/tizyx_k25_0.3.inst.cfg +++ b/resources/variants/tizyx_k25_0.3.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = tizyx_k25 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/tizyx_k25_0.4.inst.cfg b/resources/variants/tizyx_k25_0.4.inst.cfg index c147eb0ad0..07ef3ca8ed 100644 --- a/resources/variants/tizyx_k25_0.4.inst.cfg +++ b/resources/variants/tizyx_k25_0.4.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = tizyx_k25 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/tizyx_k25_0.5.inst.cfg b/resources/variants/tizyx_k25_0.5.inst.cfg index 14102fb2c7..a09a207e7a 100644 --- a/resources/variants/tizyx_k25_0.5.inst.cfg +++ b/resources/variants/tizyx_k25_0.5.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = tizyx_k25 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/tizyx_k25_0.6.inst.cfg b/resources/variants/tizyx_k25_0.6.inst.cfg index 00f69f71f4..751cf8e794 100644 --- a/resources/variants/tizyx_k25_0.6.inst.cfg +++ b/resources/variants/tizyx_k25_0.6.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = tizyx_k25 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/tizyx_k25_0.8.inst.cfg b/resources/variants/tizyx_k25_0.8.inst.cfg index c80f5e70d2..cca0986ed5 100644 --- a/resources/variants/tizyx_k25_0.8.inst.cfg +++ b/resources/variants/tizyx_k25_0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = tizyx_k25 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/tizyx_k25_1.0.inst.cfg b/resources/variants/tizyx_k25_1.0.inst.cfg index ce8593b1e8..d99948c26c 100644 --- a/resources/variants/tizyx_k25_1.0.inst.cfg +++ b/resources/variants/tizyx_k25_1.0.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = tizyx_k25 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_0.25.inst.cfg b/resources/variants/ultimaker2_0.25.inst.cfg index a58b4d9a56..004cdaf671 100644 --- a/resources/variants/ultimaker2_0.25.inst.cfg +++ b/resources/variants/ultimaker2_0.25.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_0.4.inst.cfg b/resources/variants/ultimaker2_0.4.inst.cfg index 46845d974e..607d0c4f29 100644 --- a/resources/variants/ultimaker2_0.4.inst.cfg +++ b/resources/variants/ultimaker2_0.4.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_0.6.inst.cfg b/resources/variants/ultimaker2_0.6.inst.cfg index f9ab1f1358..1ddc07817b 100644 --- a/resources/variants/ultimaker2_0.6.inst.cfg +++ b/resources/variants/ultimaker2_0.6.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_0.8.inst.cfg b/resources/variants/ultimaker2_0.8.inst.cfg index 3d9c273783..938b472c2c 100644 --- a/resources/variants/ultimaker2_0.8.inst.cfg +++ b/resources/variants/ultimaker2_0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_extended_0.25.inst.cfg b/resources/variants/ultimaker2_extended_0.25.inst.cfg index f5471fc505..45546c55aa 100644 --- a/resources/variants/ultimaker2_extended_0.25.inst.cfg +++ b/resources/variants/ultimaker2_extended_0.25.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_extended_0.4.inst.cfg b/resources/variants/ultimaker2_extended_0.4.inst.cfg index a7d03f2408..fb3d8c1116 100644 --- a/resources/variants/ultimaker2_extended_0.4.inst.cfg +++ b/resources/variants/ultimaker2_extended_0.4.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_extended_0.6.inst.cfg b/resources/variants/ultimaker2_extended_0.6.inst.cfg index 25c180e07e..50f7dc04c6 100644 --- a/resources/variants/ultimaker2_extended_0.6.inst.cfg +++ b/resources/variants/ultimaker2_extended_0.6.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_extended_0.8.inst.cfg b/resources/variants/ultimaker2_extended_0.8.inst.cfg index c33f483da3..178737dbd5 100644 --- a/resources/variants/ultimaker2_extended_0.8.inst.cfg +++ b/resources/variants/ultimaker2_extended_0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg b/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg index c65940251c..7e67824d16 100644 --- a/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.25.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_extended_plus [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg b/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg index 7493f2af44..1150c6127c 100644 --- a/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.4.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_extended_plus [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg b/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg index c4a3ab6340..fbdef77918 100644 --- a/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.6.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_extended_plus [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg b/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg index e77ec2a5c2..106537e0a7 100644 --- a/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg +++ b/resources/variants/ultimaker2_extended_plus_0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_extended_plus [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_plus_0.25.inst.cfg b/resources/variants/ultimaker2_plus_0.25.inst.cfg index 7fd7f3980f..c07b80c246 100644 --- a/resources/variants/ultimaker2_plus_0.25.inst.cfg +++ b/resources/variants/ultimaker2_plus_0.25.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_plus_0.4.inst.cfg b/resources/variants/ultimaker2_plus_0.4.inst.cfg index 3b54e0cdef..623fffbeb9 100644 --- a/resources/variants/ultimaker2_plus_0.4.inst.cfg +++ b/resources/variants/ultimaker2_plus_0.4.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_plus_0.6.inst.cfg b/resources/variants/ultimaker2_plus_0.6.inst.cfg index d8fea055e5..b57fa81dfe 100644 --- a/resources/variants/ultimaker2_plus_0.6.inst.cfg +++ b/resources/variants/ultimaker2_plus_0.6.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker2_plus_0.8.inst.cfg b/resources/variants/ultimaker2_plus_0.8.inst.cfg index 3ae902ac2f..702ec2ef31 100644 --- a/resources/variants/ultimaker2_plus_0.8.inst.cfg +++ b/resources/variants/ultimaker2_plus_0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker2_plus [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_aa0.25.inst.cfg b/resources/variants/ultimaker3_aa0.25.inst.cfg index b46fdf5dfb..fc8cc3b090 100644 --- a/resources/variants/ultimaker3_aa0.25.inst.cfg +++ b/resources/variants/ultimaker3_aa0.25.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_aa0.8.inst.cfg b/resources/variants/ultimaker3_aa0.8.inst.cfg index 56740233dd..308bed6fcb 100644 --- a/resources/variants/ultimaker3_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_aa0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_aa04.inst.cfg b/resources/variants/ultimaker3_aa04.inst.cfg index ce91e89d26..25230cd30b 100644 --- a/resources/variants/ultimaker3_aa04.inst.cfg +++ b/resources/variants/ultimaker3_aa04.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_bb0.8.inst.cfg b/resources/variants/ultimaker3_bb0.8.inst.cfg index ace0bf3a94..5ccf2816ff 100644 --- a/resources/variants/ultimaker3_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_bb0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_bb04.inst.cfg b/resources/variants/ultimaker3_bb04.inst.cfg index d571cabc9b..d919e5aab7 100644 --- a/resources/variants/ultimaker3_bb04.inst.cfg +++ b/resources/variants/ultimaker3_bb04.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_extended_aa0.25.inst.cfg b/resources/variants/ultimaker3_extended_aa0.25.inst.cfg index 714b017653..ce0f20fa7e 100644 --- a/resources/variants/ultimaker3_extended_aa0.25.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa0.25.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg index f72c96b551..f209508875 100644 --- a/resources/variants/ultimaker3_extended_aa0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_extended_aa04.inst.cfg b/resources/variants/ultimaker3_extended_aa04.inst.cfg index f354784fc6..714d19051f 100644 --- a/resources/variants/ultimaker3_extended_aa04.inst.cfg +++ b/resources/variants/ultimaker3_extended_aa04.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg index fe760c93b8..528c7f70ec 100644 --- a/resources/variants/ultimaker3_extended_bb0.8.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker3_extended_bb04.inst.cfg b/resources/variants/ultimaker3_extended_bb04.inst.cfg index 742dc9896e..5ee562ee38 100644 --- a/resources/variants/ultimaker3_extended_bb04.inst.cfg +++ b/resources/variants/ultimaker3_extended_bb04.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker3_extended [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker_s5_aa0.25.inst.cfg b/resources/variants/ultimaker_s5_aa0.25.inst.cfg index 643513faad..ebdb096b6f 100644 --- a/resources/variants/ultimaker_s5_aa0.25.inst.cfg +++ b/resources/variants/ultimaker_s5_aa0.25.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker_s5_aa0.8.inst.cfg b/resources/variants/ultimaker_s5_aa0.8.inst.cfg index eca8c400d0..d8ff1c020e 100644 --- a/resources/variants/ultimaker_s5_aa0.8.inst.cfg +++ b/resources/variants/ultimaker_s5_aa0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker_s5_aa04.inst.cfg b/resources/variants/ultimaker_s5_aa04.inst.cfg index b5b694d0c1..ac377e3e78 100644 --- a/resources/variants/ultimaker_s5_aa04.inst.cfg +++ b/resources/variants/ultimaker_s5_aa04.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker_s5_aluminum.inst.cfg b/resources/variants/ultimaker_s5_aluminum.inst.cfg index 1018b7e5ab..ca457bd7e7 100644 --- a/resources/variants/ultimaker_s5_aluminum.inst.cfg +++ b/resources/variants/ultimaker_s5_aluminum.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = buildplate diff --git a/resources/variants/ultimaker_s5_bb0.8.inst.cfg b/resources/variants/ultimaker_s5_bb0.8.inst.cfg index c1c5c1a10b..bb7f2d1420 100644 --- a/resources/variants/ultimaker_s5_bb0.8.inst.cfg +++ b/resources/variants/ultimaker_s5_bb0.8.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker_s5_bb04.inst.cfg b/resources/variants/ultimaker_s5_bb04.inst.cfg index b5ff8d51f6..cda1036507 100644 --- a/resources/variants/ultimaker_s5_bb04.inst.cfg +++ b/resources/variants/ultimaker_s5_bb04.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle diff --git a/resources/variants/ultimaker_s5_cc06.inst.cfg b/resources/variants/ultimaker_s5_cc06.inst.cfg index d41d08118a..afbeb44462 100644 --- a/resources/variants/ultimaker_s5_cc06.inst.cfg +++ b/resources/variants/ultimaker_s5_cc06.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = nozzle @@ -13,7 +13,6 @@ brim_width = 7 machine_nozzle_cool_down_speed = 0.9 machine_nozzle_id = CC 0.6 machine_nozzle_size = 0.6 -material_print_temperature = =default_material_print_temperature + 10 raft_acceleration = =acceleration_print raft_airgap = 0.3 raft_base_thickness = =resolveOrValue('layer_height_0') * 1.2 diff --git a/resources/variants/ultimaker_s5_glass.inst.cfg b/resources/variants/ultimaker_s5_glass.inst.cfg index d74eb3c6c9..e7431c933f 100644 --- a/resources/variants/ultimaker_s5_glass.inst.cfg +++ b/resources/variants/ultimaker_s5_glass.inst.cfg @@ -4,7 +4,7 @@ version = 4 definition = ultimaker_s5 [metadata] -setting_version = 5 +setting_version = 6 type = variant hardware_type = buildplate diff --git a/tests/TestPrintInformation.py b/tests/TestPrintInformation.py index a226a437c6..baa36fb338 100644 --- a/tests/TestPrintInformation.py +++ b/tests/TestPrintInformation.py @@ -1,5 +1,7 @@ +import functools from cura import PrintInformation +from cura.Settings.MachineManager import MachineManager from unittest.mock import MagicMock, patch from UM.Application import Application @@ -11,14 +13,20 @@ def getPrintInformation(printer_name) -> PrintInformation: mock_application = MagicMock() global_container_stack = MagicMock() - global_container_stack.definition.getName = MagicMock(return_value=printer_name) - mock_application.getGlobalContainerStack = MagicMock(return_value=global_container_stack) + global_container_stack.definition.getName = MagicMock(return_value = printer_name) + mock_application.getGlobalContainerStack = MagicMock(return_value = global_container_stack) - multiBuildPlateModel = MagicMock() - multiBuildPlateModel.maxBuildPlate = 0 - mock_application.getMultiBuildPlateModel = MagicMock(return_value=multiBuildPlateModel) + multi_build_plate_model = MagicMock() + multi_build_plate_model.maxBuildPlate = 0 + mock_application.getMultiBuildPlateModel = MagicMock(return_value = multi_build_plate_model) - Application.getInstance = MagicMock(return_type=mock_application) + # Mock-up the entire machine manager except the function that needs to be tested: getAbbreviatedMachineName + original_get_abbreviated_name = MachineManager.getAbbreviatedMachineName + mock_machine_manager = MagicMock() + mock_machine_manager.getAbbreviatedMachineName = functools.partial(original_get_abbreviated_name, mock_machine_manager) + mock_application.getMachineManager = MagicMock(return_value = mock_machine_manager) + + Application.getInstance = MagicMock(return_type = mock_application) with patch("json.loads", lambda x: {}): print_information = PrintInformation.PrintInformation(mock_application) @@ -28,17 +36,17 @@ def getPrintInformation(printer_name) -> PrintInformation: def setup_module(): MimeTypeDatabase.addMimeType( MimeType( - name="application/vnd.ms-package.3dmanufacturing-3dmodel+xml", - comment="3MF", - suffixes=["3mf"] + name = "application/vnd.ms-package.3dmanufacturing-3dmodel+xml", + comment = "3MF", + suffixes = ["3mf"] ) ) MimeTypeDatabase.addMimeType( MimeType( - name="application/x-cura-gcode-file", - comment="Cura GCode File", - suffixes=["gcode"] + name = "application/x-cura-gcode-file", + comment = "Cura GCode File", + suffixes = ["gcode"] ) ) @@ -49,42 +57,42 @@ def test_setProjectName(): print_information = getPrintInformation("ultimaker") # Test simple name - project_name = ["HelloWorld",".3mf"] + project_name = ["HelloWorld", ".3mf"] print_information.setProjectName(project_name[0] + project_name[1]) assert "UM_" + project_name[0] == print_information._job_name # Test the name with one dot - project_name = ["Hello.World",".3mf"] + project_name = ["Hello.World", ".3mf"] print_information.setProjectName(project_name[0] + project_name[1]) assert "UM_" + project_name[0] == print_information._job_name # Test the name with two dot - project_name = ["Hello.World.World",".3mf"] + project_name = ["Hello.World.World", ".3mf"] print_information.setProjectName(project_name[0] + project_name[1]) assert "UM_" + project_name[0] == print_information._job_name # Test the name with dot at the beginning - project_name = [".Hello.World",".3mf"] + project_name = [".Hello.World", ".3mf"] print_information.setProjectName(project_name[0] + project_name[1]) assert "UM_" + project_name[0] == print_information._job_name # Test the name with underline - project_name = ["Hello_World",".3mf"] + project_name = ["Hello_World", ".3mf"] print_information.setProjectName(project_name[0] + project_name[1]) assert "UM_" + project_name[0] == print_information._job_name # Test gcode extension - project_name = ["Hello_World",".gcode"] + project_name = ["Hello_World", ".gcode"] print_information.setProjectName(project_name[0] + project_name[1]) assert "UM_" + project_name[0] == print_information._job_name # Test empty project name - project_name = ["",""] + project_name = ["", ""] print_information.setProjectName(project_name[0] + project_name[1]) assert print_information.UNTITLED_JOB_NAME == print_information._job_name # Test wrong file extension - project_name = ["Hello_World",".test"] + project_name = ["Hello_World", ".test"] print_information.setProjectName(project_name[0] + project_name[1]) assert "UM_" + project_name[0] != print_information._job_name @@ -93,7 +101,7 @@ def test_setJobName(): print_information = getPrintInformation("ultimaker") print_information._abbr_machine = "UM" - print_information.setJobName("UM_HelloWorld", is_user_specified_job_name=False) + print_information.setJobName("UM_HelloWorld", is_user_specified_job_name = False) def test_defineAbbreviatedMachineName(): @@ -102,6 +110,6 @@ def test_defineAbbreviatedMachineName(): print_information = getPrintInformation(printer_name) # Test not ultimaker printer, name suffix should have first letter from the printer name - project_name = ["HelloWorld",".3mf"] + project_name = ["HelloWorld", ".3mf"] print_information.setProjectName(project_name[0] + project_name[1]) assert printer_name[0] + "_" + project_name[0] == print_information._job_name \ No newline at end of file