diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9e9bf4b538..deb4e63935 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,7 @@ if(CURA_DEBUGMODE)
set(_cura_debugmode "ON")
endif()
+set(CURA_APP_DISPLAY_NAME "Ultimaker Cura" CACHE STRING "Display name of Cura")
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
set(CURA_SDK_VERSION "" CACHE STRING "SDK version of Cura")
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..be77a6307b 100644
--- a/cura/API/Account.py
+++ b/cura/API/Account.py
@@ -44,7 +44,7 @@ class Account(QObject):
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_ID="um----------------------------ultimaker_cura",
CLIENT_SCOPES="account.user.read drive.backup.read drive.backup.write packages.download packages.rating.read packages.rating.write",
AUTH_DATA_PREFERENCE_KEY="general/ultimaker_auth_data",
AUTH_SUCCESS_REDIRECT="{}/app/auth-success".format(self._oauth_root),
diff --git a/cura/API/Interface/__init__.py b/cura/API/Interface/__init__.py
index 742254a1a4..cec174bf0a 100644
--- a/cura/API/Interface/__init__.py
+++ b/cura/API/Interface/__init__.py
@@ -3,7 +3,6 @@
from typing import TYPE_CHECKING
-from UM.PluginRegistry import PluginRegistry
from cura.API.Interface.Settings import Settings
if TYPE_CHECKING:
@@ -23,9 +22,6 @@ if TYPE_CHECKING:
class Interface:
- # For now we use the same API version to be consistent.
- VERSION = PluginRegistry.APIVersion
-
def __init__(self, application: "CuraApplication") -> None:
# API methods specific to the settings portion of the UI
self.settings = Settings(application)
diff --git a/cura/API/__init__.py b/cura/API/__init__.py
index ad07452c1a..b3e702263a 100644
--- a/cura/API/__init__.py
+++ b/cura/API/__init__.py
@@ -4,7 +4,6 @@ from typing import Optional, TYPE_CHECKING
from PyQt5.QtCore import QObject, pyqtProperty
-from UM.PluginRegistry import PluginRegistry
from cura.API.Backups import Backups
from cura.API.Interface import Interface
from cura.API.Account import Account
@@ -22,7 +21,6 @@ if TYPE_CHECKING:
class CuraAPI(QObject):
# For now we use the same API version to be consistent.
- VERSION = PluginRegistry.APIVersion
__instance = None # type: "CuraAPI"
_application = None # type: CuraApplication
@@ -62,4 +60,4 @@ class CuraAPI(QObject):
@property
def interface(self) -> "Interface":
- return self._interface
\ No newline at end of file
+ return self._interface
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 fc9ba1ebf4..9855bbe7de 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,6 +114,7 @@ from cura.Settings.CuraFormulaFunctions import CuraFormulaFunctions
from cura.ObjectsModel import ObjectsModel
+from cura.PrinterOutputDevice import PrinterOutputDevice
from cura.PrinterOutput.NetworkMJPGImage import NetworkMJPGImage
from UM.FlameProfiler import pyqtSlot
@@ -128,19 +130,20 @@ if TYPE_CHECKING:
numpy.seterr(all = "ignore")
try:
- from cura.CuraVersion import CuraVersion, CuraBuildType, CuraDebugMode, CuraSDKVersion
+ from cura.CuraVersion import CuraAppDisplayName, CuraVersion, CuraBuildType, CuraDebugMode, CuraSDKVersion # type: ignore
except ImportError:
+ CuraAppDisplayName = "Ultimaker Cura"
CuraVersion = "master" # [CodeStyle: Reflecting imported value]
CuraBuildType = ""
CuraDebugMode = False
- CuraSDKVersion = ""
+ 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
@@ -161,7 +164,9 @@ 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,
tray_icon_name = "cura-icon-32.png",
@@ -178,7 +183,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
@@ -203,6 +207,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
@@ -289,7 +295,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))
@@ -425,7 +434,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.:
@@ -436,6 +446,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.
@@ -489,7 +500,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", 600)
+ preferences.addPreference("view/settings_visible", False)
preferences.addPreference("cura/currency", "€")
preferences.addPreference("cura/material_settings", "{}")
@@ -628,9 +640,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
@@ -656,12 +666,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:
@@ -858,6 +868,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:
@@ -950,6 +973,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")
@@ -971,6 +995,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)
@@ -1081,88 +1107,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):
@@ -1242,62 +1186,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
@@ -1311,7 +1268,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)
@@ -1320,20 +1277,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)
@@ -1344,7 +1289,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()
@@ -1394,13 +1339,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)
@@ -1444,7 +1388,7 @@ class CuraApplication(QtApplication):
@pyqtSlot()
- def groupSelected(self):
+ def groupSelected(self) -> None:
# Create a group-node
group_node = CuraSceneNode()
group_decorator = GroupDecorator()
@@ -1460,7 +1404,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
@@ -1472,7 +1417,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"):
@@ -1495,7 +1440,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()
@@ -1661,7 +1606,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 226b2183f2..7c6304231d 100644
--- a/cura/CuraVersion.py.in
+++ b/cura/CuraVersion.py.in
@@ -1,6 +1,7 @@
-# Copyright (c) 2015 Ultimaker B.V.
+# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
+CuraAppDisplayName = "@CURA_APP_DISPLAY_NAME@"
CuraVersion = "@CURA_VERSION@"
CuraBuildType = "@CURA_BUILDTYPE@"
CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False
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..939809151d
--- /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)
\ No newline at end of file
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 1a204c020b..aee96f3153 100644
--- a/cura/Machines/MaterialManager.py
+++ b/cura/Machines/MaterialManager.py
@@ -21,6 +21,7 @@ from .VariantType import VariantType
if TYPE_CHECKING:
from UM.Settings.DefinitionContainer import DefinitionContainer
+ from UM.Settings.InstanceContainer import InstanceContainer
from cura.Settings.GlobalStack import GlobalStack
from cura.Settings.ExtruderStack import ExtruderStack
@@ -298,7 +299,7 @@ class MaterialManager(QObject):
def getRootMaterialIDWithoutDiameter(self, root_material_id: str) -> str:
return self._diameter_material_map.get(root_material_id, "")
- def getMaterialGroupListByGUID(self, guid: str) -> Optional[list]:
+ def getMaterialGroupListByGUID(self, guid: str) -> Optional[List[MaterialGroup]]:
return self._guid_material_groups_map.get(guid)
#
@@ -446,6 +447,28 @@ class MaterialManager(QObject):
material_diameter, root_material_id)
return node
+ # There are 2 ways to get fallback materials;
+ # - A fallback by type (@sa getFallbackMaterialIdByMaterialType), which adds the generic version of this material
+ # - A fallback by GUID; If a material has been duplicated, it should also check if the original materials do have
+ # a GUID. This should only be done if the material itself does not have a quality just yet.
+ def getFallBackMaterialIdsByMaterial(self, material: "InstanceContainer") -> List[str]:
+ results = [] # type: List[str]
+
+ material_groups = self.getMaterialGroupListByGUID(material.getMetaDataEntry("GUID"))
+ for material_group in material_groups: # type: ignore
+ if material_group.name != material.getId():
+ # If the material in the group is read only, put it at the front of the list (since that is the most
+ # likely one to get a result)
+ if material_group.is_read_only:
+ results.insert(0, material_group.name)
+ else:
+ results.append(material_group.name)
+
+ fallback = self.getFallbackMaterialIdByMaterialType(material.getMetaDataEntry("material"))
+ if fallback is not None:
+ results.append(fallback)
+ return results
+
#
# Used by QualityManager. Built-in quality profiles may be based on generic material IDs such as "generic_pla".
# For materials such as ultimaker_pla_orange, no quality profiles may be found, so we should fall back to use
@@ -602,7 +625,6 @@ class MaterialManager(QObject):
container_to_add.setDirty(True)
self._container_registry.addContainer(container_to_add)
-
# if the duplicated material was favorite then the new material should also be added to favorite.
if root_material_id in self.getFavorites():
self.addFavorite(new_base_id)
@@ -622,8 +644,11 @@ class MaterialManager(QObject):
machine_manager = self._application.getMachineManager()
extruder_stack = machine_manager.activeStack
+ machine_definition = self._application.getGlobalContainerStack().definition
+ preferred_material = machine_definition.getMetaDataEntry("preferred_material")
+
approximate_diameter = str(extruder_stack.approximateMaterialDiameter)
- root_material_id = "generic_pla"
+ root_material_id = preferred_material if preferred_material else "generic_pla"
root_material_id = self.getRootMaterialIDForDiameter(root_material_id, approximate_diameter)
material_group = self.getMaterialGroup(root_material_id)
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 2702001d8a..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":
@@ -140,7 +148,7 @@ class SettingVisibilityPresetsModel(QObject):
item_to_set = self._active_preset_item
if matching_preset_item is None:
# The new visibility setup is "custom" should be custom
- if self._active_preset_item.presetId == "custom":
+ if self._active_preset_item is None or self._active_preset_item.presetId == "custom":
# We are already in custom, just save the settings
self._preferences.setValue("cura/custom_visible_settings", visibility_string)
else:
@@ -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 ce19624c21..34cc9ce4b2 100644
--- a/cura/Machines/QualityManager.py
+++ b/cura/Machines/QualityManager.py
@@ -1,7 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
-from typing import TYPE_CHECKING, Optional, cast, Dict, List
+from typing import TYPE_CHECKING, Optional, cast, Dict, List, Set
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtSlot
@@ -16,7 +16,7 @@ from .QualityGroup import QualityGroup
from .QualityNode import QualityNode
if TYPE_CHECKING:
- from UM.Settings.DefinitionContainer import DefinitionContainer
+ from UM.Settings.Interfaces import DefinitionContainerInterface
from cura.Settings.GlobalStack import GlobalStack
from .QualityChangesGroup import QualityChangesGroup
from cura.CuraApplication import CuraApplication
@@ -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
@@ -259,11 +259,15 @@ class QualityManager(QObject):
root_material_id = self._material_manager.getRootMaterialIDWithoutDiameter(root_material_id)
root_material_id_list.append(root_material_id)
- # Also try to get the fallback material
- material_type = extruder.material.getMetaDataEntry("material")
- fallback_root_material_id = self._material_manager.getFallbackMaterialIdByMaterialType(material_type)
- if fallback_root_material_id:
- root_material_id_list.append(fallback_root_material_id)
+ # Also try to get the fallback materials
+ fallback_ids = self._material_manager.getFallBackMaterialIdsByMaterial(extruder.material)
+
+ if fallback_ids:
+ root_material_id_list.extend(fallback_ids)
+
+ # Weed out duplicates while preserving the order.
+ seen = set() # type: Set[str]
+ root_material_id_list = [x for x in root_material_id_list if x not in seen and not seen.add(x)] # type: ignore
# Here we construct a list of nodes we want to look for qualities with the highest priority first.
# The use case is that, when we look for qualities for a machine, we first want to search in the following
@@ -333,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.
@@ -363,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
@@ -534,7 +538,7 @@ class QualityManager(QObject):
# Example: for an Ultimaker 3 Extended, it has "quality_definition = ultimaker3". This means Ultimaker 3 Extended
# shares the same set of qualities profiles as Ultimaker 3.
#
-def getMachineDefinitionIDForQualitySearch(machine_definition: "DefinitionContainer",
+def getMachineDefinitionIDForQualitySearch(machine_definition: "DefinitionContainerInterface",
default_definition_id: str = "fdmprinter") -> str:
machine_definition_id = default_definition_id
if parseBool(machine_definition.getMetaDataEntry("has_machine_quality", False)):
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/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 65b31f1ed7..a055254891 100644
--- a/cura/OAuth2/AuthorizationService.py
+++ b/cura/OAuth2/AuthorizationService.py
@@ -83,9 +83,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
@@ -120,7 +122,7 @@ class AuthorizationService:
"redirect_uri": self._settings.CALLBACK_URL,
"scope": self._settings.CLIENT_SCOPES,
"response_type": "code",
- "state": "CuraDriveIsAwesome",
+ "state": "(.Y.)",
"code_challenge": challenge_code,
"code_challenge_method": "S512"
})
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 21b57d0806..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:
@@ -369,6 +368,16 @@ class PrintInformation(QObject):
else:
self._base_name = ""
+ # Strip the old "curaproject" extension from the name
+ OLD_CURA_PROJECT_EXT = ".curaproject"
+ if self._base_name.lower().endswith(OLD_CURA_PROJECT_EXT):
+ self._base_name = self._base_name[:len(self._base_name) - len(OLD_CURA_PROJECT_EXT)]
+
+ # CURA-5896 Try to strip extra extensions with an infinite amount of ".curaproject.3mf".
+ OLD_CURA_PROJECT_3MF_EXT = ".curaproject.3mf"
+ while self._base_name.lower().endswith(OLD_CURA_PROJECT_3MF_EXT):
+ self._base_name = self._base_name[:len(self._base_name) - len(OLD_CURA_PROJECT_3MF_EXT)]
+
self._updateJobName()
@pyqtProperty(str, fset = setBaseName, notify = baseNameChanged)
@@ -385,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/NetworkedPrinterOutputDevice.py b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py
index f7c7f5d233..14f1364601 100644
--- a/cura/PrinterOutput/NetworkedPrinterOutputDevice.py
+++ b/cura/PrinterOutput/NetworkedPrinterOutputDevice.py
@@ -6,7 +6,7 @@ from UM.Logger import Logger
from UM.Scene.SceneNode import SceneNode #For typing.
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
@@ -28,8 +28,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
@@ -125,7 +125,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 +133,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)
@@ -147,6 +147,9 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
request.setHeader(QNetworkRequest.UserAgentHeader, self._user_agent)
return request
+ 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()
@@ -213,7 +216,7 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
request = self._createEmptyRequest(target)
self._last_request_time = time()
if self._manager is not None:
- reply = self._manager.post(request, data)
+ reply = self._manager.post(request, data.encode())
if on_progress is not None:
reply.uploadProgress.connect(on_progress)
self._registerOnFinishedCallback(reply, on_finished)
@@ -282,8 +285,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..256c9dffe9 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:
+ result = self.timeElapsed / self.timeTotal
+ # Never get a progress past 1.0
+ return min(result, 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..99e8835c2f 100644
--- a/cura/PrinterOutputDevice.py
+++ b/cura/PrinterOutputDevice.py
@@ -4,7 +4,7 @@
from UM.Decorators import deprecated
from UM.i18n import i18nCatalog
from UM.OutputDevice.OutputDevice import OutputDevice
-from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTimer, QUrl
+from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTimer, QUrl, Q_ENUMS
from PyQt5.QtWidgets import QMessageBox
from UM.Logger import Logger
@@ -28,11 +28,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 +53,11 @@ class ConnectionState(IntEnum):
# For all other uses it should be used in the same way as a "regular" OutputDevice.
@signalemitter
class PrinterOutputDevice(QObject, OutputDevice):
+
+ # Put ConnectionType here with Q_ENUMS() so it can be registered as a QML type and accessible via QML, and there is
+ # no need to remember what those Enum integer values mean.
+ Q_ENUMS(ConnectionType)
+
printersChanged = pyqtSignal()
connectionStateChanged = pyqtSignal(str)
acceptsCommandsChanged = pyqtSignal()
@@ -62,7 +74,7 @@ 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]
@@ -83,7 +95,8 @@ class PrinterOutputDevice(QObject, OutputDevice):
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
self._firmware_updater = None #type: Optional[FirmwareUpdater]
self._firmware_name = None #type: Optional[str]
@@ -110,15 +123,18 @@ 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)
+ def getConnectionType(self) -> "ConnectionType":
+ return self._connection_type
+
@pyqtProperty(str, notify = connectionStateChanged)
- def connectionState(self) -> ConnectionState:
+ def connectionState(self) -> "ConnectionState":
return self._connection_state
def _update(self) -> None:
@@ -174,13 +190,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:
@@ -211,6 +227,11 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._unique_configurations.sort(key = lambda k: k.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 +259,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 52e687832c..661106dec7 100644
--- a/cura/Scene/ConvexHullDecorator.py
+++ b/cura/Scene/ConvexHullDecorator.py
@@ -142,6 +142,12 @@ class ConvexHullDecorator(SceneNodeDecorator):
controller = Application.getInstance().getController()
root = controller.getScene().getRoot()
if self._node is None or controller.isToolOperationActive() or not self.__isDescendant(root, self._node):
+ # If the tool operation is still active, we need to compute the convex hull later after the controller is
+ # no longer active.
+ if controller.isToolOperationActive():
+ self.recomputeConvexHullDelayed()
+ return
+
if self._convex_hull_node:
self._convex_hull_node.setParent(None)
self._convex_hull_node = None
@@ -181,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
@@ -266,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..886ed93ad3 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)
@@ -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/ContainerManager.py b/cura/Settings/ContainerManager.py
index 3cfca1a944..133e04e8fc 100644
--- a/cura/Settings/ContainerManager.py
+++ b/cura/Settings/ContainerManager.py
@@ -419,13 +419,13 @@ class ContainerManager(QObject):
self._container_name_filters[name_filter] = entry
## Import single profile, file_url does not have to end with curaprofile
- @pyqtSlot(QUrl, result="QVariantMap")
- def importProfile(self, file_url: QUrl):
+ @pyqtSlot(QUrl, result = "QVariantMap")
+ def importProfile(self, file_url: QUrl) -> Dict[str, str]:
if not file_url.isValid():
- return
+ return {"status": "error", "message": catalog.i18nc("@info:status", "Invalid file URL:") + " " + str(file_url)}
path = file_url.toLocalFile()
if not path:
- return
+ return {"status": "error", "message": catalog.i18nc("@info:status", "Invalid file URL:") + " " + str(file_url)}
return self._container_registry.importProfile(path)
@pyqtSlot(QObject, QUrl, str)
diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py
index 11640adc0f..9f44d075e0 100644
--- a/cura/Settings/CuraContainerRegistry.py
+++ b/cura/Settings/CuraContainerRegistry.py
@@ -5,12 +5,12 @@ import os
import re
import configparser
-from typing import cast, Optional
-
+from typing import cast, Dict, Optional
from PyQt5.QtWidgets import QMessageBox
from UM.Decorators import override
from UM.Settings.ContainerFormatError import ContainerFormatError
+from UM.Settings.Interfaces import ContainerInterface
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer
@@ -28,7 +28,7 @@ from . import GlobalStack
import cura.CuraApplication
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
-from cura.ReaderWriters.ProfileReader import NoProfileException
+from cura.ReaderWriters.ProfileReader import NoProfileException, ProfileReader
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@@ -161,20 +161,20 @@ class CuraContainerRegistry(ContainerRegistry):
## Imports a profile from a file
#
- # \param file_name \type{str} the full path and filename of the profile to import
- # \return \type{Dict} dict with a 'status' key containing the string 'ok' or 'error', and a 'message' key
- # containing a message for the user
- def importProfile(self, file_name):
+ # \param file_name The full path and filename of the profile to import.
+ # \return Dict with a 'status' key containing the string 'ok' or 'error',
+ # and a 'message' key containing a message for the user.
+ def importProfile(self, file_name: str) -> Dict[str, str]:
Logger.log("d", "Attempting to import profile %s", file_name)
if not file_name:
- return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags or !", "Failed to import profile from {0}: {1}", file_name, "Invalid path")}
+ return { "status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags !", "Failed to import profile from {0}: {1}", file_name, "Invalid path")}
plugin_registry = PluginRegistry.getInstance()
extension = file_name.split(".")[-1]
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
- return
+ return {"status": "error", "message": catalog.i18nc("@info:status Don't translate the XML tags !", "Can't import profile from {0} before a printer is added.", file_name)}
machine_extruders = []
for position in sorted(global_stack.extruders):
@@ -183,7 +183,7 @@ class CuraContainerRegistry(ContainerRegistry):
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
if meta_data["profile_reader"][0]["extension"] != extension:
continue
- profile_reader = plugin_registry.getPluginObject(plugin_id)
+ profile_reader = cast(ProfileReader, plugin_registry.getPluginObject(plugin_id))
try:
profile_or_list = profile_reader.read(file_name) # Try to open the file with the profile reader.
except NoProfileException:
@@ -221,13 +221,13 @@ class CuraContainerRegistry(ContainerRegistry):
# Make sure we have a profile_definition in the file:
if profile_definition is None:
break
- machine_definition = self.findDefinitionContainers(id = profile_definition)
- if not machine_definition:
+ machine_definitions = self.findDefinitionContainers(id = profile_definition)
+ if not machine_definitions:
Logger.log("e", "Incorrect profile [%s]. Unknown machine type [%s]", file_name, profile_definition)
return {"status": "error",
"message": catalog.i18nc("@info:status Don't translate the XML tags !", "This profile {0} contains incorrect data, could not import it.", file_name)
}
- machine_definition = machine_definition[0]
+ machine_definition = machine_definitions[0]
# Get the expected machine definition.
# i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode...
@@ -274,11 +274,12 @@ class CuraContainerRegistry(ContainerRegistry):
setting_value = global_profile.getProperty(qc_setting_key, "value")
setting_definition = global_stack.getSettingDefinition(qc_setting_key)
- new_instance = SettingInstance(setting_definition, profile)
- new_instance.setProperty("value", setting_value)
- new_instance.resetState() # Ensure that the state is not seen as a user state.
- profile.addInstance(new_instance)
- profile.setDirty(True)
+ if setting_definition is not None:
+ new_instance = SettingInstance(setting_definition, profile)
+ new_instance.setProperty("value", setting_value)
+ new_instance.resetState() # Ensure that the state is not seen as a user state.
+ profile.addInstance(new_instance)
+ profile.setDirty(True)
global_profile.removeInstance(qc_setting_key, postpone_emit=True)
extruder_profiles.append(profile)
@@ -290,7 +291,7 @@ class CuraContainerRegistry(ContainerRegistry):
for profile_index, profile in enumerate(profile_or_list):
if profile_index == 0:
# This is assumed to be the global profile
- profile_id = (global_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
+ profile_id = (cast(ContainerInterface, global_stack.getBottom()).getId() + "_" + name_seed).lower().replace(" ", "_")
elif profile_index < len(machine_extruders) + 1:
# This is assumed to be an extruder profile
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..dec2524e6b 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()
@@ -201,7 +203,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 +249,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 +263,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 +273,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 +292,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 +417,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 +436,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 +451,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.
@@ -519,7 +517,13 @@ class MachineManager(QObject):
def printerConnected(self):
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
+
def activeMachineNetworkKey(self) -> str:
if self._global_container_stack:
return self._global_container_stack.getMetaDataEntry("um_network_key", "")
@@ -616,6 +620,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 +658,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 +674,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 +743,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 +751,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 +876,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 +921,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 +941,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 +1009,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 +1088,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 +1146,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 +1216,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 +1317,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 +1388,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 +1427,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 +1530,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 +1543,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_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/installer.nsi b/installer.nsi
deleted file mode 100644
index 7516f733a1..0000000000
--- a/installer.nsi
+++ /dev/null
@@ -1,156 +0,0 @@
-!ifndef VERSION
- !define VERSION '15.09.80'
-!endif
-
-; The name of the installer
-Name "Cura ${VERSION}"
-
-; The file to write
-OutFile "Cura_${VERSION}.exe"
-
-; The default installation directory
-InstallDir $PROGRAMFILES\Cura_${VERSION}
-
-; Registry key to check for directory (so if you install again, it will
-; overwrite the old one automatically)
-InstallDirRegKey HKLM "Software\Cura_${VERSION}" "Install_Dir"
-
-; Request application privileges for Windows Vista
-RequestExecutionLevel admin
-
-; Set the LZMA compressor to reduce size.
-SetCompressor /SOLID lzma
-;--------------------------------
-
-!include "MUI2.nsh"
-!include "Library.nsh"
-
-; !define MUI_ICON "dist/resources/cura.ico"
-!define MUI_BGCOLOR FFFFFF
-
-; Directory page defines
-!define MUI_DIRECTORYPAGE_VERIFYONLEAVE
-
-; Header
-; Don't show the component description box
-!define MUI_COMPONENTSPAGE_NODESC
-
-;Do not leave (Un)Installer page automaticly
-!define MUI_FINISHPAGE_NOAUTOCLOSE
-!define MUI_UNFINISHPAGE_NOAUTOCLOSE
-
-;Run Cura after installing
-!define MUI_FINISHPAGE_RUN
-!define MUI_FINISHPAGE_RUN_TEXT "Start Cura ${VERSION}"
-!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
-
-;Add an option to show release notes
-!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\plugins\ChangeLogPlugin\changelog.txt"
-
-; Pages
-;!insertmacro MUI_PAGE_WELCOME
-!insertmacro MUI_PAGE_DIRECTORY
-!insertmacro MUI_PAGE_COMPONENTS
-!insertmacro MUI_PAGE_INSTFILES
-!insertmacro MUI_PAGE_FINISH
-!insertmacro MUI_UNPAGE_CONFIRM
-!insertmacro MUI_UNPAGE_INSTFILES
-!insertmacro MUI_UNPAGE_FINISH
-
-; Languages
-!insertmacro MUI_LANGUAGE "English"
-
-; Reserve Files
-!insertmacro MUI_RESERVEFILE_LANGDLL
-ReserveFile '${NSISDIR}\Plugins\InstallOptions.dll'
-
-;--------------------------------
-
-; The stuff to install
-Section "Cura ${VERSION}"
-
- SectionIn RO
-
- ; Set output path to the installation directory.
- SetOutPath $INSTDIR
-
- ; Put file there
- File /r "dist\"
-
- ; Write the installation path into the registry
- WriteRegStr HKLM "SOFTWARE\Cura_${VERSION}" "Install_Dir" "$INSTDIR"
-
- ; Write the uninstall keys for Windows
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cura_${VERSION}" "DisplayName" "Cura ${VERSION}"
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cura_${VERSION}" "UninstallString" '"$INSTDIR\uninstall.exe"'
- WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cura_${VERSION}" "NoModify" 1
- WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cura_${VERSION}" "NoRepair" 1
- WriteUninstaller "uninstall.exe"
-
- ; Write start menu entries for all users
- SetShellVarContext all
-
- CreateDirectory "$SMPROGRAMS\Cura ${VERSION}"
- CreateShortCut "$SMPROGRAMS\Cura ${VERSION}\Uninstall Cura ${VERSION}.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
- CreateShortCut "$SMPROGRAMS\Cura ${VERSION}\Cura ${VERSION}.lnk" "$INSTDIR\Cura.exe" '' "$INSTDIR\Cura.exe" 0
-
-SectionEnd
-
-Function LaunchLink
- ; Write start menu entries for all users
- SetShellVarContext all
- Exec '"$WINDIR\explorer.exe" "$SMPROGRAMS\Cura ${VERSION}\Cura ${VERSION}.lnk"'
-FunctionEnd
-
-Section "Install Visual Studio 2010 Redistributable"
- SetOutPath "$INSTDIR"
- File "vcredist_2010_20110908_x86.exe"
-
- IfSilent +2
- ExecWait '"$INSTDIR\vcredist_2010_20110908_x86.exe" /q /norestart'
-
-SectionEnd
-
-Section "Install Arduino Drivers"
- ; Set output path to the driver directory.
- SetOutPath "$INSTDIR\drivers\"
- File /r "drivers\"
-
- ${If} ${RunningX64}
- IfSilent +2
- ExecWait '"$INSTDIR\drivers\dpinst64.exe" /lm'
- ${Else}
- IfSilent +2
- ExecWait '"$INSTDIR\drivers\dpinst32.exe" /lm'
- ${EndIf}
-SectionEnd
-
-Section "Open STL files with Cura"
- ${registerExtension} "$INSTDIR\Cura.exe" ".stl" "STL_File"
-SectionEnd
-
-Section /o "Open OBJ files with Cura"
- WriteRegStr HKCR .obj "" "Cura OBJ model file"
- DeleteRegValue HKCR .obj "Content Type"
- WriteRegStr HKCR "Cura OBJ model file\DefaultIcon" "" "$INSTDIR\Cura.exe,0"
- WriteRegStr HKCR "Cura OBJ model file\shell" "" "open"
- WriteRegStr HKCR "Cura OBJ model file\shell\open\command" "" '"$INSTDIR\Cura.exe" "%1"'
-SectionEnd
-
-;--------------------------------
-
-; Uninstaller
-
-Section "Uninstall"
-
- ; Remove registry keys
- DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cura_${VERSION}"
- DeleteRegKey HKLM "SOFTWARE\Cura_${VERSION}"
-
- ; Write start menu entries for all users
- SetShellVarContext all
- ; Remove directories used
- RMDir /r "$SMPROGRAMS\Cura ${VERSION}"
- RMDir /r "$INSTDIR"
-
-SectionEnd
diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py
index e994e1a817..55296979b5 100755
--- a/plugins/3MFReader/ThreeMFWorkspaceReader.py
+++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py
@@ -298,7 +298,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
values = parser["values"] if parser.has_section("values") else dict()
num_settings_overriden_by_quality_changes += len(values)
# Check if quality changes already exists.
- quality_changes = self._container_registry.findInstanceContainers(id = container_id)
+ quality_changes = self._container_registry.findInstanceContainers(name = custom_quality_name,
+ type = "quality_changes")
if quality_changes:
containers_found_dict["quality_changes"] = True
# Check if there really is a conflict by comparing the values
@@ -793,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.py b/plugins/ChangeLogPlugin/ChangeLog.py
index 723c83a021..eeec5edf9b 100644
--- a/plugins/ChangeLogPlugin/ChangeLog.py
+++ b/plugins/ChangeLogPlugin/ChangeLog.py
@@ -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.
from UM.i18n import i18nCatalog
@@ -29,6 +29,7 @@ class ChangeLog(Extension, QObject,):
self._change_logs = None
Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
Application.getInstance().getPreferences().addPreference("general/latest_version_changelog_shown", "2.0.0") #First version of CURA with uranium
+ self.setMenuName(catalog.i18nc("@item:inmenu", "Changelog"))
self.addMenuItem(catalog.i18nc("@item:inmenu", "Show Changelog"), self.showChangelog)
def getChangeLogs(self):
diff --git a/plugins/ChangeLogPlugin/ChangeLog.txt b/plugins/ChangeLogPlugin/ChangeLog.txt
index 266442473c..7e5cf2dd3b 100755
--- a/plugins/ChangeLogPlugin/ChangeLog.txt
+++ b/plugins/ChangeLogPlugin/ChangeLog.txt
@@ -11,8 +11,8 @@ It is now possible to specify the cooling fan to use if your printer has multipl
*Settings refactor
The CuraEngine has been refactored to create a more testable, future-proof way of storing and representing settings. This makes slicing faster, and future development easier.
-*Print core CC Red 0.6
-The new print core CC Red 0.6 is selectable when the Ultimaker S5 profile is active. This print core is optimized for use with abrasive materials and composites.
+*Print core CC 0.6
+The new print core CC 0.6 is selectable when the Ultimaker S5 profile is active. This print core is optimized for use with abrasive materials and composites.
*File name and layer display
Added M117 commands to GCODE to give real-time information about the print job file name and layer number shown on the printer’s display when printing via USB. Contributed by adecastilho.
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/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py
index 58bc74f3f1..f12a5b1222 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.
diff --git a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py
index 594bf3a43e..71c96880e8 100644
--- a/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py
+++ b/plugins/CuraEngineBackend/ProcessSlicedLayersJob.py
@@ -195,7 +195,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 4c60b95824..9efd3e956a 100644
--- a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py
+++ b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py
@@ -93,6 +93,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.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/DictionaryOfDoom.json b/plugins/LegacyProfileReader/DictionaryOfDoom.json
index 0be413dd2c..f65cc271d1 100644
--- a/plugins/LegacyProfileReader/DictionaryOfDoom.json
+++ b/plugins/LegacyProfileReader/DictionaryOfDoom.json
@@ -1,6 +1,6 @@
{
"source_version": "15.04",
- "target_version": 3,
+ "target_version": "4.5",
"translation": {
"machine_nozzle_size": "nozzle_size",
diff --git a/plugins/LegacyProfileReader/LegacyProfileReader.py b/plugins/LegacyProfileReader/LegacyProfileReader.py
index cd577218d5..013bab6f11 100644
--- a/plugins/LegacyProfileReader/LegacyProfileReader.py
+++ b/plugins/LegacyProfileReader/LegacyProfileReader.py
@@ -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 configparser # For reading the legacy profile INI files.
@@ -6,6 +6,7 @@ import io
import json # For reading the Dictionary of Doom.
import math # For mathematical operations included in the Dictionary of Doom.
import os.path # For concatenating the path to the plugin and the relative path to the Dictionary of Doom.
+from typing import Dict
from UM.Application import Application # To get the machine manager to create the new profile in.
from UM.Logger import Logger # Logging errors.
@@ -33,10 +34,11 @@ class LegacyProfileReader(ProfileReader):
# \param json The JSON file to load the default setting values from. This
# should not be a URL but a pre-loaded JSON handle.
# \return A dictionary of the default values of the legacy Cura version.
- def prepareDefaults(self, json):
+ def prepareDefaults(self, json: Dict[str, Dict[str, str]]) -> Dict[str, str]:
defaults = {}
- for key in json["defaults"]: # We have to copy over all defaults from the JSON handle to a normal dict.
- defaults[key] = json["defaults"][key]
+ if "defaults" in json:
+ for key in json["defaults"]: # We have to copy over all defaults from the JSON handle to a normal dict.
+ defaults[key] = json["defaults"][key]
return defaults
## Prepares the local variables that can be used in evaluation of computing
@@ -80,11 +82,10 @@ class LegacyProfileReader(ProfileReader):
Logger.log("i", "Importing legacy profile from file " + file_name + ".")
container_registry = ContainerRegistry.getInstance()
profile_id = container_registry.uniqueName("Imported Legacy Profile")
- profile = InstanceContainer(profile_id) # Create an empty profile.
- parser = configparser.ConfigParser(interpolation = None)
+ input_parser = configparser.ConfigParser(interpolation = None)
try:
- parser.read([file_name]) # Parse the INI file.
+ input_parser.read([file_name]) # Parse the INI file.
except Exception as e:
Logger.log("e", "Unable to open legacy profile %s: %s", file_name, str(e))
return None
@@ -92,7 +93,7 @@ class LegacyProfileReader(ProfileReader):
# Legacy Cura saved the profile under the section "profile_N" where N is the ID of a machine, except when you export in which case it saves it in the section "profile".
# Since importing multiple machine profiles is out of scope, just import the first section we find.
section = ""
- for found_section in parser.sections():
+ for found_section in input_parser.sections():
if found_section.startswith("profile"):
section = found_section
break
@@ -110,15 +111,13 @@ class LegacyProfileReader(ProfileReader):
return None
defaults = self.prepareDefaults(dict_of_doom)
- legacy_settings = self.prepareLocals(parser, section, defaults) #Gets the settings from the legacy profile.
+ legacy_settings = self.prepareLocals(input_parser, section, defaults) #Gets the settings from the legacy profile.
- #Check the target version in the Dictionary of Doom with this application version.
- if "target_version" not in dict_of_doom:
- Logger.log("e", "Dictionary of Doom has no target version. Is it the correct JSON file?")
- return None
- if InstanceContainer.Version != dict_of_doom["target_version"]:
- Logger.log("e", "Dictionary of Doom of legacy profile reader (version %s) is not in sync with the current instance container version (version %s)!", dict_of_doom["target_version"], str(InstanceContainer.Version))
- return None
+ # Serialised format into version 4.5. Do NOT upgrade this, let the version upgrader handle it.
+ output_parser = configparser.ConfigParser(interpolation = None)
+ output_parser.add_section("general")
+ output_parser.add_section("metadata")
+ output_parser.add_section("values")
if "translation" not in dict_of_doom:
Logger.log("e", "Dictionary of Doom has no translation. Is it the correct JSON file?")
@@ -127,7 +126,7 @@ class LegacyProfileReader(ProfileReader):
quality_definition = current_printer_definition.getMetaDataEntry("quality_definition")
if not quality_definition:
quality_definition = current_printer_definition.getId()
- profile.setDefinition(quality_definition)
+ output_parser["general"]["definition"] = quality_definition
for new_setting in dict_of_doom["translation"]: # Evaluate all new settings that would get a value from the translations.
old_setting_expression = dict_of_doom["translation"][new_setting]
compiled = compile(old_setting_expression, new_setting, "eval")
@@ -140,37 +139,34 @@ class LegacyProfileReader(ProfileReader):
definitions = current_printer_definition.findDefinitions(key = new_setting)
if definitions:
if new_value != value_using_defaults and definitions[0].default_value != new_value: # Not equal to the default in the new Cura OR the default in the legacy Cura.
- profile.setProperty(new_setting, "value", new_value) # Store the setting in the profile!
+ output_parser["values"][new_setting] = str(new_value) # Store the setting in the profile!
- if len(profile.getAllKeys()) == 0:
+ if len(output_parser["values"]) == 0:
Logger.log("i", "A legacy profile was imported but everything evaluates to the defaults, creating an empty profile.")
- profile.setMetaDataEntry("type", "profile")
- # don't know what quality_type it is based on, so use "normal" by default
- profile.setMetaDataEntry("quality_type", "normal")
- profile.setName(profile_id)
- profile.setDirty(True)
+ output_parser["general"]["version"] = "4"
+ output_parser["general"]["name"] = profile_id
+ output_parser["metadata"]["type"] = "quality_changes"
+ output_parser["metadata"]["quality_type"] = "normal" # Don't know what quality_type it is based on, so use "normal" by default.
+ output_parser["metadata"]["position"] = "0" # We only support single extrusion.
+ output_parser["metadata"]["setting_version"] = "5" # What the dictionary of doom is made for.
- #Serialise and deserialise in order to perform the version upgrade.
- parser = configparser.ConfigParser(interpolation = None)
- data = profile.serialize()
- parser.read_string(data)
- parser["general"]["version"] = "1"
- if parser.has_section("values"):
- parser["settings"] = parser["values"]
- del parser["values"]
+ # Serialise in order to perform the version upgrade.
stream = io.StringIO()
- parser.write(stream)
+ output_parser.write(stream)
data = stream.getvalue()
- profile.deserialize(data)
- # The definition can get reset to fdmprinter during the deserialization's upgrade. Here we set the definition
- # again.
- profile.setDefinition(quality_definition)
+ profile = InstanceContainer(profile_id)
+ profile.deserialize(data) # Also performs the version upgrade.
+ profile.setDirty(True)
#We need to return one extruder stack and one global stack.
global_container_id = container_registry.uniqueName("Global Imported Legacy Profile")
+ # We duplicate the extruder profile into the global stack.
+ # This may introduce some settings that are global in the extruder stack and some settings that are per-extruder in the global stack.
+ # We don't care about that. The engine will ignore them anyway.
global_profile = profile.duplicate(new_id = global_container_id, new_name = profile_id) #Needs to have the same name as the extruder profile.
+ del global_profile.getMetaData()["position"] # Has no position because it's global.
global_profile.setDirty(True)
profile_definition = "fdmprinter"
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/LegacyProfileReader/tests/TestLegacyProfileReader.py b/plugins/LegacyProfileReader/tests/TestLegacyProfileReader.py
new file mode 100644
index 0000000000..480a61f301
--- /dev/null
+++ b/plugins/LegacyProfileReader/tests/TestLegacyProfileReader.py
@@ -0,0 +1,190 @@
+# Copyright (c) 2018 Ultimaker B.V.
+# Cura is released under the terms of the LGPLv3 or higher.
+
+import configparser # An input for some functions we're testing.
+import os.path # To find the integration test .ini files.
+import pytest # To register tests with.
+import unittest.mock # To mock the application, plug-in and container registry out.
+
+import UM.Application # To mock the application out.
+import UM.PluginRegistry # To mock the plug-in registry out.
+import UM.Settings.ContainerRegistry # To mock the container registry out.
+import UM.Settings.InstanceContainer # To intercept the serialised data from the read() function.
+
+import LegacyProfileReader as LegacyProfileReaderModule # To get the directory of the module.
+from LegacyProfileReader import LegacyProfileReader # The module we're testing.
+
+@pytest.fixture
+def legacy_profile_reader():
+ return LegacyProfileReader()
+
+test_prepareDefaultsData = [
+ {
+ "defaults":
+ {
+ "foo": "bar"
+ },
+ "cheese": "delicious"
+ },
+ {
+ "cat": "fluffy",
+ "dog": "floofy"
+ }
+]
+
+@pytest.mark.parametrize("input", test_prepareDefaultsData)
+def test_prepareDefaults(legacy_profile_reader, input):
+ output = legacy_profile_reader.prepareDefaults(input)
+ if "defaults" in input:
+ assert input["defaults"] == output
+ else:
+ assert output == {}
+
+test_prepareLocalsData = [
+ ( # Ordinary case.
+ { # Parser data.
+ "profile":
+ {
+ "layer_height": "0.2",
+ "infill_density": "30"
+ }
+ },
+ { # Defaults.
+ "layer_height": "0.1",
+ "infill_density": "20",
+ "line_width": "0.4"
+ }
+ ),
+ ( # Empty data.
+ { # Parser data.
+ "profile":
+ {
+ }
+ },
+ { # Defaults.
+ }
+ ),
+ ( # All defaults.
+ { # Parser data.
+ "profile":
+ {
+ }
+ },
+ { # Defaults.
+ "foo": "bar",
+ "boo": "far"
+ }
+ ),
+ ( # Multiple config sections.
+ { # Parser data.
+ "some_other_name":
+ {
+ "foo": "bar"
+ },
+ "profile":
+ {
+ "foo": "baz" #Not the same as in some_other_name
+ }
+ },
+ { # Defaults.
+ "foo": "bla"
+ }
+ )
+]
+
+@pytest.mark.parametrize("parser_data, defaults", test_prepareLocalsData)
+def test_prepareLocals(legacy_profile_reader, parser_data, defaults):
+ parser = configparser.ConfigParser()
+ parser.read_dict(parser_data)
+
+ output = legacy_profile_reader.prepareLocals(parser, "profile", defaults)
+
+ assert set(defaults.keys()) <= set(output.keys()) # All defaults must be in there.
+ assert set(parser_data["profile"]) <= set(output.keys()) # All overwritten values must be in there.
+ for key in output:
+ if key in parser_data["profile"]:
+ assert output[key] == parser_data["profile"][key] # If overwritten, must be the overwritten value.
+ else:
+ assert output[key] == defaults[key] # Otherwise must be equal to the default.
+
+test_prepareLocalsNoSectionErrorData = [
+ ( # Section does not exist.
+ { # Parser data.
+ "some_other_name":
+ {
+ "foo": "bar"
+ },
+ },
+ { # Defaults.
+ "foo": "baz"
+ }
+ )
+]
+
+## Test cases where a key error is expected.
+@pytest.mark.parametrize("parser_data, defaults", test_prepareLocalsNoSectionErrorData)
+def test_prepareLocalsNoSectionError(legacy_profile_reader, parser_data, defaults):
+ parser = configparser.ConfigParser()
+ parser.read_dict(parser_data)
+
+ with pytest.raises(configparser.NoSectionError):
+ legacy_profile_reader.prepareLocals(parser, "profile", defaults)
+
+intercepted_data = ""
+
+@pytest.mark.parametrize("file_name", ["normal_case.ini"])
+def test_read(legacy_profile_reader, file_name):
+ # Mock out all dependencies. Quite a lot!
+ global_stack = unittest.mock.MagicMock()
+ global_stack.getProperty = unittest.mock.MagicMock(return_value = 1) # For machine_extruder_count setting.
+ def getMetaDataEntry(key, default_value = ""):
+ if key == "quality_definition":
+ return "mocked_quality_definition"
+ if key == "has_machine_quality":
+ return "True"
+ global_stack.definition.getMetaDataEntry = getMetaDataEntry
+ global_stack.definition.getId = unittest.mock.MagicMock(return_value = "mocked_global_definition")
+ application = unittest.mock.MagicMock()
+ application.getGlobalContainerStack = unittest.mock.MagicMock(return_value = global_stack)
+ application_getInstance = unittest.mock.MagicMock(return_value = application)
+ container_registry = unittest.mock.MagicMock()
+ container_registry_getInstance = unittest.mock.MagicMock(return_value = container_registry)
+ container_registry.uniqueName = unittest.mock.MagicMock(return_value = "Imported Legacy Profile")
+ container_registry.findDefinitionContainers = unittest.mock.MagicMock(return_value = [global_stack.definition])
+ UM.Settings.InstanceContainer.setContainerRegistry(container_registry)
+ plugin_registry = unittest.mock.MagicMock()
+ plugin_registry_getInstance = unittest.mock.MagicMock(return_value = plugin_registry)
+ plugin_registry.getPluginPath = unittest.mock.MagicMock(return_value = os.path.dirname(LegacyProfileReaderModule.__file__))
+
+ # Mock out the resulting InstanceContainer so that we can intercept the data before it's passed through the version upgrader.
+ def deserialize(self, data): # Intercepts the serialised data that we'd perform the version upgrade from when deserializing.
+ global intercepted_data
+ intercepted_data = data
+
+ parser = configparser.ConfigParser()
+ parser.read_string(data)
+ self._metadata["position"] = parser["metadata"]["position"]
+ def duplicate(self, new_id, new_name):
+ self._metadata["id"] = new_id
+ self._metadata["name"] = new_name
+ return self
+
+ with unittest.mock.patch.object(UM.Application.Application, "getInstance", application_getInstance):
+ with unittest.mock.patch.object(UM.Settings.ContainerRegistry.ContainerRegistry, "getInstance", container_registry_getInstance):
+ with unittest.mock.patch.object(UM.PluginRegistry.PluginRegistry, "getInstance", plugin_registry_getInstance):
+ with unittest.mock.patch.object(UM.Settings.InstanceContainer.InstanceContainer, "deserialize", deserialize):
+ with unittest.mock.patch.object(UM.Settings.InstanceContainer.InstanceContainer, "duplicate", duplicate):
+ result = legacy_profile_reader.read(os.path.join(os.path.dirname(__file__), file_name))
+
+ assert len(result) == 1
+
+ # Let's see what's inside the actual output file that we generated.
+ parser = configparser.ConfigParser()
+ parser.read_string(intercepted_data)
+ assert parser["general"]["definition"] == "mocked_quality_definition"
+ assert parser["general"]["version"] == "4" # Yes, before we upgraded.
+ assert parser["general"]["name"] == "Imported Legacy Profile" # Because we overwrote uniqueName.
+ assert parser["metadata"]["type"] == "quality_changes"
+ assert parser["metadata"]["quality_type"] == "normal"
+ assert parser["metadata"]["position"] == "0"
+ assert parser["metadata"]["setting_version"] == "5" # Yes, before we upgraded.
\ No newline at end of file
diff --git a/plugins/LegacyProfileReader/tests/normal_case.ini b/plugins/LegacyProfileReader/tests/normal_case.ini
new file mode 100644
index 0000000000..213444d2d3
--- /dev/null
+++ b/plugins/LegacyProfileReader/tests/normal_case.ini
@@ -0,0 +1,7 @@
+[profile]
+foo = bar
+boo = far
+fill_overlap = 3
+
+[alterations]
+some = values
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/MonitorMainView.qml b/plugins/MonitorStage/MonitorMain.qml
similarity index 66%
rename from plugins/MonitorStage/MonitorMainView.qml
rename to plugins/MonitorStage/MonitorMain.qml
index c48f6d0aab..34cf4ad801 100644
--- a/plugins/MonitorStage/MonitorMainView.qml
+++ b/plugins/MonitorStage/MonitorMain.qml
@@ -1,45 +1,48 @@
-// 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
- }
-}
+// Copyright (c) 2017 Ultimaker B.V.
+
+import QtQuick 2.10
+import QtQuick.Controls 1.4
+
+import UM 1.3 as UM
+import Cura 1.0 as Cura
+
+
+Item
+{
+ // 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
+ }
+}
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 1a1ea92d10..78f9cc0516 100644
--- a/plugins/PostProcessingPlugin/PostProcessingPlugin.py
+++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.py
@@ -32,7 +32,8 @@ class PostProcessingPlugin(QObject, Extension):
def __init__(self, parent = None) -> None:
QObject.__init__(self, parent)
Extension.__init__(self)
- self.addMenuItem(i18n_catalog.i18n("Modify G-Code"), self.showPopup)
+ self.setMenuName(i18n_catalog.i18nc("@item:inmenu", "Post Processing"))
+ self.addMenuItem(i18n_catalog.i18nc("@item:inmenu", "Modify G-Code"), self.showPopup)
self._view = None
# Loaded scripts are all scripts that can be used
@@ -54,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..d5fe618b2d 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
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/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/SimulationSliderLabel.qml b/plugins/SimulationView/SimulationSliderLabel.qml
index b69fede243..06c6a51b44 100644
--- a/plugins/SimulationView/SimulationSliderLabel.qml
+++ b/plugins/SimulationView/SimulationSliderLabel.qml
@@ -48,7 +48,7 @@ UM.PointingRectangle {
horizontalCenter: parent.horizontalCenter
}
- width: (maximumValue.toString().length + 1) * 10 * screenScaleFactor
+ width: ((maximumValue + 1).toString().length + 1) * 10 * screenScaleFactor
text: sliderLabelRoot.value + startFrom // the current handle value, add 1 because layers is an array
horizontalAlignment: TextInput.AlignRight
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/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..9ede2a6bda 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
{
@@ -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 58fea079e9..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
@@ -11,157 +11,232 @@ Item
id: base
property var packageData
- property var technicalDataSheetUrl: {
+ property var technicalDataSheetUrl:
+ {
var link = undefined
if ("Technical Data Sheet" in packageData.links)
{
+ // HACK: This is the way the old API (used in 3.6-beta) used to do it. For safety it's still here,
+ // but it can be removed over time.
link = packageData.links["Technical Data Sheet"]
}
+ else if ("technicalDataSheet" in packageData.links)
+ {
+ link = packageData.links["technicalDataSheet"]
+ }
return link
}
+ property var safetyDataSheetUrl:
+ {
+ var sds_name = "safetyDataSheet"
+ return (sds_name in packageData.links) ? packageData.links[sds_name] : undefined
+ }
+ property var printingGuidelinesUrl:
+ {
+ 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
- Label
+
+ visible: packageData.type == "material" &&
+ (packageData.has_configs || technicalDataSheetUrl !== undefined ||
+ safetyDataSheetUrl !== undefined || printingGuidelinesUrl !== undefined ||
+ materialWebsiteUrl !== undefined)
+
+ Item
{
- id: heading
- anchors.topMargin: UM.Theme.getSize("default_margin").height
+ id: combatibilityItem
+ visible: packageData.has_configs
width: parent.width
- text: catalog.i18nc("@label", "Compatibility")
- wrapMode: Text.WordWrap
- color: UM.Theme.getColor("text_medium")
- font: UM.Theme.getFont("medium")
- }
- TableView
- {
- id: table
- anchors.top: heading.bottom
- anchors.topMargin: UM.Theme.getSize("default_margin").height
- width: parent.width
- frameVisible: false
+ // This is a bit of a hack, but the whole QML is pretty messy right now. This needs a big overhaul.
+ height: visible ? heading.height + table.height: 0
- // Workaround for scroll issues (QTBUG-49652)
- flickableItem.interactive: false
- Component.onCompleted:
+ Label
{
- for (var i = 0; i < flickableItem.children.length; ++i)
- {
- flickableItem.children[i].enabled = false
- }
- }
- selectionMode: 0
- model: packageData.supported_configs
- headerDelegate: Rectangle
- {
- color: UM.Theme.getColor("sidebar")
- height: UM.Theme.getSize("toolbox_chart_row").height
- Label
- {
- anchors.verticalCenter: parent.verticalCenter
- elide: Text.ElideRight
- text: styleData.value || ""
- color: UM.Theme.getColor("text")
- font: UM.Theme.getFont("default_bold")
- }
- Rectangle
- {
- anchors.bottom: parent.bottom
- height: UM.Theme.getSize("default_lining").height
- width: parent.width
- color: "black"
- }
- }
- rowDelegate: Item
- {
- height: UM.Theme.getSize("toolbox_chart_row").height
- Label
- {
- anchors.verticalCenter: parent.verticalCenter
- elide: Text.ElideRight
- text: styleData.value || ""
- color: UM.Theme.getColor("text_medium")
- font: UM.Theme.getFont("default")
- }
- }
- itemDelegate: Item
- {
- height: UM.Theme.getSize("toolbox_chart_row").height
- Label
- {
- anchors.verticalCenter: parent.verticalCenter
- elide: Text.ElideRight
- text: styleData.value || ""
- color: UM.Theme.getColor("text_medium")
- font: UM.Theme.getFont("default")
- }
+ id: heading
+ anchors.topMargin: UM.Theme.getSize("default_margin").height
+ width: parent.width
+ text: catalog.i18nc("@label", "Compatibility")
+ wrapMode: Text.WordWrap
+ color: UM.Theme.getColor("text_medium")
+ font: UM.Theme.getFont("medium")
+ renderType: Text.NativeRendering
}
- Component
+ TableView
{
- id: columnTextDelegate
- Label
- {
- anchors.fill: parent
- verticalAlignment: Text.AlignVCenter
- text: styleData.value || ""
- elide: Text.ElideRight
- color: UM.Theme.getColor("text_medium")
- font: UM.Theme.getFont("default")
- }
- }
+ id: table
+ anchors.top: heading.bottom
+ anchors.topMargin: UM.Theme.getSize("default_margin").height
+ width: parent.width
+ frameVisible: false
- TableViewColumn
- {
- role: "machine"
- title: "Machine"
- width: Math.floor(table.width * 0.25)
- delegate: columnTextDelegate
- }
- TableViewColumn
- {
- role: "print_core"
- title: "Print Core"
- width: Math.floor(table.width * 0.2)
- }
- TableViewColumn
- {
- role: "build_plate"
- title: "Build Plate"
- width: Math.floor(table.width * 0.225)
- }
- TableViewColumn
- {
- role: "support_material"
- title: "Support"
- width: Math.floor(table.width * 0.225)
- }
- TableViewColumn
- {
- role: "quality"
- title: "Quality"
- width: Math.floor(table.width * 0.1)
+ // Workaround for scroll issues (QTBUG-49652)
+ flickableItem.interactive: false
+ Component.onCompleted:
+ {
+ for (var i = 0; i < flickableItem.children.length; ++i)
+ {
+ flickableItem.children[i].enabled = false
+ }
+ }
+ selectionMode: 0
+ model: packageData.supported_configs
+ headerDelegate: Rectangle
+ {
+ color: UM.Theme.getColor("main_background")
+ height: UM.Theme.getSize("toolbox_chart_row").height
+ Label
+ {
+ anchors.verticalCenter: parent.verticalCenter
+ elide: Text.ElideRight
+ text: styleData.value || ""
+ color: UM.Theme.getColor("text")
+ font: UM.Theme.getFont("default_bold")
+ renderType: Text.NativeRendering
+ }
+ Rectangle
+ {
+ anchors.bottom: parent.bottom
+ height: UM.Theme.getSize("default_lining").height
+ width: parent.width
+ color: "black"
+ }
+ }
+ rowDelegate: Item
+ {
+ height: UM.Theme.getSize("toolbox_chart_row").height
+ Label
+ {
+ anchors.verticalCenter: parent.verticalCenter
+ elide: Text.ElideRight
+ text: styleData.value || ""
+ color: UM.Theme.getColor("text_medium")
+ font: UM.Theme.getFont("default")
+ renderType: Text.NativeRendering
+ }
+ }
+ itemDelegate: Item
+ {
+ height: UM.Theme.getSize("toolbox_chart_row").height
+ Label
+ {
+ anchors.verticalCenter: parent.verticalCenter
+ elide: Text.ElideRight
+ text: styleData.value || ""
+ color: UM.Theme.getColor("text_medium")
+ font: UM.Theme.getFont("default")
+ renderType: Text.NativeRendering
+ }
+ }
+
+ Component
+ {
+ id: columnTextDelegate
+ Label
+ {
+ anchors.fill: parent
+ verticalAlignment: Text.AlignVCenter
+ text: styleData.value || ""
+ elide: Text.ElideRight
+ color: UM.Theme.getColor("text_medium")
+ font: UM.Theme.getFont("default")
+ renderType: Text.NativeRendering
+ }
+ }
+
+ TableViewColumn
+ {
+ role: "machine"
+ title: "Machine"
+ width: Math.floor(table.width * 0.25)
+ delegate: columnTextDelegate
+ }
+ TableViewColumn
+ {
+ role: "print_core"
+ title: "Print Core"
+ width: Math.floor(table.width * 0.2)
+ }
+ TableViewColumn
+ {
+ role: "build_plate"
+ title: "Build Plate"
+ width: Math.floor(table.width * 0.225)
+ }
+ TableViewColumn
+ {
+ role: "support_material"
+ title: "Support"
+ width: Math.floor(table.width * 0.225)
+ }
+ TableViewColumn
+ {
+ role: "quality"
+ title: "Quality"
+ width: Math.floor(table.width * 0.1)
+ }
}
}
Label
{
- id: technical_data_sheet
- anchors.top: table.bottom
+ id: data_sheet_links
+ anchors.top: combatibilityItem.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height / 2
- visible: base.technicalDataSheetUrl !== undefined
+ visible: base.technicalDataSheetUrl !== undefined ||
+ base.safetyDataSheetUrl !== undefined || base.printingGuidelinesUrl !== undefined ||
+ base.materialWebsiteUrl !== undefined
+ height: visible ? contentHeight : 0
text:
{
+ var result = ""
if (base.technicalDataSheetUrl !== undefined)
{
- return "%2".arg(base.technicalDataSheetUrl).arg("Technical Data Sheet")
+ var tds_name = catalog.i18nc("@action:label", "Technical Data Sheet")
+ result += "%2".arg(base.technicalDataSheetUrl).arg(tds_name)
}
- return ""
+ if (base.safetyDataSheetUrl !== undefined)
+ {
+ if (result.length > 0)
+ {
+ result += " "
+ }
+ var sds_name = catalog.i18nc("@action:label", "Safety Data Sheet")
+ result += "%2".arg(base.safetyDataSheetUrl).arg(sds_name)
+ }
+ if (base.printingGuidelinesUrl !== undefined)
+ {
+ if (result.length > 0)
+ {
+ result += " "
+ }
+ 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 d544757d58..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: 3
+ 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..7160dafa2d 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,20 +73,19 @@ 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
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..333d4dd50a 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
@@ -49,17 +49,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 +83,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 +92,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 aa5626b7f2..d94fdf6bb7 100644
--- a/plugins/Toolbox/src/PackagesModel.py
+++ b/plugins/Toolbox/src/PackagesModel.py
@@ -12,7 +12,7 @@ from UM.Qt.ListModel import ListModel
from .ConfigsModel import ConfigsModel
-## Model that holds cura packages. By setting the filter property the instances held by this model can be changed.
+## Model that holds Cura packages. By setting the filter property the instances held by this model can be changed.
class PackagesModel(ListModel):
def __init__(self, parent = None):
super().__init__(parent)
@@ -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 = []
@@ -70,7 +75,7 @@ class PackagesModel(ListModel):
# Links is a list of dictionaries with "title" and "url". Convert this list into a dict so it's easier
# to process.
- link_list = package['data']['links'] if 'links' in package['data'] else []
+ link_list = package["data"]["links"] if "links" in package["data"] else []
links_dict = {d["title"]: d["url"] for d in link_list}
if "author_id" not in package["author"] or "display_name" not in package["author"]:
@@ -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 25e7656999..05669e55d8 100644
--- a/plugins/Toolbox/src/Toolbox.py
+++ b/plugins/Toolbox/src/Toolbox.py
@@ -13,7 +13,6 @@ 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
@@ -31,8 +30,8 @@ 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
+ 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__()
@@ -50,47 +49,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 +107,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 +127,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
@@ -172,18 +186,13 @@ class Toolbox(QObject, Extension):
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,
- sdk_version=self._sdk_version
+ cloud_api_root = self._cloud_api_root,
+ cloud_api_version = self._cloud_api_version,
+ sdk_version = self._sdk_version
)
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))
+ "authors": QUrl("{base_url}/authors".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.
@@ -192,9 +201,9 @@ class Toolbox(QObject, Extension):
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
+ if not cura.CuraVersion.CuraCloudAPIRoot: # type: ignore
return self.DEFAULT_CLOUD_API_ROOT
- return cura.CuraVersion.CuraCloudAPIRoot # type: ignore
+ return cura.CuraVersion.CuraCloudAPIRoot # type: ignore
# Get the cloud API version from CuraVersion
def _getCloudAPIVersion(self) -> int:
@@ -202,18 +211,18 @@ class Toolbox(QObject, Extension):
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
+ if not cura.CuraVersion.CuraCloudAPIVersion: # type: ignore
return self.DEFAULT_CLOUD_API_VERSION
- return cura.CuraVersion.CuraCloudAPIVersion # type: ignore
+ 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._plugin_registry.APIVersion
+ return self._application.getAPIVersion().getMajor()
if not hasattr(cura.CuraVersion, "CuraSDKVersion"): # type: ignore
- return self._plugin_registry.APIVersion
+ return self._application.getAPIVersion().getMajor()
if not cura.CuraVersion.CuraSDKVersion: # type: ignore
- return self._plugin_registry.APIVersion
+ return self._application.getAPIVersion().getMajor()
return cura.CuraVersion.CuraSDKVersion # type: ignore
@pyqtSlot()
@@ -231,12 +240,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()
@@ -265,21 +268,25 @@ class Toolbox(QObject, Extension):
raise Exception("Failed to create Marketplace dialog")
return dialog
- def _convertPluginMetadata(self, plugin: Dict[str, Any]) -> Dict[str, Any]:
- formatted = {
- "package_id": plugin["id"],
- "package_type": "plugin",
- "display_name": plugin["plugin"]["name"],
- "package_version": plugin["plugin"]["version"],
- "sdk_version": plugin["plugin"]["api"],
- "author": {
- "author_id": plugin["plugin"]["author"],
- "display_name": plugin["plugin"]["author"]
- },
- "is_installed": True,
- "description": plugin["plugin"]["description"]
- }
- return formatted
+ def _convertPluginMetadata(self, plugin_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
+ try:
+ 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"],
+ "author": {
+ "author_id": plugin_data["plugin"]["author"],
+ "display_name": plugin_data["plugin"]["author"]
+ },
+ "is_installed": True,
+ "description": plugin_data["plugin"]["description"]
+ }
+ return formatted
+ except KeyError:
+ Logger.log("w", "Unable to convert plugin meta data %s", str(plugin_data))
+ return None
@pyqtSlot()
def _updateInstalledModels(self) -> None:
@@ -295,11 +302,13 @@ class Toolbox(QObject, Extension):
for plugin_id in old_plugin_ids:
# Neither the installed packages nor the packages that are scheduled to remove are old plugins
if plugin_id not in installed_package_ids and plugin_id not in scheduled_to_remove_package_ids:
- Logger.log('i', 'Found a plugin that was installed with the old plugin browser: %s', plugin_id)
+ Logger.log("i", "Found a plugin that was installed with the old plugin browser: %s", plugin_id)
old_metadata = self._plugin_registry.getMetaData(plugin_id)
new_metadata = self._convertPluginMetadata(old_metadata)
-
+ if new_metadata is None:
+ # Something went wrong converting it.
+ continue
self._old_plugin_ids.add(plugin_id)
self._old_plugin_metadata[new_metadata["package_id"]] = new_metadata
@@ -313,13 +322,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)
@@ -473,7 +479,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
@@ -485,11 +491,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)
@@ -505,7 +508,10 @@ class Toolbox(QObject, Extension):
# version, we also need to check if the current one has a lower SDK version. If so, this package should also
# be upgradable.
elif remote_version == local_version:
- can_upgrade = local_package.get("sdk_version", 0) < remote_package.get("sdk_version", 0)
+ # First read sdk_version_semver. If that doesn't exist, read just sdk_version (old version system).
+ remote_sdk_version = Version(remote_package.get("sdk_version_semver", remote_package.get("sdk_version", 0)))
+ local_sdk_version = Version(local_package.get("sdk_version_semver", local_package.get("sdk_version", 0)))
+ can_upgrade = local_sdk_version < remote_sdk_version
return can_upgrade
@@ -536,8 +542,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
@@ -545,7 +551,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
@@ -559,34 +565,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"):
@@ -595,7 +598,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)
@@ -603,15 +607,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
@@ -637,22 +641,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:
@@ -665,39 +655,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
@@ -707,7 +691,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
@@ -717,10 +707,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)
@@ -729,7 +719,6 @@ class Toolbox(QObject, Extension):
return
self.install(file_path)
- return
# Getter & Setters for Properties:
# --------------------------------------------------------------------------
@@ -752,8 +741,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)
@@ -761,16 +751,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:
@@ -778,48 +770,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()
@@ -827,7 +819,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()
@@ -835,21 +827,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"]
@@ -858,30 +850,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/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..f86135ae62
--- /dev/null
+++ b/plugins/UM3NetworkPrinting/resources/qml/ExpandableCard.qml
@@ -0,0 +1,82 @@
+// 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 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: headerMouseArea.containsMouse ? headerHoverColor : headerBackgroundColor
+ height: childrenRect.height
+ width: parent.width
+ Behavior on color
+ {
+ ColorAnimation
+ {
+ duration: 100
+ }
+ }
+ }
+
+ MouseArea
+ {
+ id: headerMouseArea
+ anchors.fill: header
+ onClicked: base.expanded = !base.expanded
+ hoverEnabled: true
+ }
+
+ 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..44bd47f904
--- /dev/null
+++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorBuildplateConfiguration.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.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 alias buildplate: buildplateLabel.text
+
+ // 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 // TODO: Theme! (Should be same as extruder icon width)
+
+ UM.RecolorImage
+ {
+ id: buildplateIcon
+ anchors.centerIn: parent
+ color: "#0a0850" // TODO: Theme! (Standard purple)
+ height: parent.height
+ source: "../svg/icons/buildplate.svg"
+ width: height
+ }
+ }
+
+ Label
+ {
+ id: buildplateLabel
+ color: "#191919" // TODO: Theme!
+ elide: Text.ElideRight
+ font: UM.Theme.getFont("default") // 12pt, regular
+ 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..eccd93c578
--- /dev/null
+++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorCarousel.qml
@@ -0,0 +1,252 @@
+// 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!
+ property var maxOffset: (OutputDevice.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: OutputDevice.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 < OutputDevice.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!
+ Repeater
+ {
+ model: OutputDevice.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 < OutputDevice.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..6a32310dd5
--- /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.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 += "
";
- 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;
- }
- 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 6c6df7d7fb..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml
+++ /dev/null
@@ -1,270 +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 + UM.Theme.getSize("default_margin").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;
- anchors {
- top: parent.top;
- topMargin: UM.Theme.getSize("default_margin").height;
- }
- height: childrenRect.height;
- width: parent.width;
- spacing: UM.Theme.getSize("default_margin").height;
-
- // Main card
- Item {
- id: mainCard;
- height: 60 * screenScaleFactor;
- width: parent.width;
-
- // Machine icon
- Item {
- id: machineIcon;
- anchors {
- leftMargin: UM.Theme.getSize("wide_margin").width;
- top: parent.top;
- left: parent.left;
- margins: UM.Theme.getSize("default_margin").width;
- }
- 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;
- }
- }
- }
-
- HorizontalLine {
- anchors {
- left: parent.left;
- leftMargin: UM.Theme.getSize("default_margin").width;
- right: parent.right;
- rightMargin: UM.Theme.getSize("default_margin").width;
- }
- visible: root.printer;
- }
-
- // Detailed card
- PrinterCardDetails {
- collapsed: root.collapsed;
- printer: root.printer;
- visible: root.printer;
- }
-
- CameraButton {
- id: showCameraButton;
- anchors {
- left: parent.left;
- leftMargin: UM.Theme.getSize("default_margin").width;
- }
- iconSource: "../svg/camera-icon.svg";
- visible: root.printer && root.printJob;
- }
- }
-
- // Progress bar
- PrinterCardProgressBar {
- anchors {
- top: cardContents.bottom;
- topMargin: UM.Theme.getSize("default_margin").height;
- }
- 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 097bd5c7a6..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml
+++ /dev/null
@@ -1,69 +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("wide_margin").height;
- spacing: UM.Theme.getSize("default_margin").height;
- width: parent.width;
-
- PrinterInfoBlock {
- printer: root.printer;
- printJob: root.printer ? root.printer.activePrintJob : null;
- }
-
- HorizontalLine {
- visible: root.printJob;
- }
-
- 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;
- }
- }
-}
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..320201e165 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;
@@ -83,9 +115,7 @@ Item {
Column {
Repeater {
- model: Cura.ExtrudersModel {
- simpleNames: true;
- }
+ model: CuraApplication.getExtrudersModel()
Label {
text: model.name;
@@ -96,7 +126,7 @@ Item {
Column {
Repeater {
id: nozzleColumn;
- model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].hotendIds : null;
+ model: hotendIds
Label {
text: nozzleColumn.model[index];
@@ -107,7 +137,7 @@ Item {
Column {
Repeater {
id: materialColumn;
- model: printerConnected ? Cura.MachineManager.printerOutputDevices[0].materialNames : null;
+ model: materialNames
Label {
text: materialColumn.model[index];
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/external_link.svg b/plugins/UM3NetworkPrinting/resources/svg/icons/external_link.svg
new file mode 100644
index 0000000000..a2130fb97b
--- /dev/null
+++ b/plugins/UM3NetworkPrinting/resources/svg/icons/external_link.svg
@@ -0,0 +1,8 @@
+
\ 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/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py
index 7504d55ad9..5e8aaa9fa9 100644
--- a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py
+++ b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py
@@ -22,6 +22,7 @@ from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationM
from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
+from cura.PrinterOutputDevice import ConnectionType
from .ClusterUM3PrinterOutputController import ClusterUM3PrinterOutputController
from .SendMaterialJob import SendMaterialJob
@@ -54,7 +55,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
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
@@ -64,8 +65,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
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)
@@ -387,8 +387,24 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
@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()
+ completed = datetime.fromtimestamp(current_time + time_remaining)
+ today = datetime.fromtimestamp(current_time)
+
+ # If finishing date is more than 7 days out, using "Mon Dec 3 at HH:MM" format
+ if completed.toordinal() > today.toordinal() + 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 completed.toordinal() > today.toordinal() + 1:
+ return completed.strftime("%a")
+
+ # If finishing tomorrow, use "tomorrow at HH:MM" format
+ elif completed.toordinal() > today.toordinal():
+ return "tomorrow"
+
+ # If finishing today, use "today at HH:MM" format
+ else:
+ return "today"
@pyqtSlot(str)
def sendJobToTop(self, print_job_uuid: str) -> None:
@@ -590,13 +606,45 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
origin_name=change["origin_name"]))
return result
- def _createMaterialOutputModel(self, material_data) -> MaterialOutputModel:
- containers = ContainerRegistry.getInstance().findInstanceContainers(type="material", GUID=material_data["guid"])
- if containers:
- color = containers[0].getMetaDataEntry("color_code")
- brand = containers[0].getMetaDataEntry("brand")
- material_type = containers[0].getMetaDataEntry("material")
- name = containers[0].getName()
+ def _createMaterialOutputModel(self, material_data: Dict[str, Any]) -> "MaterialOutputModel":
+ material_manager = CuraApplication.getInstance().getMaterialManager()
+ 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))
+ 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(
@@ -604,9 +652,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/DiscoverUM3Action.py b/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py
index be83e04585..6ce99e4891 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,30 @@ 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:
+ 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)
+ 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), key)
+ 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 = 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.getConnectionType().value)
+ CuraApplication.getInstance().getMachineManager().replaceContainersMetadata(key = "connection_type", value = previous_connection_type, new_value = printer_device.getConnectionType().value)
else:
- global_container_stack.setMetaDataEntry("um_network_key", key)
+ global_container_stack.setMetaDataEntry("um_network_key", printer_device.key)
+ global_container_stack.setMetaDataEntry("connection_type", printer_device.getConnectionType().value)
if self._network_plugin:
# Ensure that the connection states are refreshed.
diff --git a/plugins/UM3NetworkPrinting/src/LegacyUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/LegacyUM3OutputDevice.py
index e45de2dbb0..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
@@ -498,8 +499,8 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice):
self._authentication_id = None
self.post("auth/request",
- json.dumps({"application": "Cura-" + CuraApplication.getInstance().getVersion(),
- "user": self._getUserName()}).encode(),
+ json.dumps({"application": "Cura-" + CuraApplication.getInstance().getVersion(),
+ "user": self._getUserName()}),
on_finished=self._onRequestAuthenticationFinished)
self.setAuthenticationState(AuthState.AuthenticationRequested)
diff --git a/plugins/UM3NetworkPrinting/src/Models.py b/plugins/UM3NetworkPrinting/src/Models.py
new file mode 100644
index 0000000000..2bcac70766
--- /dev/null
+++ b/plugins/UM3NetworkPrinting/src/Models.py
@@ -0,0 +1,43 @@
+# 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()
+
+ 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:
+ 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..f536fad49a 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
+import urllib.parse
+from typing import Dict, TYPE_CHECKING, Set
-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.MimeTypeDatabase import MimeTypeDatabase
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.
+from cura.CuraApplication import CuraApplication
+# 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")
- try:
- remote_materials_list = json.loads(remote_materials_list)
- 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.")
+ # 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
- 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
+ # 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
- 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
- except KeyError:
- Logger.log("e", "Current material storage on printer was an invalid reply (missing version).")
- return
+ # Send materials to the printer
+ self._sendMaterials(material_ids_to_send)
- for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.MaterialInstanceContainer):
+ ## 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:
+ file_paths = Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.MaterialInstanceContainer)
+
+ # Find all local material files and send them if needed.
+ for file_path in file_paths:
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()))
+ file_name = os.path.basename(file_path)
+ material_id = urllib.parse.unquote_plus(mime_type.stripExtension(file_name))
+ if material_id not in materials_to_send:
+ # If the material does not have to be sent we skip it.
+ continue
- 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)
+ self._sendMaterialFile(file_path, file_name, material_id)
- def sendingFinished(self, reply: QNetworkReply):
+ ## 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}".format(code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)))
- Logger.log("e", reply.readAll().data().decode("utf-8"))
\ No newline at end of file
+ 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) -> Dict[str, ClusterMaterial]:
+ try:
+ 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.")
+ 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.")
+
+ ## 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]
+ container_registry = Application.getInstance().getContainerRegistry()
+ material_containers = container_registry.findContainersMetadata(type = "material")
+
+ # Find the latest version of all material containers in the registry.
+ for material in material_containers:
+ try:
+ # material version must be an int
+ material["version"] = int(material["version"])
+
+ # Create a new local material
+ local_material = LocalMaterial(**material)
+
+ if local_material.GUID not in result or \
+ local_material.version > result.get(local_material.GUID).version:
+ result[local_material.GUID] = local_material
+
+ except KeyError:
+ Logger.logException("w", "Local material {} has missing values.".format(material["id"]))
+ except ValueError:
+ Logger.logException("w", "Local material {} has invalid values.".format(material["id"]))
+ except TypeError:
+ Logger.logException("w", "Local material {} has invalid values.".format(material["id"]))
+
+ return result
diff --git a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py
index 9c070f2de2..80212fcf00 100644
--- a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py
+++ b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py
@@ -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.
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
@@ -283,6 +283,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.getConnectionType().value)
device.connect()
device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged)
@@ -325,13 +326,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 +342,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:
diff --git a/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py
new file mode 100644
index 0000000000..b669eb192a
--- /dev/null
+++ b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py
@@ -0,0 +1,190 @@
+# Copyright (c) 2018 Ultimaker B.V.
+# Copyright (c) 2018 Ultimaker B.V.
+# Cura is released under the terms of the LGPLv3 or higher.
+import io
+import json
+from unittest import TestCase, mock
+from unittest.mock import patch, call
+
+from PyQt5.QtCore import QByteArray
+
+from UM.MimeTypeDatabase import MimeType
+from UM.Application import Application
+from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob
+
+
+@patch("builtins.open", lambda _, __: io.StringIO(""))
+@patch("UM.MimeTypeDatabase.MimeTypeDatabase.getMimeTypeForFile",
+ lambda _: MimeType(name = "application/x-ultimaker-material-profile", comment = "Ultimaker Material Profile",
+ suffixes = ["xml.fdm_material"]))
+@patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: ["/materials/generic_pla_white.xml.fdm_material"])
+@patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice")
+@patch("PyQt5.QtNetwork.QNetworkReply")
+class TestSendMaterialJob(TestCase):
+ _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}
+
+ _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}
+
+ _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, reply_mock):
+ 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, device_mock):
+ 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, device_mock):
+ 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, device_mock):
+ 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, device_mock):
+ 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.Settings.CuraContainerRegistry")
+ @patch("UM.Application")
+ def test__onGetRemoteMaterials_withInvalidVersionInLocalMaterial(self, application_mock, container_registry_mock,
+ reply_mock, device_mock):
+ reply_mock.attribute.return_value = 200
+ reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii"))
+
+ localMaterialWhiteWithInvalidVersion = self._LOCAL_MATERIAL_WHITE.copy()
+ localMaterialWhiteWithInvalidVersion["version"] = "one"
+ container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithInvalidVersion]
+
+ application_mock.getContainerRegistry.return_value = container_registry_mock
+
+ 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("cura.Settings.CuraContainerRegistry")
+ @patch("UM.Application")
+ def test__onGetRemoteMaterials_withNoUpdate(self, application_mock, container_registry_mock, reply_mock,
+ device_mock):
+ application_mock.getContainerRegistry.return_value = container_registry_mock
+
+ device_mock.createFormPart.return_value = "_xXx_"
+
+ container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE]
+
+ 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("cura.Settings.CuraContainerRegistry")
+ @patch("UM.Application")
+ def test__onGetRemoteMaterials_withUpdatedMaterial(self, application_mock, container_registry_mock, reply_mock,
+ device_mock):
+ application_mock.getContainerRegistry.return_value = container_registry_mock
+
+ device_mock.createFormPart.return_value = "_xXx_"
+
+ localMaterialWhiteWithHigherVersion = self._LOCAL_MATERIAL_WHITE.copy()
+ localMaterialWhiteWithHigherVersion["version"] = "2"
+ container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithHigherVersion]
+
+ 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(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("cura.Settings.CuraContainerRegistry")
+ @patch("UM.Application")
+ def test__onGetRemoteMaterials_withNewMaterial(self, application_mock, container_registry_mock, reply_mock,
+ device_mock):
+ application_mock.getContainerRegistry.return_value = container_registry_mock
+
+ device_mock.createFormPart.return_value = "_xXx_"
+
+ container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE,
+ self._LOCAL_MATERIAL_BLACK]
+
+ 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/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 8213f195d5..5fd757f843 100644
--- a/plugins/VersionUpgrade/VersionUpgrade33to34/__init__.py
+++ b/plugins/VersionUpgrade/VersionUpgrade33to34/__init__.py
@@ -1,16 +1,22 @@
# 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
("definition_changes", 3000004): ("definition_changes", 4000004, upgrade.upgradeInstanceContainer),
("quality_changes", 3000004): ("quality_changes", 4000004, upgrade.upgradeInstanceContainer),
+ ("quality", 3000004): ("quality", 4000004, upgrade.upgradeInstanceContainer),
("user", 3000004): ("user", 4000004, upgrade.upgradeInstanceContainer),
},
"sources": {
@@ -22,6 +28,10 @@ def getMetaData():
"get_version": upgrade.getCfgVersion,
"location": {"./quality_changes"}
},
+ "quality": {
+ "get_version": upgrade.getCfgVersion,
+ "location": {"./quality"}
+ },
"user": {
"get_version": upgrade.getCfgVersion,
"location": {"./user"}
@@ -30,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 de0fdccb7d..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
@@ -13,6 +18,7 @@ def getMetaData():
("definition_changes", 4000004): ("definition_changes", 4000005, upgrade.upgradeInstanceContainer),
("quality_changes", 4000004): ("quality_changes", 4000005, upgrade.upgradeInstanceContainer),
+ ("quality", 4000004): ("quality", 4000005, upgrade.upgradeInstanceContainer),
("user", 4000004): ("user", 4000005, upgrade.upgradeInstanceContainer),
("machine_stack", 4000004): ("machine_stack", 4000005, upgrade.upgradeStack),
@@ -39,6 +45,10 @@ def getMetaData():
"get_version": upgrade.getCfgVersion,
"location": {"./quality_changes"}
},
+ "quality": {
+ "get_version": upgrade.getCfgVersion,
+ "location": {"./quality"}
+ },
"user": {
"get_version": upgrade.getCfgVersion,
"location": {"./user"}
@@ -47,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/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/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 8ec0c3d29d..99b8cd35a0 100644
--- a/resources/bundled_packages/cura.json
+++ b/resources/bundled_packages/cura.json
@@ -5,11 +5,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -22,11 +22,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -39,11 +39,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -56,11 +56,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -73,11 +73,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -90,11 +90,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -107,11 +107,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -124,11 +124,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -141,11 +141,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -158,11 +158,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -175,11 +175,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -192,8 +192,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,11 +209,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -226,11 +226,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -243,11 +243,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -260,8 +260,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,11 +277,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -294,11 +294,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -311,11 +311,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -328,11 +328,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -345,11 +345,28 @@
"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": "Ultimaker",
+ "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",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -362,11 +379,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -379,11 +396,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -396,11 +413,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -413,11 +430,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -430,11 +447,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -447,11 +464,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -464,11 +481,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -481,11 +498,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -498,11 +515,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -515,11 +532,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -532,11 +549,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -549,11 +566,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -566,11 +583,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -583,11 +600,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -600,11 +617,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -617,11 +634,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -634,11 +651,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -651,11 +668,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -668,11 +685,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -685,11 +702,11 @@
"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.0",
- "sdk_version": 5,
+ "package_version": "1.0.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -702,8 +719,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,11 +736,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -736,11 +753,11 @@
"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": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "plugins@ultimaker.com",
"website": "https://ultimaker.com"
@@ -753,8 +770,8 @@
"package_type": "material",
"display_name": "Generic ABS",
"description": "The generic ABS profile which other profiles can be based upon.",
- "package_version": "1.1.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 +788,8 @@
"package_type": "material",
"display_name": "Generic BAM",
"description": "The generic BAM profile which other profiles can be based upon.",
- "package_version": "1.1.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 +806,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.0.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 +824,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.0.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 +842,8 @@
"package_type": "material",
"display_name": "Generic CPE",
"description": "The generic CPE profile which other profiles can be based upon.",
- "package_version": "1.1.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 +860,8 @@
"package_type": "material",
"display_name": "Generic CPE+",
"description": "The generic CPE+ profile which other profiles can be based upon.",
- "package_version": "1.1.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 +878,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.0.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 +896,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.0.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 +914,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 +932,8 @@
"package_type": "material",
"display_name": "Generic Nylon",
"description": "The generic Nylon profile which other profiles can be based upon.",
- "package_version": "1.1.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 +950,8 @@
"package_type": "material",
"display_name": "Generic PC",
"description": "The generic PC profile which other profiles can be based upon.",
- "package_version": "1.1.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 +968,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 +986,8 @@
"package_type": "material",
"display_name": "Generic PLA",
"description": "The generic PLA profile which other profiles can be based upon.",
- "package_version": "1.1.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 +1004,8 @@
"package_type": "material",
"display_name": "Generic PP",
"description": "The generic PP profile which other profiles can be based upon.",
- "package_version": "1.1.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 +1022,8 @@
"package_type": "material",
"display_name": "Generic PVA",
"description": "The generic PVA profile which other profiles can be based upon.",
- "package_version": "1.1.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 +1040,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 +1058,8 @@
"package_type": "material",
"display_name": "Generic TPU",
"description": "The generic TPU profile which other profiles can be based upon.",
- "package_version": "1.1.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 +1076,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 +1093,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 +1110,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 +1127,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 +1144,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 +1161,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 +1178,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 +1195,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 +1212,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 +1229,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 +1246,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 +1263,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 +1280,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 +1297,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,11 +1314,11 @@
"package_type": "material",
"display_name": "Ultimaker ABS",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1316,11 +1333,11 @@
"package_type": "material",
"display_name": "Ultimaker Breakaway",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/breakaway",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1335,11 +1352,11 @@
"package_type": "material",
"display_name": "Ultimaker CPE",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1354,11 +1371,11 @@
"package_type": "material",
"display_name": "Ultimaker CPE+",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/cpe",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1373,11 +1390,11 @@
"package_type": "material",
"display_name": "Ultimaker Nylon",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1392,11 +1409,11 @@
"package_type": "material",
"display_name": "Ultimaker PC",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.2",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/pc",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1411,11 +1428,11 @@
"package_type": "material",
"display_name": "Ultimaker PLA",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1430,11 +1447,11 @@
"package_type": "material",
"display_name": "Ultimaker PP",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/pp",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1449,11 +1466,11 @@
"package_type": "material",
"display_name": "Ultimaker PVA",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/abs",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1468,11 +1485,11 @@
"package_type": "material",
"display_name": "Ultimaker TPU 95A",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.1.0",
- "sdk_version": 5,
+ "package_version": "1.2.1",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/tpu-95a",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1487,11 +1504,11 @@
"package_type": "material",
"display_name": "Ultimaker Tough PLA",
"description": "Example package for material and quality profiles for Ultimaker materials.",
- "package_version": "1.0.0",
- "sdk_version": 5,
+ "package_version": "1.0.3",
+ "sdk_version": "6.0",
"website": "https://ultimaker.com/products/materials/tough-pla",
"author": {
- "author_id": "Ultimaker",
+ "author_id": "UltimakerPackages",
"display_name": "Ultimaker B.V.",
"email": "materials@ultimaker.com",
"website": "https://ultimaker.com",
@@ -1506,8 +1523,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 +1540,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 +1557,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 +1574,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",
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 bc6e8a40f4..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":
{
@@ -4139,6 +4139,20 @@
"limit_to_extruder": "support_infill_extruder_nr",
"settable_per_mesh": false
},
+ "minimum_support_area":
+ {
+ "label": "Minimum Support Area",
+ "description": "Minimum area size for support polygons. Polygons which have an area smaller than this value will not be generated.",
+ "unit": "mm²",
+ "type": "float",
+ "default_value": 0.0,
+ "minimum_value": "0",
+ "enabled": "support_enable",
+ "limit_to_extruder": "support_infill_extruder_nr",
+ "settable_per_mesh": true,
+ "fabricate_enabled": true,
+ "intermediate_enabled": true
+ },
"support_interface_enable":
{
"label": "Enable Support Interface",
@@ -4378,6 +4392,94 @@
}
}
},
+ "minimum_interface_area":
+ {
+ "label": "Minimum Support Interface Area",
+ "description": "Minimum area size for support interface polygons. Polygons which have an area smaller than this value will not be generated.",
+ "unit": "mm²",
+ "type": "float",
+ "default_value": 1.0,
+ "minimum_value": "0",
+ "minimum_value_warning": "minimum_support_area",
+ "limit_to_extruder": "support_interface_extruder_nr",
+ "enabled": "support_interface_enable and support_enable",
+ "settable_per_mesh": true,
+ "children":
+ {
+ "minimum_roof_area":
+ {
+ "label": "Minimum Support Roof Area",
+ "description": "Minimum area size for the roofs of the support. Polygons which have an area smaller than this value will not be generated.",
+ "unit": "mm²",
+ "type": "float",
+ "default_value": 1.0,
+ "value": "extruderValue(support_roof_extruder_nr, 'minimum_interface_area')",
+ "minimum_value": "0",
+ "minimum_value_warning": "minimum_support_area",
+ "limit_to_extruder": "support_roof_extruder_nr",
+ "enabled": "support_roof_enable and support_enable",
+ "settable_per_mesh": true
+ },
+ "minimum_bottom_area":
+ {
+ "label": "Minimum Support Floor Area",
+ "description": "Minimum area size for the floors of the support. Polygons which have an area smaller than this value will not be generated.",
+ "unit": "mm²",
+ "type": "float",
+ "default_value": 1.0,
+ "value": "extruderValue(support_bottom_extruder_nr, 'minimum_interface_area')",
+ "minimum_value": "0",
+ "minimum_value_warning": "minimum_support_area",
+ "limit_to_extruder": "support_bottom_extruder_nr",
+ "enabled": "support_bottom_enable and support_enable",
+ "settable_per_mesh": true
+ }
+ }
+ },
+ "support_interface_offset":
+ {
+ "label": "Support Interface Horizontal Expansion",
+ "description": "Amount of offset applied to the support interface polygons.",
+ "unit": "mm",
+ "type": "float",
+ "default_value": 0.0,
+ "maximum_value": "extruderValue(support_extruder_nr, 'support_offset')",
+ "limit_to_extruder": "support_interface_extruder_nr",
+ "enabled": "support_interface_enable and (support_enable or support_tree_enable)",
+ "settable_per_mesh": false,
+ "settable_per_extruder": true,
+ "children":
+ {
+ "support_roof_offset":
+ {
+ "label": "Support Roof Horizontal Expansion",
+ "description": "Amount of offset applied to the roofs of the support.",
+ "unit": "mm",
+ "type": "float",
+ "default_value": 0.0,
+ "value": "extruderValue(support_roof_extruder_nr, 'support_interface_offset')",
+ "maximum_value": "extruderValue(support_extruder_nr, 'support_offset')",
+ "limit_to_extruder": "support_roof_extruder_nr",
+ "enabled": "support_roof_enable and (support_enable or support_tree_enable)",
+ "settable_per_mesh": false,
+ "settable_per_extruder": true
+ },
+ "support_bottom_offset":
+ {
+ "label": "Support Floor Horizontal Expansion",
+ "description": "Amount of offset applied to the floors of the support.",
+ "unit": "mm",
+ "type": "float",
+ "default_value": 0.0,
+ "value": "extruderValue(support_bottom_extruder_nr, 'support_interface_offset')",
+ "maximum_value": "extruderValue(support_extruder_nr, 'support_offset')",
+ "limit_to_extruder": "support_bottom_extruder_nr",
+ "enabled": "support_bottom_enable and (support_enable or support_tree_enable)",
+ "settable_per_mesh": false,
+ "settable_per_extruder": true
+ }
+ }
+ },
"support_fan_enable":
{
"label": "Fan Speed Override",
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/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/i18n/de_DE/cura.po b/resources/i18n/de_DE/cura.po
index 85a4a129ac..3433edc5bd 100644
--- a/resources/i18n/de_DE/cura.po
+++ b/resources/i18n/de_DE/cura.po
@@ -49,7 +49,7 @@ msgstr "GCodeWriter unterstützt keinen Nicht-Textmodus."
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "Vor dem Exportieren bitte G-Code vorbereiten."
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -64,11 +64,7 @@ msgid ""
"
{model_names}
\n"
"
Find out how to ensure the best possible print quality and reliability.
"
#: /home/ruben/Projects/Cura/plugins/ChangeLogPlugin/ChangeLog.py:32
msgctxt "@item:inmenu"
@@ -78,7 +74,7 @@ msgstr "Änderungsprotokoll anzeigen"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "Firmware aktualisieren"
#: /home/ruben/Projects/Cura/plugins/ProfileFlattener/ProfileFlattener.py:23
msgctxt "@item:inmenu"
@@ -822,7 +818,7 @@ msgstr "Vorgeschnittene Datei {0}"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "Login fehlgeschlagen"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -896,32 +892,32 @@ msgstr "Import des Profils aus Datei {0} fehlgeschlagen: !"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "Kein benutzerdefiniertes Profil für das Importieren in Datei {0}"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Import des Profils aus Datei {0} fehlgeschlagen:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "Dieses Profil {0} enthält falsche Daten, Importieren nicht möglich."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "Die Maschine, die im Profil {0} ({1}) definiert wurde, entspricht nicht Ihrer derzeitigen Maschine ({2}). Importieren nicht möglich."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Import des Profils aus Datei {0} fehlgeschlagen:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1073,12 +1069,7 @@ msgid ""
"
Backups can be found in the configuration folder.
\n"
"
Please send us this Crash Report to fix the problem.
\n"
" "
-msgstr ""
-"
Hoppla, bei Ultimaker Cura ist ein Problem aufgetreten.
\n"
-"
Beim Start ist ein nicht behebbarer Fehler aufgetreten. Er wurde möglicherweise durch einige falsche Konfigurationsdateien verursacht. Wir empfehlen ein Backup und Reset Ihrer Konfiguration.
\n"
-"
Backups sind im Konfigurationsordner abgelegt.
\n"
-"
Senden Sie uns diesen Absturzbericht bitte, um das Problem zu beheben.
\n"
-" "
+msgstr "
Hoppla, bei Ultimaker Cura ist ein Problem aufgetreten.
\n
Beim Start ist ein nicht behebbarer Fehler aufgetreten. Er wurde möglicherweise durch einige falsche Konfigurationsdateien verursacht. Wir empfehlen ein Backup und Reset Ihrer Konfiguration.
\n
Backups sind im Konfigurationsordner abgelegt.
\n
Senden Sie uns diesen Absturzbericht bitte, um das Problem zu beheben.
A fatal error has occurred in Cura. Please send us this Crash Report to fix the problem
\n"
"
Please use the \"Send report\" button to post a bug report automatically to our servers
\n"
" "
-msgstr ""
-"
Ein schwerer Fehler ist in Cura aufgetreten. Senden Sie uns diesen Absturzbericht, um das Problem zu beheben
\n"
-"
Verwenden Sie bitte die Schaltfläche „Bericht senden“, um den Fehlerbericht automatisch an unsere Server zu senden
\n"
-" "
+msgstr "
Ein schwerer Fehler ist in Cura aufgetreten. Senden Sie uns diesen Absturzbericht, um das Problem zu beheben
\n
Verwenden Sie bitte die Schaltfläche „Bericht senden“, um den Fehlerbericht automatisch an unsere Server zu senden
\n "
#: /home/ruben/Projects/Cura/cura/CrashHandler.py:177
msgctxt "@title:groupbox"
@@ -1408,7 +1396,7 @@ msgstr "Y-Versatz Düse"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:451
msgctxt "@label"
msgid "Cooling Fan Number"
-msgstr ""
+msgstr "Kühllüfter-Nr."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:452
msgctxt "@label"
@@ -1512,7 +1500,7 @@ msgstr "Zurück"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:20
msgctxt "@title:window"
msgid "Confirm uninstall"
-msgstr ""
+msgstr "Deinstallieren bestätigen"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:50
msgctxt "@text:window"
@@ -1590,10 +1578,7 @@ msgid ""
"This plugin contains a license.\n"
"You need to accept this license to install this plugin.\n"
"Do you agree with the terms below?"
-msgstr ""
-"Dieses Plugin enthält eine Lizenz.\n"
-"Sie müssen diese Lizenz akzeptieren, um das Plugin zu installieren.\n"
-"Stimmen Sie den nachfolgenden Bedingungen zu?"
+msgstr "Dieses Plugin enthält eine Lizenz.\nSie müssen diese Lizenz akzeptieren, um das Plugin zu installieren.\nStimmen Sie den nachfolgenden Bedingungen zu?"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml:54
msgctxt "@action:button"
@@ -1655,7 +1640,7 @@ msgstr "Schließen"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:31
msgctxt "@title"
msgid "Update Firmware"
-msgstr ""
+msgstr "Firmware aktualisieren"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:39
msgctxt "@label"
@@ -1680,12 +1665,12 @@ msgstr "Benutzerdefinierte Firmware hochladen"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:83
msgctxt "@label"
msgid "Firmware can not be updated because there is no connection with the printer."
-msgstr ""
+msgstr "Firmware kann nicht aktualisiert werden, da keine Verbindung zum Drucker besteht."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:91
msgctxt "@label"
msgid "Firmware can not be updated because the connection with the printer does not support upgrading firmware."
-msgstr ""
+msgstr "Firmware kann nicht aktualisiert werden, da die Verbindung zum Drucker die Firmware-Aktualisierung nicht unterstützt."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:98
msgctxt "@title:window"
@@ -1753,10 +1738,7 @@ msgid ""
"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"
"\n"
"Select your printer from the list below:"
-msgstr ""
-"Um über das Netzwerk direkt auf Ihrem Drucker zu drucken, stellen Sie bitte sicher, dass der Drucker mit dem Netzwerkkabel verbunden ist oder verbinden Sie Ihren Drucker mit Ihrem WLAN-Netzwerk. Wenn Sie Cura nicht mit Ihrem Drucker verbinden, können Sie dennoch ein USB-Laufwerk für die Übertragung von G-Code-Dateien auf Ihren Drucker verwenden.\n"
-"\n"
-"Wählen Sie Ihren Drucker aus der folgenden Liste:"
+msgstr "Um über das Netzwerk direkt auf Ihrem Drucker zu drucken, stellen Sie bitte sicher, dass der Drucker mit dem Netzwerkkabel verbunden ist oder verbinden Sie Ihren Drucker mit Ihrem WLAN-Netzwerk. Wenn Sie Cura nicht mit Ihrem Drucker verbinden, können Sie dennoch ein USB-Laufwerk für die Übertragung von G-Code-Dateien auf Ihren Drucker verwenden.\n\nWählen Sie Ihren Drucker aus der folgenden Liste:"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml:85
#: /home/ruben/Projects/Cura/resources/qml/Preferences/MachinesPage.qml:42
@@ -1920,62 +1902,62 @@ msgstr "Warten auf: "
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:299
msgctxt "@label"
msgid "Configuration change"
-msgstr ""
+msgstr "Konfigurationsänderung"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:365
msgctxt "@label"
msgid "The assigned printer, %1, requires the following configuration change(s):"
-msgstr ""
+msgstr "Der zugewiesene Drucker %1 erfordert die folgende(n) Konfigurationsänderung(en):"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:367
msgctxt "@label"
msgid "The printer %1 is assigned, but the job contains an unknown material configuration."
-msgstr ""
+msgstr "Der Drucker %1 wurde zugewiesen, allerdings enthält der Auftrag eine unbekannte Materialkonfiguration."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:375
msgctxt "@label"
msgid "Change material %1 from %2 to %3."
-msgstr ""
+msgstr "Material %1 von %2 auf %3 wechseln."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:378
msgctxt "@label"
msgid "Load %3 as material %1 (This cannot be overridden)."
-msgstr ""
+msgstr "%3 als Material %1 laden (Dies kann nicht übergangen werden)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:381
msgctxt "@label"
msgid "Change print core %1 from %2 to %3."
-msgstr ""
+msgstr "Print Core %1 von %2 auf %3 wechseln."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:384
msgctxt "@label"
msgid "Change build plate to %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Druckplatte auf %1 wechseln (Dies kann nicht übergangen werden)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:404
msgctxt "@label"
msgid "Override"
-msgstr ""
+msgstr "Überschreiben"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:432
msgctxt "@label"
msgid "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?"
-msgstr ""
+msgstr "Das Starten eines Druckauftrags mit einer inkompatiblen Konfiguration kann Ihren 3D-Drucker beschädigen. Möchten Sie die Konfiguration wirklich überschreiben und %1 drucken?"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:435
msgctxt "@window:title"
msgid "Override configuration configuration and start print"
-msgstr ""
+msgstr "Konfiguration überschreiben und Druck starten"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:466
msgctxt "@label"
msgid "Glass"
-msgstr ""
+msgstr "Glas"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:469
msgctxt "@label"
msgid "Aluminum"
-msgstr ""
+msgstr "Aluminium"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml:39
msgctxt "@label link to connect manager"
@@ -2664,9 +2646,7 @@ msgctxt "@text:window"
msgid ""
"You have customized some profile settings.\n"
"Would you like to keep or discard those settings?"
-msgstr ""
-"Sie haben einige Profileinstellungen angepasst.\n"
-"Möchten Sie diese Einstellungen übernehmen oder verwerfen?"
+msgstr "Sie haben einige Profileinstellungen angepasst.\nMöchten Sie diese Einstellungen übernehmen oder verwerfen?"
#: /home/ruben/Projects/Cura/resources/qml/DiscardOrKeepProfileChangesDialog.qml:110
msgctxt "@title:column"
@@ -3368,9 +3348,7 @@ msgctxt "@info:credit"
msgid ""
"Cura is developed by Ultimaker B.V. in cooperation with the community.\n"
"Cura proudly uses the following open source projects:"
-msgstr ""
-"Cura wurde von Ultimaker B.V. in Zusammenarbeit mit der Community entwickelt.\n"
-"Cura verwendet mit Stolz die folgenden Open Source-Projekte:"
+msgstr "Cura wurde von Ultimaker B.V. in Zusammenarbeit mit der Community entwickelt.\nCura verwendet mit Stolz die folgenden Open Source-Projekte:"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:132
msgctxt "@label"
@@ -3435,17 +3413,17 @@ msgstr "Support-Bibliothek für die Handhabung von STL-Dateien"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:145
msgctxt "@label"
msgid "Support library for handling planar objects"
-msgstr ""
+msgstr "Support-Bibliothek für die Handhabung von ebenen Objekten"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:146
msgctxt "@label"
msgid "Support library for handling triangular meshes"
-msgstr ""
+msgstr "Support-Bibliothek für die Handhabung von dreieckigen Netzen"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:147
msgctxt "@label"
msgid "Support library for analysis of complex networks"
-msgstr ""
+msgstr "Support-Bibliothek für die Analyse von komplexen Netzwerken"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:148
msgctxt "@label"
@@ -3455,7 +3433,7 @@ msgstr "Support-Bibliothek für die Handhabung von 3MF-Dateien"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:149
msgctxt "@label"
msgid "Support library for file metadata and streaming"
-msgstr ""
+msgstr "Support-Bibliothek für Datei-Metadaten und Streaming"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:150
msgctxt "@label"
@@ -3503,10 +3481,7 @@ msgid ""
"Some setting/override values are different from the values stored in the profile.\n"
"\n"
"Click to open the profile manager."
-msgstr ""
-"Einige Einstellungs-/Überschreibungswerte unterscheiden sich von den im Profil gespeicherten Werten.\n"
-"\n"
-"Klicken Sie, um den Profilmanager zu öffnen."
+msgstr "Einige Einstellungs-/Überschreibungswerte unterscheiden sich von den im Profil gespeicherten Werten.\n\nKlicken Sie, um den Profilmanager zu öffnen."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingView.qml:200
msgctxt "@label:textbox"
@@ -3560,10 +3535,7 @@ msgid ""
"Some hidden settings use values different from their normal calculated value.\n"
"\n"
"Click to make these settings visible."
-msgstr ""
-"Einige ausgeblendete Einstellungen verwenden Werte, die von ihren normalen, berechneten Werten abweichen.\n"
-"\n"
-"Klicken Sie, um diese Einstellungen sichtbar zu machen."
+msgstr "Einige ausgeblendete Einstellungen verwenden Werte, die von ihren normalen, berechneten Werten abweichen.\n\nKlicken Sie, um diese Einstellungen sichtbar zu machen."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:61
msgctxt "@label Header for list of settings."
@@ -3591,10 +3563,7 @@ msgid ""
"This setting has a value that is different from the profile.\n"
"\n"
"Click to restore the value of the profile."
-msgstr ""
-"Diese Einstellung hat einen vom Profil abweichenden Wert.\n"
-"\n"
-"Klicken Sie, um den Wert des Profils wiederherzustellen."
+msgstr "Diese Einstellung hat einen vom Profil abweichenden Wert.\n\nKlicken Sie, um den Wert des Profils wiederherzustellen."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:281
msgctxt "@label"
@@ -3602,10 +3571,7 @@ msgid ""
"This setting is normally calculated, but it currently has an absolute value set.\n"
"\n"
"Click to restore the calculated value."
-msgstr ""
-"Diese Einstellung wird normalerweise berechnet; aktuell ist jedoch ein Absolutwert eingestellt.\n"
-"\n"
-"Klicken Sie, um den berechneten Wert wiederherzustellen."
+msgstr "Diese Einstellung wird normalerweise berechnet; aktuell ist jedoch ein Absolutwert eingestellt.\n\nKlicken Sie, um den berechneten Wert wiederherzustellen."
#: /home/ruben/Projects/Cura/resources/qml/PrinterOutput/ManualPrinterControl.qml:129
msgctxt "@label"
@@ -3830,9 +3796,7 @@ msgctxt "@label:listbox"
msgid ""
"Print Setup disabled\n"
"G-code files cannot be modified"
-msgstr ""
-"Druckeinrichtung deaktiviert\n"
-"G-Code-Dateien können nicht geändert werden"
+msgstr "Druckeinrichtung deaktiviert\nG-Code-Dateien können nicht geändert werden"
#: /home/ruben/Projects/Cura/resources/qml/PrepareSidebar.qml:340
msgctxt "@label Hours and minutes"
@@ -4606,12 +4570,12 @@ msgstr "Änderungsprotokoll"
#: FirmwareUpdater/plugin.json
msgctxt "description"
msgid "Provides a machine actions for updating firmware."
-msgstr ""
+msgstr "Ermöglicht Gerätemaßnahmen für die Aktualisierung der Firmware."
#: FirmwareUpdater/plugin.json
msgctxt "name"
msgid "Firmware Updater"
-msgstr ""
+msgstr "Firmware-Aktualisierungsfunktion"
#: ProfileFlattener/plugin.json
msgctxt "description"
diff --git a/resources/i18n/de_DE/fdmextruder.def.json.po b/resources/i18n/de_DE/fdmextruder.def.json.po
index 9d146a1a63..77ffa5631d 100644
--- a/resources/i18n/de_DE/fdmextruder.def.json.po
+++ b/resources/i18n/de_DE/fdmextruder.def.json.po
@@ -169,12 +169,12 @@ msgstr "Die Z-Koordinate der Position, an der die Düse am Druckbeginn einzieht.
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number label"
msgid "Extruder Print Cooling Fan"
-msgstr ""
+msgstr "Drucklüfter Extruder"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number description"
msgid "The number of the print cooling fan associated with this extruder. Only change this from the default value of 0 when you have a different print cooling fan for each extruder."
-msgstr ""
+msgstr "Die Anzahl der Drucklüfter für diesen Extruder. Nur vom Standardwert 0 ändern, wenn Sie für jeden Extruder einen anderen Drucklüfter verwenden."
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
diff --git a/resources/i18n/de_DE/fdmprinter.def.json.po b/resources/i18n/de_DE/fdmprinter.def.json.po
index 0bcf015c21..383a7a3886 100644
--- a/resources/i18n/de_DE/fdmprinter.def.json.po
+++ b/resources/i18n/de_DE/fdmprinter.def.json.po
@@ -57,9 +57,7 @@ msgctxt "machine_start_gcode description"
msgid ""
"G-code commands to be executed at the very start - separated by \n"
"."
-msgstr ""
-"G-Code-Befehle, die zu Beginn ausgeführt werden sollen – getrennt durch \n"
-"."
+msgstr "G-Code-Befehle, die zu Beginn ausgeführt werden sollen – getrennt durch \n."
#: fdmprinter.def.json
msgctxt "machine_end_gcode label"
@@ -71,9 +69,7 @@ msgctxt "machine_end_gcode description"
msgid ""
"G-code commands to be executed at the very end - separated by \n"
"."
-msgstr ""
-"G-Code-Befehle, die am Ende ausgeführt werden sollen – getrennt durch \n"
-"."
+msgstr "G-Code-Befehle, die am Ende ausgeführt werden sollen – getrennt durch \n."
#: fdmprinter.def.json
msgctxt "material_guid label"
@@ -1078,7 +1074,7 @@ msgstr "Polygone oben/unten verbinden"
#: fdmprinter.def.json
msgctxt "connect_skin_polygons description"
msgid "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happen midway over infill this feature can reduce the top surface quality."
-msgstr ""
+msgstr "Außenhaut-Pfade oben/unten verbinden, wenn sie nebeneinander laufen. Bei konzentrischen Mustern reduziert die Aktivierung dieser Einstellung die Durchlaufzeit erheblich. Da die Verbindungen jedoch auf halbem Weg über der Füllung erfolgen können, kann diese Funktion die Oberflächenqualität reduzieren."
#: fdmprinter.def.json
msgctxt "skin_angles label"
@@ -1498,7 +1494,7 @@ msgstr "Füllmuster"
#: fdmprinter.def.json
msgctxt "infill_pattern description"
msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
-msgstr ""
+msgstr "Das Muster des Füllmaterials des Drucks. Die Linien- und Zickzackfüllmethode wechseln nach jeder Schicht die Richtung, um Materialkosten zu reduzieren. Die Gitter-, Dreieck- Tri-Hexagon-, Würfel-, Octahedral-, Viertelwürfel-, Quer- und konzentrischen Muster werden in jeder Schicht vollständig gedruckt. Gyroid-, Würfel-, Viertelwürfel- und Octahedral-Füllungen wechseln mit jeder Schicht, um eine gleichmäßigere Verteilung der Stärke in allen Richtungen zu erzielen."
#: fdmprinter.def.json
msgctxt "infill_pattern option grid"
@@ -1563,7 +1559,7 @@ msgstr "3D-Quer"
#: fdmprinter.def.json
msgctxt "infill_pattern option gyroid"
msgid "Gyroid"
-msgstr ""
+msgstr "Gyroid"
#: fdmprinter.def.json
msgctxt "zig_zaggify_infill label"
@@ -1635,9 +1631,7 @@ msgctxt "infill_wall_line_count description"
msgid ""
"Add extra walls around the infill area. Such walls can make top/bottom skin lines sag down less which means you need less top/bottom skin layers for the same quality at the cost of some extra material.\n"
"This feature can combine with the Connect Infill Polygons to connect all the infill into a single extrusion path without the need for travels or retractions if configured right."
-msgstr ""
-"Fügen Sie zusätzliche Wände um den Füllbereich hinzu. Derartige Wände können zu einem verringerten Absacken der oberen/unteren Außenhautlinien beitragen, was bedeutet, dass Sie weniger Außenhautschichten oben/unten bei derselben Qualität von Kosten für zusätzliches Material benötigen.\n"
-" Diese Funktion ist verknüpfbar mit „Füllungspolygone verbinden“, um alle Füllungen mit einem einzigen Extrusionspfad zu verbinden, ohne dass hierzu Vorwärtsbewegungen oder Rückzüge erforderlich sind, sofern die richtige Konfiguration gewählt wurde."
+msgstr "Fügen Sie zusätzliche Wände um den Füllbereich hinzu. Derartige Wände können zu einem verringerten Absacken der oberen/unteren Außenhautlinien beitragen, was bedeutet, dass Sie weniger Außenhautschichten oben/unten bei derselben Qualität von Kosten für zusätzliches Material benötigen.\n Diese Funktion ist verknüpfbar mit „Füllungspolygone verbinden“, um alle Füllungen mit einem einzigen Extrusionspfad zu verbinden, ohne dass hierzu Vorwärtsbewegungen oder Rückzüge erforderlich sind, sofern die richtige Konfiguration gewählt wurde."
#: fdmprinter.def.json
msgctxt "sub_div_rad_add label"
@@ -3272,32 +3266,32 @@ msgstr "Ausrichtung des Füllmusters für Unterstützung. Das Füllmuster für U
#: fdmprinter.def.json
msgctxt "support_brim_enable label"
msgid "Enable Support Brim"
-msgstr ""
+msgstr "Stütz-Brim aktivieren"
#: fdmprinter.def.json
msgctxt "support_brim_enable description"
msgid "Generate a brim within the support infill regions of the first layer. This brim is printed underneath the support, not around it. Enabling this setting increases the adhesion of support to the build plate."
-msgstr ""
+msgstr "Erstellen Sie ein Brim in den Stützstruktur-Füllungsbereichen der ersten Schicht. Das Brim wird unterhalb der Stützstruktur und nicht drumherum gedruckt. Die Aktivierung dieser Einstellung erhöht die Haftung der Stützstruktur am Druckbett."
#: fdmprinter.def.json
msgctxt "support_brim_width label"
msgid "Support Brim Width"
-msgstr ""
+msgstr "Breite der Brim-Stützstruktur"
#: fdmprinter.def.json
msgctxt "support_brim_width description"
msgid "The width of the brim to print underneath the support. A larger brim enhances adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Die Breite des unter der Stützstruktur zu druckenden Brims. Ein größeres Brim erhöht die Haftung am Druckbett, jedoch erhöht sich hierdurch der Materialverbrauch."
#: fdmprinter.def.json
msgctxt "support_brim_line_count label"
msgid "Support Brim Line Count"
-msgstr ""
+msgstr "Anzahl der Brim-Stützstrukturlinien"
#: fdmprinter.def.json
msgctxt "support_brim_line_count description"
msgid "The number of lines used for the support brim. More brim lines enhance adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Die Anzahl der Linien für die Brim-Stützstruktur. Eine größere Anzahl von Brim-Linien verbessert die Haftung am Druckbett, jedoch erhöht sich hierdurch der Materialverbrauch."
#: fdmprinter.def.json
msgctxt "support_z_distance label"
@@ -3834,9 +3828,7 @@ msgctxt "skirt_gap description"
msgid ""
"The horizontal distance between the skirt and the first layer of the print.\n"
"This is the minimum distance. Multiple skirt lines will extend outwards from this distance."
-msgstr ""
-"Der horizontale Abstand zwischen dem Skirt und der ersten Schicht des Drucks.\n"
-"Es handelt sich dabei um den Mindestabstand. Ab diesem Abstand werden mehrere Skirt-Linien in äußerer Richtung angebracht."
+msgstr "Der horizontale Abstand zwischen dem Skirt und der ersten Schicht des Drucks.\nEs handelt sich dabei um den Mindestabstand. Ab diesem Abstand werden mehrere Skirt-Linien in äußerer Richtung angebracht."
#: fdmprinter.def.json
msgctxt "skirt_brim_minimal_length label"
@@ -3871,12 +3863,12 @@ msgstr "Die Anzahl der Linien für das Brim-Element. Eine größere Anzahl von B
#: fdmprinter.def.json
msgctxt "brim_replaces_support label"
msgid "Brim Replaces Support"
-msgstr ""
+msgstr "Brim ersetzt die Stützstruktur"
#: fdmprinter.def.json
msgctxt "brim_replaces_support description"
msgid "Enforce brim to be printed around the model even if that space would otherwise be occupied by support. This replaces some regions of the first layer of support by brim regions."
-msgstr ""
+msgstr "Erzwingen Sie den Druck des Brims um das Modell herum, auch wenn dieser Raum sonst durch die Stützstruktur belegt würde. Dies ersetzt einige der ersten Schichten der Stützstruktur durch Brim-Bereiche."
#: fdmprinter.def.json
msgctxt "brim_outside_only label"
@@ -5283,9 +5275,7 @@ msgctxt "wireframe_up_half_speed description"
msgid ""
"Distance of an upward move which is extruded with half speed.\n"
"This can cause better adhesion to previous layers, while not heating the material in those layers too much. Only applies to Wire Printing."
-msgstr ""
-"Die Strecke einer Aufwärtsbewegung, die mit halber Geschwindigkeit extrudiert wird.\n"
-"Dies kann zu einer besseren Haftung an vorhergehenden Schichten führen, während gleichzeitig ein Überhitzen des Materials in diesen Schichten vermieden wird. Dies gilt nur für das Drucken mit Drahtstruktur."
+msgstr "Die Strecke einer Aufwärtsbewegung, die mit halber Geschwindigkeit extrudiert wird.\nDies kann zu einer besseren Haftung an vorhergehenden Schichten führen, während gleichzeitig ein Überhitzen des Materials in diesen Schichten vermieden wird. Dies gilt nur für das Drucken mit Drahtstruktur."
#: fdmprinter.def.json
msgctxt "wireframe_top_jump label"
diff --git a/resources/i18n/es_ES/cura.po b/resources/i18n/es_ES/cura.po
index 71c133daa9..e6b5867e39 100644
--- a/resources/i18n/es_ES/cura.po
+++ b/resources/i18n/es_ES/cura.po
@@ -49,7 +49,7 @@ msgstr "GCodeWriter no es compatible con el modo sin texto."
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "Prepare el Gcode antes de la exportación."
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -64,11 +64,7 @@ msgid ""
"
{model_names}
\n"
"
Find out how to ensure the best possible print quality and reliability.
"
#: /home/ruben/Projects/Cura/plugins/ChangeLogPlugin/ChangeLog.py:32
msgctxt "@item:inmenu"
@@ -78,7 +74,7 @@ msgstr "Mostrar registro de cambios"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "Actualizar firmware"
#: /home/ruben/Projects/Cura/plugins/ProfileFlattener/ProfileFlattener.py:23
msgctxt "@item:inmenu"
@@ -822,7 +818,7 @@ msgstr "Archivo {0} presegmentado"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "Fallo de inicio de sesión"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -896,32 +892,32 @@ msgstr "Error al importar el perfil de {0}: {1}!"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "No hay ningún perfil personalizado para importar en el archivo {0}."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Error al importar el perfil de {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "Este perfil {0} contiene datos incorrectos, no se han podido importar."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "El equipo definido en el perfil {0} ({1}) no coincide con el equipo actual ({2}), no se ha podido importar."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Error al importar el perfil de {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1073,12 +1069,7 @@ msgid ""
"
Backups can be found in the configuration folder.
\n"
"
Please send us this Crash Report to fix the problem.
\n"
" "
-msgstr ""
-"
¡Vaya! Ultimaker Cura ha encontrado un error.
\n"
-"
Hemos detectado un error irreversible durante el inicio, posiblemente como consecuencia de varios archivos de configuración erróneos. Le recomendamos que realice una copia de seguridad y que restablezca los ajustes.
\n"
-"
Las copias de seguridad se encuentran en la carpeta de configuración.
\n"
-"
Envíenos el informe de errores para que podamos solucionar el problema.
\n"
-" "
+msgstr "
¡Vaya! Ultimaker Cura ha encontrado un error.
\n
Hemos detectado un error irreversible durante el inicio, posiblemente como consecuencia de varios archivos de configuración erróneos. Le recomendamos que realice una copia de seguridad y que restablezca los ajustes.
\n
Las copias de seguridad se encuentran en la carpeta de configuración.
\n
Envíenos el informe de errores para que podamos solucionar el problema.
A fatal error has occurred in Cura. Please send us this Crash Report to fix the problem
\n"
"
Please use the \"Send report\" button to post a bug report automatically to our servers
\n"
" "
-msgstr ""
-"
Se ha producido un error grave en Cura. Envíenos este informe de errores para que podamos solucionar el problema.
\n"
-"
Utilice el botón \"Enviar informe\" para publicar automáticamente el informe de errores en nuestros servidores.
\n"
-" "
+msgstr "
Se ha producido un error grave en Cura. Envíenos este informe de errores para que podamos solucionar el problema.
\n
Utilice el botón \"Enviar informe\" para publicar automáticamente el informe de errores en nuestros servidores.
\n "
#: /home/ruben/Projects/Cura/cura/CrashHandler.py:177
msgctxt "@title:groupbox"
@@ -1408,7 +1396,7 @@ msgstr "Desplazamiento de la tobera sobre el eje Y"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:451
msgctxt "@label"
msgid "Cooling Fan Number"
-msgstr ""
+msgstr "Número de ventilador de enfriamiento"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:452
msgctxt "@label"
@@ -1512,7 +1500,7 @@ msgstr "Atrás"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:20
msgctxt "@title:window"
msgid "Confirm uninstall"
-msgstr ""
+msgstr "Confirmar desinstalación"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:50
msgctxt "@text:window"
@@ -1590,10 +1578,7 @@ msgid ""
"This plugin contains a license.\n"
"You need to accept this license to install this plugin.\n"
"Do you agree with the terms below?"
-msgstr ""
-"Este complemento incluye una licencia.\n"
-"Debe aceptar dicha licencia para instalar el complemento.\n"
-"¿Acepta las condiciones que aparecen a continuación?"
+msgstr "Este complemento incluye una licencia.\nDebe aceptar dicha licencia para instalar el complemento.\n¿Acepta las condiciones que aparecen a continuación?"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml:54
msgctxt "@action:button"
@@ -1655,7 +1640,7 @@ msgstr "Cerrar"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:31
msgctxt "@title"
msgid "Update Firmware"
-msgstr ""
+msgstr "Actualizar firmware"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:39
msgctxt "@label"
@@ -1680,12 +1665,12 @@ msgstr "Cargar firmware personalizado"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:83
msgctxt "@label"
msgid "Firmware can not be updated because there is no connection with the printer."
-msgstr ""
+msgstr "No se puede actualizar el firmware porque no hay conexión con la impresora."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:91
msgctxt "@label"
msgid "Firmware can not be updated because the connection with the printer does not support upgrading firmware."
-msgstr ""
+msgstr "No se puede actualizar el firmware porque la conexión con la impresora no permite actualizaciones de firmware."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:98
msgctxt "@title:window"
@@ -1753,10 +1738,7 @@ msgid ""
"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"
"\n"
"Select your printer from the list below:"
-msgstr ""
-"Para imprimir directamente en la impresora a través de la red, asegúrese de que esta está conectada a la red utilizando un cable de red o conéctela a la red wifi. Si no conecta Cura con la impresora, también puede utilizar una unidad USB para transferir archivos GCode a la impresora.\n"
-"\n"
-"Seleccione la impresora de la siguiente lista:"
+msgstr "Para imprimir directamente en la impresora a través de la red, asegúrese de que esta está conectada a la red utilizando un cable de red o conéctela a la red wifi. Si no conecta Cura con la impresora, también puede utilizar una unidad USB para transferir archivos GCode a la impresora.\n\nSeleccione la impresora de la siguiente lista:"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml:85
#: /home/ruben/Projects/Cura/resources/qml/Preferences/MachinesPage.qml:42
@@ -1920,62 +1902,62 @@ msgstr "Esperando: "
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:299
msgctxt "@label"
msgid "Configuration change"
-msgstr ""
+msgstr "Cambio de configuración"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:365
msgctxt "@label"
msgid "The assigned printer, %1, requires the following configuration change(s):"
-msgstr ""
+msgstr "Es necesario modificar la siguiente configuración de la impresora asignada %1:"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:367
msgctxt "@label"
msgid "The printer %1 is assigned, but the job contains an unknown material configuration."
-msgstr ""
+msgstr "Se ha asignado la impresora 1%, pero el trabajo tiene una configuración de material desconocido."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:375
msgctxt "@label"
msgid "Change material %1 from %2 to %3."
-msgstr ""
+msgstr "Cambiar material %1, de %2 a %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:378
msgctxt "@label"
msgid "Load %3 as material %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Cargar %3 como material %1 (no se puede anular)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:381
msgctxt "@label"
msgid "Change print core %1 from %2 to %3."
-msgstr ""
+msgstr "Cambiar print core %1, de %2 a %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:384
msgctxt "@label"
msgid "Change build plate to %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Cambiar la placa de impresión a %1 (no se puede anular)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:404
msgctxt "@label"
msgid "Override"
-msgstr ""
+msgstr "Anular"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:432
msgctxt "@label"
msgid "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?"
-msgstr ""
+msgstr "Iniciar un trabajo de impresión con una configuración no compatible puede causar daños en su impresora 3D. ¿Seguro de que desea sobrescribir la configuración e imprimir %1?"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:435
msgctxt "@window:title"
msgid "Override configuration configuration and start print"
-msgstr ""
+msgstr "Sobrescribir la configuración e iniciar la impresión"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:466
msgctxt "@label"
msgid "Glass"
-msgstr ""
+msgstr "Vidrio"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:469
msgctxt "@label"
msgid "Aluminum"
-msgstr ""
+msgstr "Aluminio"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml:39
msgctxt "@label link to connect manager"
@@ -2664,9 +2646,7 @@ msgctxt "@text:window"
msgid ""
"You have customized some profile settings.\n"
"Would you like to keep or discard those settings?"
-msgstr ""
-"Ha personalizado parte de los ajustes del perfil.\n"
-"¿Desea descartar los cambios o guardarlos?"
+msgstr "Ha personalizado parte de los ajustes del perfil.\n¿Desea descartar los cambios o guardarlos?"
#: /home/ruben/Projects/Cura/resources/qml/DiscardOrKeepProfileChangesDialog.qml:110
msgctxt "@title:column"
@@ -3368,9 +3348,7 @@ msgctxt "@info:credit"
msgid ""
"Cura is developed by Ultimaker B.V. in cooperation with the community.\n"
"Cura proudly uses the following open source projects:"
-msgstr ""
-"Ultimaker B.V. ha desarrollado Cura en cooperación con la comunidad.\n"
-"Cura se enorgullece de utilizar los siguientes proyectos de código abierto:"
+msgstr "Ultimaker B.V. ha desarrollado Cura en cooperación con la comunidad.\nCura se enorgullece de utilizar los siguientes proyectos de código abierto:"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:132
msgctxt "@label"
@@ -3435,17 +3413,17 @@ msgstr "Biblioteca de apoyo para gestionar archivos STL"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:145
msgctxt "@label"
msgid "Support library for handling planar objects"
-msgstr ""
+msgstr "Biblioteca de compatibilidad para trabajar con objetos planos"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:146
msgctxt "@label"
msgid "Support library for handling triangular meshes"
-msgstr ""
+msgstr "Biblioteca de compatibilidad para trabajar con mallas triangulares"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:147
msgctxt "@label"
msgid "Support library for analysis of complex networks"
-msgstr ""
+msgstr "Biblioteca de compatibilidad para analizar redes complejas"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:148
msgctxt "@label"
@@ -3455,7 +3433,7 @@ msgstr "Biblioteca de compatibilidad para trabajar con archivos 3MF"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:149
msgctxt "@label"
msgid "Support library for file metadata and streaming"
-msgstr ""
+msgstr "Biblioteca de compatibilidad para metadatos y transmisión de archivos"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:150
msgctxt "@label"
@@ -3503,10 +3481,7 @@ msgid ""
"Some setting/override values are different from the values stored in the profile.\n"
"\n"
"Click to open the profile manager."
-msgstr ""
-"Algunos valores de los ajustes o sobrescrituras son distintos a los valores almacenados en el perfil.\n"
-"\n"
-"Haga clic para abrir el administrador de perfiles."
+msgstr "Algunos valores de los ajustes o sobrescrituras son distintos a los valores almacenados en el perfil.\n\nHaga clic para abrir el administrador de perfiles."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingView.qml:200
msgctxt "@label:textbox"
@@ -3560,10 +3535,7 @@ msgid ""
"Some hidden settings use values different from their normal calculated value.\n"
"\n"
"Click to make these settings visible."
-msgstr ""
-"Algunos ajustes ocultos utilizan valores diferentes de los valores normales calculados.\n"
-"\n"
-"Haga clic para mostrar estos ajustes."
+msgstr "Algunos ajustes ocultos utilizan valores diferentes de los valores normales calculados.\n\nHaga clic para mostrar estos ajustes."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:61
msgctxt "@label Header for list of settings."
@@ -3591,10 +3563,7 @@ msgid ""
"This setting has a value that is different from the profile.\n"
"\n"
"Click to restore the value of the profile."
-msgstr ""
-"Este ajuste tiene un valor distinto del perfil.\n"
-"\n"
-"Haga clic para restaurar el valor del perfil."
+msgstr "Este ajuste tiene un valor distinto del perfil.\n\nHaga clic para restaurar el valor del perfil."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:281
msgctxt "@label"
@@ -3602,10 +3571,7 @@ msgid ""
"This setting is normally calculated, but it currently has an absolute value set.\n"
"\n"
"Click to restore the calculated value."
-msgstr ""
-"Este ajuste se calcula normalmente pero actualmente tiene un valor absoluto establecido.\n"
-"\n"
-"Haga clic para restaurar el valor calculado."
+msgstr "Este ajuste se calcula normalmente pero actualmente tiene un valor absoluto establecido.\n\nHaga clic para restaurar el valor calculado."
#: /home/ruben/Projects/Cura/resources/qml/PrinterOutput/ManualPrinterControl.qml:129
msgctxt "@label"
@@ -3830,9 +3796,7 @@ msgctxt "@label:listbox"
msgid ""
"Print Setup disabled\n"
"G-code files cannot be modified"
-msgstr ""
-"Ajustes de impresión deshabilitados\n"
-"No se pueden modificar los archivos GCode"
+msgstr "Ajustes de impresión deshabilitados\nNo se pueden modificar los archivos GCode"
#: /home/ruben/Projects/Cura/resources/qml/PrepareSidebar.qml:340
msgctxt "@label Hours and minutes"
@@ -4606,12 +4570,12 @@ msgstr "Registro de cambios"
#: FirmwareUpdater/plugin.json
msgctxt "description"
msgid "Provides a machine actions for updating firmware."
-msgstr ""
+msgstr "Proporciona opciones a la máquina para actualizar el firmware."
#: FirmwareUpdater/plugin.json
msgctxt "name"
msgid "Firmware Updater"
-msgstr ""
+msgstr "Actualizador de firmware"
#: ProfileFlattener/plugin.json
msgctxt "description"
diff --git a/resources/i18n/es_ES/fdmextruder.def.json.po b/resources/i18n/es_ES/fdmextruder.def.json.po
index f4791134ce..3da8d5251f 100644
--- a/resources/i18n/es_ES/fdmextruder.def.json.po
+++ b/resources/i18n/es_ES/fdmextruder.def.json.po
@@ -169,12 +169,12 @@ msgstr "Coordenada Z de la posición en la que la tobera queda preparada al inic
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number label"
msgid "Extruder Print Cooling Fan"
-msgstr ""
+msgstr "Ventilador de refrigeración de impresión del extrusor"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number description"
msgid "The number of the print cooling fan associated with this extruder. Only change this from the default value of 0 when you have a different print cooling fan for each extruder."
-msgstr ""
+msgstr "Número del ventilador de refrigeración de impresión asociado al extrusor. Modifique el valor predeterminado 0 solo cuando disponga de un ventilador de refrigeración de impresión diferente para cada extrusor."
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
diff --git a/resources/i18n/es_ES/fdmprinter.def.json.po b/resources/i18n/es_ES/fdmprinter.def.json.po
index 3133fa86b8..bd4ad9fd7f 100644
--- a/resources/i18n/es_ES/fdmprinter.def.json.po
+++ b/resources/i18n/es_ES/fdmprinter.def.json.po
@@ -57,9 +57,7 @@ msgctxt "machine_start_gcode description"
msgid ""
"G-code commands to be executed at the very start - separated by \n"
"."
-msgstr ""
-"Los comandos de GCode que se ejecutarán justo al inicio separados por - \n"
-"."
+msgstr "Los comandos de GCode que se ejecutarán justo al inicio separados por - \n."
#: fdmprinter.def.json
msgctxt "machine_end_gcode label"
@@ -71,9 +69,7 @@ msgctxt "machine_end_gcode description"
msgid ""
"G-code commands to be executed at the very end - separated by \n"
"."
-msgstr ""
-"Los comandos de GCode que se ejecutarán justo al final separados por -\n"
-"."
+msgstr "Los comandos de GCode que se ejecutarán justo al final separados por -\n."
#: fdmprinter.def.json
msgctxt "material_guid label"
@@ -1078,7 +1074,7 @@ msgstr "Conectar polígonos superiores/inferiores"
#: fdmprinter.def.json
msgctxt "connect_skin_polygons description"
msgid "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happen midway over infill this feature can reduce the top surface quality."
-msgstr ""
+msgstr "Conecta las trayectorias de forro superior/inferior cuando están próximas entre sí. Al habilitar este ajuste, en el patrón concéntrico se reduce considerablemente el tiempo de desplazamiento, pero las conexiones pueden producirse en mitad del relleno, con lo que bajaría la calidad de la superficie superior."
#: fdmprinter.def.json
msgctxt "skin_angles label"
@@ -1498,7 +1494,7 @@ msgstr "Patrón de relleno"
#: fdmprinter.def.json
msgctxt "infill_pattern description"
msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
-msgstr ""
+msgstr "Patrón del material de relleno de la impresión. El relleno de línea y zigzag cambia de dirección en capas alternas, con lo que se reduce el coste de material. Los patrones de rejilla, triángulo, trihexágono, cubo, octeto, cubo bitruncado, transversal y concéntrico se imprimen en todas las capas por completo. El relleno giroide, cúbico, cúbico bitruncado y de octeto cambian en cada capa para proporcionar una distribución de fuerza equitativa en cada dirección."
#: fdmprinter.def.json
msgctxt "infill_pattern option grid"
@@ -1563,7 +1559,7 @@ msgstr "Cruz 3D"
#: fdmprinter.def.json
msgctxt "infill_pattern option gyroid"
msgid "Gyroid"
-msgstr ""
+msgstr "Giroide"
#: fdmprinter.def.json
msgctxt "zig_zaggify_infill label"
@@ -1635,9 +1631,7 @@ msgctxt "infill_wall_line_count description"
msgid ""
"Add extra walls around the infill area. Such walls can make top/bottom skin lines sag down less which means you need less top/bottom skin layers for the same quality at the cost of some extra material.\n"
"This feature can combine with the Connect Infill Polygons to connect all the infill into a single extrusion path without the need for travels or retractions if configured right."
-msgstr ""
-"Agregar paredes adicionales alrededor del área de relleno. Estas paredes pueden hacer que las líneas del forro superior/inferior se aflojen menos, lo que significa que necesitaría menos capas de forro superior/inferior para obtener la misma calidad utilizando algo más de material.\n"
-"Puede utilizar esta función junto a la de Conectar polígonos de relleno para conectar todo el relleno en una única trayectoria de extrusión sin necesidad de desplazamientos ni retracciones si se configura correctamente."
+msgstr "Agregar paredes adicionales alrededor del área de relleno. Estas paredes pueden hacer que las líneas del forro superior/inferior se aflojen menos, lo que significa que necesitaría menos capas de forro superior/inferior para obtener la misma calidad utilizando algo más de material.\nPuede utilizar esta función junto a la de Conectar polígonos de relleno para conectar todo el relleno en una única trayectoria de extrusión sin necesidad de desplazamientos ni retracciones si se configura correctamente."
#: fdmprinter.def.json
msgctxt "sub_div_rad_add label"
@@ -3272,32 +3266,32 @@ msgstr "Orientación del patrón de relleno para soportes. El patrón de relleno
#: fdmprinter.def.json
msgctxt "support_brim_enable label"
msgid "Enable Support Brim"
-msgstr ""
+msgstr "Habilitar borde de soporte"
#: fdmprinter.def.json
msgctxt "support_brim_enable description"
msgid "Generate a brim within the support infill regions of the first layer. This brim is printed underneath the support, not around it. Enabling this setting increases the adhesion of support to the build plate."
-msgstr ""
+msgstr "Genera un borde dentro de las zonas de relleno del soporte de la primera capa. Este borde se imprime por debajo del soporte y no a su alrededor. Si habilita esta configuración aumentará la adhesión del soporte a la placa de impresión."
#: fdmprinter.def.json
msgctxt "support_brim_width label"
msgid "Support Brim Width"
-msgstr ""
+msgstr "Ancho del borde de soporte"
#: fdmprinter.def.json
msgctxt "support_brim_width description"
msgid "The width of the brim to print underneath the support. A larger brim enhances adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Anchura del borde de impresión que se imprime por debajo del soporte. Una anchura de soporte amplia mejora la adhesión a la placa de impresión, pero requieren material adicional."
#: fdmprinter.def.json
msgctxt "support_brim_line_count label"
msgid "Support Brim Line Count"
-msgstr ""
+msgstr "Recuento de líneas del borde de soporte"
#: fdmprinter.def.json
msgctxt "support_brim_line_count description"
msgid "The number of lines used for the support brim. More brim lines enhance adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Número de líneas utilizadas para el borde de soporte. Más líneas de borde mejoran la adhesión a la placa de impresión, pero requieren material adicional."
#: fdmprinter.def.json
msgctxt "support_z_distance label"
@@ -3834,9 +3828,7 @@ msgctxt "skirt_gap description"
msgid ""
"The horizontal distance between the skirt and the first layer of the print.\n"
"This is the minimum distance. Multiple skirt lines will extend outwards from this distance."
-msgstr ""
-"La distancia horizontal entre la falda y la primera capa de la impresión.\n"
-"Se trata de la distancia mínima. Múltiples líneas de falda se extenderán hacia el exterior a partir de esta distancia."
+msgstr "La distancia horizontal entre la falda y la primera capa de la impresión.\nSe trata de la distancia mínima. Múltiples líneas de falda se extenderán hacia el exterior a partir de esta distancia."
#: fdmprinter.def.json
msgctxt "skirt_brim_minimal_length label"
@@ -3871,12 +3863,12 @@ msgstr "Número de líneas utilizadas para un borde. Más líneas de borde mejor
#: fdmprinter.def.json
msgctxt "brim_replaces_support label"
msgid "Brim Replaces Support"
-msgstr ""
+msgstr "Sustituir soporte por borde"
#: fdmprinter.def.json
msgctxt "brim_replaces_support description"
msgid "Enforce brim to be printed around the model even if that space would otherwise be occupied by support. This replaces some regions of the first layer of support by brim regions."
-msgstr ""
+msgstr "Aplica la impresión de un borde alrededor del modelo, aunque en esa posición debiera estar el soporte. Sustituye algunas áreas de la primera capa de soporte por áreas de borde."
#: fdmprinter.def.json
msgctxt "brim_outside_only label"
@@ -5283,9 +5275,7 @@ msgctxt "wireframe_up_half_speed description"
msgid ""
"Distance of an upward move which is extruded with half speed.\n"
"This can cause better adhesion to previous layers, while not heating the material in those layers too much. Only applies to Wire Printing."
-msgstr ""
-"Distancia de un movimiento ascendente que se extrude a media velocidad.\n"
-"Esto puede causar una mejor adherencia a las capas anteriores, aunque no calienta demasiado el material en esas capas. Solo se aplica a la impresión de alambre."
+msgstr "Distancia de un movimiento ascendente que se extrude a media velocidad.\nEsto puede causar una mejor adherencia a las capas anteriores, aunque no calienta demasiado el material en esas capas. Solo se aplica a la impresión de alambre."
#: fdmprinter.def.json
msgctxt "wireframe_top_jump label"
diff --git a/resources/i18n/fr_FR/cura.po b/resources/i18n/fr_FR/cura.po
index f477c14ac6..9b1fff4124 100644
--- a/resources/i18n/fr_FR/cura.po
+++ b/resources/i18n/fr_FR/cura.po
@@ -49,7 +49,7 @@ msgstr "GCodeWriter ne prend pas en charge le mode non-texte."
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "Veuillez préparer le G-Code avant d'exporter."
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -64,11 +64,7 @@ msgid ""
"
{model_names}
\n"
"
Find out how to ensure the best possible print quality and reliability.
"
#: /home/ruben/Projects/Cura/plugins/ChangeLogPlugin/ChangeLog.py:32
msgctxt "@item:inmenu"
@@ -78,7 +74,7 @@ msgstr "Afficher le récapitulatif des changements"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "Mettre à jour le firmware"
#: /home/ruben/Projects/Cura/plugins/ProfileFlattener/ProfileFlattener.py:23
msgctxt "@item:inmenu"
@@ -822,7 +818,7 @@ msgstr "Fichier {0} prédécoupé"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "La connexion a échoué"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -896,32 +892,32 @@ msgstr "Échec de l'importation du profil depuis le fichier {0}!"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "Aucun profil personnalisé à importer dans le fichier {0}"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Échec de l'importation du profil depuis le fichier {0} :"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "Le profil {0} contient des données incorrectes ; échec de l'importation."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "La machine définie dans le profil {0} ({1}) ne correspond pas à votre machine actuelle ({2}) ; échec de l'importation."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Échec de l'importation du profil depuis le fichier {0} :"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1073,12 +1069,7 @@ msgid ""
"
Backups can be found in the configuration folder.
\n"
"
Please send us this Crash Report to fix the problem.
\n"
" "
-msgstr ""
-"
Oups, un problème est survenu dans Ultimaker Cura.
\n"
-"
Une erreur irrécupérable est survenue lors du démarrage. Elle peut avoir été causée par des fichiers de configuration incorrects. Nous vous suggérons de sauvegarder et de réinitialiser votre configuration.
\n"
-"
Les sauvegardes se trouvent dans le dossier de configuration.
\n"
-"
Veuillez nous envoyer ce rapport d'incident pour que nous puissions résoudre le problème.
\n"
-" "
+msgstr "
Oups, un problème est survenu dans Ultimaker Cura.
\n
Une erreur irrécupérable est survenue lors du démarrage. Elle peut avoir été causée par des fichiers de configuration incorrects. Nous vous suggérons de sauvegarder et de réinitialiser votre configuration.
\n
Les sauvegardes se trouvent dans le dossier de configuration.
\n
Veuillez nous envoyer ce rapport d'incident pour que nous puissions résoudre le problème.
A fatal error has occurred in Cura. Please send us this Crash Report to fix the problem
\n"
"
Please use the \"Send report\" button to post a bug report automatically to our servers
\n"
" "
-msgstr ""
-"
Une erreur fatale est survenue dans Cura. Veuillez nous envoyer ce rapport d'incident pour résoudre le problème
\n"
-"
Veuillez utiliser le bouton « Envoyer rapport » pour publier automatiquement un rapport d'erreur sur nos serveurs
\n"
-" "
+msgstr "
Une erreur fatale est survenue dans Cura. Veuillez nous envoyer ce rapport d'incident pour résoudre le problème
\n
Veuillez utiliser le bouton « Envoyer rapport » pour publier automatiquement un rapport d'erreur sur nos serveurs
\n "
#: /home/ruben/Projects/Cura/cura/CrashHandler.py:177
msgctxt "@title:groupbox"
@@ -1408,7 +1396,7 @@ msgstr "Décalage buse Y"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:451
msgctxt "@label"
msgid "Cooling Fan Number"
-msgstr ""
+msgstr "Numéro du ventilateur de refroidissement"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:452
msgctxt "@label"
@@ -1512,7 +1500,7 @@ msgstr "Précédent"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:20
msgctxt "@title:window"
msgid "Confirm uninstall"
-msgstr ""
+msgstr "Confirmer la désinstallation"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:50
msgctxt "@text:window"
@@ -1590,10 +1578,7 @@ msgid ""
"This plugin contains a license.\n"
"You need to accept this license to install this plugin.\n"
"Do you agree with the terms below?"
-msgstr ""
-"Ce plug-in contient une licence.\n"
-"Vous devez approuver cette licence pour installer ce plug-in.\n"
-"Acceptez-vous les clauses ci-dessous ?"
+msgstr "Ce plug-in contient une licence.\nVous devez approuver cette licence pour installer ce plug-in.\nAcceptez-vous les clauses ci-dessous ?"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml:54
msgctxt "@action:button"
@@ -1655,7 +1640,7 @@ msgstr "Fermer"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:31
msgctxt "@title"
msgid "Update Firmware"
-msgstr ""
+msgstr "Mettre à jour le firmware"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:39
msgctxt "@label"
@@ -1680,12 +1665,12 @@ msgstr "Charger le firmware personnalisé"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:83
msgctxt "@label"
msgid "Firmware can not be updated because there is no connection with the printer."
-msgstr ""
+msgstr "Impossible de se connecter à l'imprimante ; échec de la mise à jour du firmware."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:91
msgctxt "@label"
msgid "Firmware can not be updated because the connection with the printer does not support upgrading firmware."
-msgstr ""
+msgstr "Échec de la mise à jour du firmware, car cette fonctionnalité n'est pas prise en charge par la connexion avec l'imprimante."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:98
msgctxt "@title:window"
@@ -1753,10 +1738,7 @@ msgid ""
"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"
"\n"
"Select your printer from the list below:"
-msgstr ""
-"Pour imprimer directement sur votre imprimante sur le réseau, assurez-vous que votre imprimante est connectée au réseau via un câble réseau ou en connectant votre imprimante à votre réseau Wi-Fi. Si vous ne connectez pas Cura avec votre imprimante, vous pouvez utiliser une clé USB pour transférer les fichiers g-code sur votre imprimante.\n"
-"\n"
-"Sélectionnez votre imprimante dans la liste ci-dessous :"
+msgstr "Pour imprimer directement sur votre imprimante sur le réseau, assurez-vous que votre imprimante est connectée au réseau via un câble réseau ou en connectant votre imprimante à votre réseau Wi-Fi. Si vous ne connectez pas Cura avec votre imprimante, vous pouvez utiliser une clé USB pour transférer les fichiers g-code sur votre imprimante.\n\nSélectionnez votre imprimante dans la liste ci-dessous :"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml:85
#: /home/ruben/Projects/Cura/resources/qml/Preferences/MachinesPage.qml:42
@@ -1920,62 +1902,62 @@ msgstr "En attente : "
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:299
msgctxt "@label"
msgid "Configuration change"
-msgstr ""
+msgstr "Modification des configurations"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:365
msgctxt "@label"
msgid "The assigned printer, %1, requires the following configuration change(s):"
-msgstr ""
+msgstr "L'imprimante assignée, %1, nécessite d'apporter la ou les modifications suivantes à la configuration :"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:367
msgctxt "@label"
msgid "The printer %1 is assigned, but the job contains an unknown material configuration."
-msgstr ""
+msgstr "L'imprimante %1 est assignée, mais le projet contient une configuration matérielle inconnue."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:375
msgctxt "@label"
msgid "Change material %1 from %2 to %3."
-msgstr ""
+msgstr "Changer le matériau %1 de %2 à %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:378
msgctxt "@label"
msgid "Load %3 as material %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Charger %3 comme matériau %1 (Ceci ne peut pas être remplacé)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:381
msgctxt "@label"
msgid "Change print core %1 from %2 to %3."
-msgstr ""
+msgstr "Changer le print core %1 de %2 à %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:384
msgctxt "@label"
msgid "Change build plate to %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Changer le plateau en %1 (Ceci ne peut pas être remplacé)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:404
msgctxt "@label"
msgid "Override"
-msgstr ""
+msgstr "Remplacer"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:432
msgctxt "@label"
msgid "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?"
-msgstr ""
+msgstr "Le fait de démarrer un travail d'impression avec une configuration incompatible peut endommager votre imprimante 3D. Êtes-vous sûr de vouloir remplacer la configuration et imprimer %1 ?"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:435
msgctxt "@window:title"
msgid "Override configuration configuration and start print"
-msgstr ""
+msgstr "Remplacer la configuration et lancer l'impression"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:466
msgctxt "@label"
msgid "Glass"
-msgstr ""
+msgstr "Verre"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:469
msgctxt "@label"
msgid "Aluminum"
-msgstr ""
+msgstr "Aluminium"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml:39
msgctxt "@label link to connect manager"
@@ -2664,9 +2646,7 @@ msgctxt "@text:window"
msgid ""
"You have customized some profile settings.\n"
"Would you like to keep or discard those settings?"
-msgstr ""
-"Vous avez personnalisé certains paramètres du profil.\n"
-"Souhaitez-vous conserver ces changements, ou les annuler ?"
+msgstr "Vous avez personnalisé certains paramètres du profil.\nSouhaitez-vous conserver ces changements, ou les annuler ?"
#: /home/ruben/Projects/Cura/resources/qml/DiscardOrKeepProfileChangesDialog.qml:110
msgctxt "@title:column"
@@ -3368,9 +3348,7 @@ msgctxt "@info:credit"
msgid ""
"Cura is developed by Ultimaker B.V. in cooperation with the community.\n"
"Cura proudly uses the following open source projects:"
-msgstr ""
-"Cura a été développé par Ultimaker B.V. en coopération avec la communauté Ultimaker.\n"
-"Cura est fier d'utiliser les projets open source suivants :"
+msgstr "Cura a été développé par Ultimaker B.V. en coopération avec la communauté Ultimaker.\nCura est fier d'utiliser les projets open source suivants :"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:132
msgctxt "@label"
@@ -3435,17 +3413,17 @@ msgstr "Prise en charge de la bibliothèque pour le traitement des fichiers STL"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:145
msgctxt "@label"
msgid "Support library for handling planar objects"
-msgstr ""
+msgstr "Prise en charge de la bibliothèque pour le traitement des objets planaires"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:146
msgctxt "@label"
msgid "Support library for handling triangular meshes"
-msgstr ""
+msgstr "Prise en charge de la bibliothèque pour le traitement des mailles triangulaires"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:147
msgctxt "@label"
msgid "Support library for analysis of complex networks"
-msgstr ""
+msgstr "Prise en charge de la bibliothèque pour l'analyse de réseaux complexes"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:148
msgctxt "@label"
@@ -3455,7 +3433,7 @@ msgstr "Prise en charge de la bibliothèque pour le traitement des fichiers 3MF"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:149
msgctxt "@label"
msgid "Support library for file metadata and streaming"
-msgstr ""
+msgstr "Prise en charge de la bibliothèque pour les métadonnées et le streaming de fichiers"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:150
msgctxt "@label"
@@ -3503,10 +3481,7 @@ msgid ""
"Some setting/override values are different from the values stored in the profile.\n"
"\n"
"Click to open the profile manager."
-msgstr ""
-"Certaines valeurs de paramètre / forçage sont différentes des valeurs enregistrées dans le profil. \n"
-"\n"
-"Cliquez pour ouvrir le gestionnaire de profils."
+msgstr "Certaines valeurs de paramètre / forçage sont différentes des valeurs enregistrées dans le profil. \n\nCliquez pour ouvrir le gestionnaire de profils."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingView.qml:200
msgctxt "@label:textbox"
@@ -3560,10 +3535,7 @@ msgid ""
"Some hidden settings use values different from their normal calculated value.\n"
"\n"
"Click to make these settings visible."
-msgstr ""
-"Certains paramètres masqués utilisent des valeurs différentes de leur valeur normalement calculée.\n"
-"\n"
-"Cliquez pour rendre ces paramètres visibles."
+msgstr "Certains paramètres masqués utilisent des valeurs différentes de leur valeur normalement calculée.\n\nCliquez pour rendre ces paramètres visibles."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:61
msgctxt "@label Header for list of settings."
@@ -3591,10 +3563,7 @@ msgid ""
"This setting has a value that is different from the profile.\n"
"\n"
"Click to restore the value of the profile."
-msgstr ""
-"Ce paramètre possède une valeur qui est différente du profil.\n"
-"\n"
-"Cliquez pour restaurer la valeur du profil."
+msgstr "Ce paramètre possède une valeur qui est différente du profil.\n\nCliquez pour restaurer la valeur du profil."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:281
msgctxt "@label"
@@ -3602,10 +3571,7 @@ msgid ""
"This setting is normally calculated, but it currently has an absolute value set.\n"
"\n"
"Click to restore the calculated value."
-msgstr ""
-"Ce paramètre est normalement calculé mais il possède actuellement une valeur absolue définie.\n"
-"\n"
-"Cliquez pour restaurer la valeur calculée."
+msgstr "Ce paramètre est normalement calculé mais il possède actuellement une valeur absolue définie.\n\nCliquez pour restaurer la valeur calculée."
#: /home/ruben/Projects/Cura/resources/qml/PrinterOutput/ManualPrinterControl.qml:129
msgctxt "@label"
@@ -3830,9 +3796,7 @@ msgctxt "@label:listbox"
msgid ""
"Print Setup disabled\n"
"G-code files cannot be modified"
-msgstr ""
-"Configuration de l'impression désactivée\n"
-"Les fichiers G-Code ne peuvent pas être modifiés"
+msgstr "Configuration de l'impression désactivée\nLes fichiers G-Code ne peuvent pas être modifiés"
#: /home/ruben/Projects/Cura/resources/qml/PrepareSidebar.qml:340
msgctxt "@label Hours and minutes"
@@ -4606,12 +4570,12 @@ msgstr "Récapitulatif des changements"
#: FirmwareUpdater/plugin.json
msgctxt "description"
msgid "Provides a machine actions for updating firmware."
-msgstr ""
+msgstr "Fournit à une machine des actions permettant la mise à jour du firmware."
#: FirmwareUpdater/plugin.json
msgctxt "name"
msgid "Firmware Updater"
-msgstr ""
+msgstr "Programme de mise à jour du firmware"
#: ProfileFlattener/plugin.json
msgctxt "description"
diff --git a/resources/i18n/fr_FR/fdmextruder.def.json.po b/resources/i18n/fr_FR/fdmextruder.def.json.po
index 6fc72c38e1..52969f511f 100644
--- a/resources/i18n/fr_FR/fdmextruder.def.json.po
+++ b/resources/i18n/fr_FR/fdmextruder.def.json.po
@@ -169,12 +169,12 @@ msgstr "Les coordonnées Z de la position à laquelle la buse s'amorce au début
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number label"
msgid "Extruder Print Cooling Fan"
-msgstr ""
+msgstr "Ventilateur de refroidissement d'impression de l'extrudeuse"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number description"
msgid "The number of the print cooling fan associated with this extruder. Only change this from the default value of 0 when you have a different print cooling fan for each extruder."
-msgstr ""
+msgstr "Numéro du ventilateur de refroidissement d'impression associé à cette extrudeuse. Ne modifiez cette valeur par rapport à la valeur par défaut 0 que si vous utilisez un ventilateur de refroidissement d'impression différent pour chaque extrudeuse."
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
diff --git a/resources/i18n/fr_FR/fdmprinter.def.json.po b/resources/i18n/fr_FR/fdmprinter.def.json.po
index 4eb7d674f5..87aa9d5a27 100644
--- a/resources/i18n/fr_FR/fdmprinter.def.json.po
+++ b/resources/i18n/fr_FR/fdmprinter.def.json.po
@@ -57,9 +57,7 @@ msgctxt "machine_start_gcode description"
msgid ""
"G-code commands to be executed at the very start - separated by \n"
"."
-msgstr ""
-"Commandes G-Code à exécuter au tout début, séparées par \n"
-"."
+msgstr "Commandes G-Code à exécuter au tout début, séparées par \n."
#: fdmprinter.def.json
msgctxt "machine_end_gcode label"
@@ -71,9 +69,7 @@ msgctxt "machine_end_gcode description"
msgid ""
"G-code commands to be executed at the very end - separated by \n"
"."
-msgstr ""
-"Commandes G-Code à exécuter tout à la fin, séparées par \n"
-"."
+msgstr "Commandes G-Code à exécuter tout à la fin, séparées par \n."
#: fdmprinter.def.json
msgctxt "material_guid label"
@@ -1078,7 +1074,7 @@ msgstr "Relier les polygones supérieurs / inférieurs"
#: fdmprinter.def.json
msgctxt "connect_skin_polygons description"
msgid "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happen midway over infill this feature can reduce the top surface quality."
-msgstr ""
+msgstr "Relier les voies de couche extérieure supérieures / inférieures lorsqu'elles sont côte à côte. Pour le motif concentrique, ce paramètre réduit considérablement le temps de parcours, mais comme les liens peuvent se trouver à mi-chemin sur le remplissage, cette fonctionnalité peut réduire la qualité de la surface supérieure."
#: fdmprinter.def.json
msgctxt "skin_angles label"
@@ -1498,7 +1494,7 @@ msgstr "Motif de remplissage"
#: fdmprinter.def.json
msgctxt "infill_pattern description"
msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
-msgstr ""
+msgstr "Motif du matériau de remplissage de l'impression. La ligne et le remplissage en zigzag changent de sens à chaque alternance de couche, réduisant ainsi les coûts matériels. Les motifs en grille, en triangle, trihexagonaux, cubiques, octaédriques, quart cubiques et concentriques sont entièrement imprimés sur chaque couche. Les remplissages gyroïde, cubique, quart cubique et octaédrique changent à chaque couche afin d'offrir une répartition plus égale de la solidité dans chaque direction."
#: fdmprinter.def.json
msgctxt "infill_pattern option grid"
@@ -1563,7 +1559,7 @@ msgstr "Entrecroisé 3D"
#: fdmprinter.def.json
msgctxt "infill_pattern option gyroid"
msgid "Gyroid"
-msgstr ""
+msgstr "Gyroïde"
#: fdmprinter.def.json
msgctxt "zig_zaggify_infill label"
@@ -1635,9 +1631,7 @@ msgctxt "infill_wall_line_count description"
msgid ""
"Add extra walls around the infill area. Such walls can make top/bottom skin lines sag down less which means you need less top/bottom skin layers for the same quality at the cost of some extra material.\n"
"This feature can combine with the Connect Infill Polygons to connect all the infill into a single extrusion path without the need for travels or retractions if configured right."
-msgstr ""
-"Ajoutez des parois supplémentaires autour de la zone de remplissage. De telles parois peuvent réduire l'affaissement des lignes de couche extérieure supérieure / inférieure, réduisant le nombre de couches extérieures supérieures / inférieures nécessaires pour obtenir la même qualité, au prix d'un peu de matériau supplémentaire.\n"
-"Configurée correctement, cette fonctionnalité peut être combinée avec « Relier les polygones de remplissage » pour relier tous les remplissages en un seul mouvement d'extrusion sans avoir besoin de déplacements ou de rétractions."
+msgstr "Ajoutez des parois supplémentaires autour de la zone de remplissage. De telles parois peuvent réduire l'affaissement des lignes de couche extérieure supérieure / inférieure, réduisant le nombre de couches extérieures supérieures / inférieures nécessaires pour obtenir la même qualité, au prix d'un peu de matériau supplémentaire.\nConfigurée correctement, cette fonctionnalité peut être combinée avec « Relier les polygones de remplissage » pour relier tous les remplissages en un seul mouvement d'extrusion sans avoir besoin de déplacements ou de rétractions."
#: fdmprinter.def.json
msgctxt "sub_div_rad_add label"
@@ -3272,32 +3266,32 @@ msgstr "Orientation du motif de remplissage pour les supports. Le motif de rempl
#: fdmprinter.def.json
msgctxt "support_brim_enable label"
msgid "Enable Support Brim"
-msgstr ""
+msgstr "Activer la bordure du support"
#: fdmprinter.def.json
msgctxt "support_brim_enable description"
msgid "Generate a brim within the support infill regions of the first layer. This brim is printed underneath the support, not around it. Enabling this setting increases the adhesion of support to the build plate."
-msgstr ""
+msgstr "Générer un bord à l'intérieur des zones de remplissage du support de la première couche. Cette bordure est imprimée sous le support et non autour de celui-ci, ce qui augmente l'adhérence du support au plateau."
#: fdmprinter.def.json
msgctxt "support_brim_width label"
msgid "Support Brim Width"
-msgstr ""
+msgstr "Largeur de la bordure du support"
#: fdmprinter.def.json
msgctxt "support_brim_width description"
msgid "The width of the brim to print underneath the support. A larger brim enhances adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Largeur de la bordure à imprimer sous le support. Une plus grande bordure améliore l'adhérence au plateau, mais demande un peu de matériau supplémentaire."
#: fdmprinter.def.json
msgctxt "support_brim_line_count label"
msgid "Support Brim Line Count"
-msgstr ""
+msgstr "Nombre de lignes de la bordure du support"
#: fdmprinter.def.json
msgctxt "support_brim_line_count description"
msgid "The number of lines used for the support brim. More brim lines enhance adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Nombre de lignes utilisées pour la bordure du support. L'augmentation du nombre de lignes de bordure améliore l'adhérence au plateau, mais demande un peu de matériau supplémentaire."
#: fdmprinter.def.json
msgctxt "support_z_distance label"
@@ -3834,9 +3828,7 @@ msgctxt "skirt_gap description"
msgid ""
"The horizontal distance between the skirt and the first layer of the print.\n"
"This is the minimum distance. Multiple skirt lines will extend outwards from this distance."
-msgstr ""
-"La distance horizontale entre la jupe et la première couche de l’impression.\n"
-"Il s’agit de la distance minimale séparant la jupe de l’objet. Si la jupe a d’autres lignes, celles-ci s’étendront vers l’extérieur."
+msgstr "La distance horizontale entre la jupe et la première couche de l’impression.\nIl s’agit de la distance minimale séparant la jupe de l’objet. Si la jupe a d’autres lignes, celles-ci s’étendront vers l’extérieur."
#: fdmprinter.def.json
msgctxt "skirt_brim_minimal_length label"
@@ -3871,12 +3863,12 @@ msgstr "Le nombre de lignes utilisées pour une bordure. Un plus grand nombre de
#: fdmprinter.def.json
msgctxt "brim_replaces_support label"
msgid "Brim Replaces Support"
-msgstr ""
+msgstr "La bordure remplace le support"
#: fdmprinter.def.json
msgctxt "brim_replaces_support description"
msgid "Enforce brim to be printed around the model even if that space would otherwise be occupied by support. This replaces some regions of the first layer of support by brim regions."
-msgstr ""
+msgstr "Appliquer la bordure à imprimer autour du modèle même si cet espace aurait autrement dû être occupé par le support, en remplaçant certaines régions de la première couche de support par des régions de la bordure."
#: fdmprinter.def.json
msgctxt "brim_outside_only label"
@@ -5283,9 +5275,7 @@ msgctxt "wireframe_up_half_speed description"
msgid ""
"Distance of an upward move which is extruded with half speed.\n"
"This can cause better adhesion to previous layers, while not heating the material in those layers too much. Only applies to Wire Printing."
-msgstr ""
-"Distance d’un déplacement ascendant qui est extrudé à mi-vitesse.\n"
-"Cela peut permettre une meilleure adhérence aux couches précédentes sans surchauffer le matériau dans ces couches. Uniquement applicable à l'impression filaire."
+msgstr "Distance d’un déplacement ascendant qui est extrudé à mi-vitesse.\nCela peut permettre une meilleure adhérence aux couches précédentes sans surchauffer le matériau dans ces couches. Uniquement applicable à l'impression filaire."
#: fdmprinter.def.json
msgctxt "wireframe_top_jump label"
diff --git a/resources/i18n/it_IT/cura.po b/resources/i18n/it_IT/cura.po
index 6a30a94865..d285cbfdc3 100644
--- a/resources/i18n/it_IT/cura.po
+++ b/resources/i18n/it_IT/cura.po
@@ -49,7 +49,7 @@ msgstr "GCodeWriter non supporta la modalità non di testo."
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "Preparare il codice G prima dell’esportazione."
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -64,11 +64,7 @@ msgid ""
"
{model_names}
\n"
"
Find out how to ensure the best possible print quality and reliability.
"
#: /home/ruben/Projects/Cura/plugins/ChangeLogPlugin/ChangeLog.py:32
msgctxt "@item:inmenu"
@@ -78,7 +74,7 @@ msgstr "Visualizza registro modifiche"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "Aggiornamento firmware"
#: /home/ruben/Projects/Cura/plugins/ProfileFlattener/ProfileFlattener.py:23
msgctxt "@item:inmenu"
@@ -822,7 +818,7 @@ msgstr "File pre-sezionato {0}"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "Login non riuscito"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -896,32 +892,32 @@ msgstr "Impossibile importare il profilo da {0}: {
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "Nessun profilo personalizzato da importare nel file {0}"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Impossibile importare il profilo da {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "Questo profilo {0} contiene dati errati, impossibile importarlo."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "La macchina definita nel profilo {0} ({1}) non corrisponde alla macchina corrente ({2}), impossibile importarla."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Impossibile importare il profilo da {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1073,12 +1069,7 @@ msgid ""
"
Backups can be found in the configuration folder.
\n"
"
Please send us this Crash Report to fix the problem.
\n"
" "
-msgstr ""
-"
Oops, Ultimaker Cura ha rilevato qualcosa che non sembra corretto.
\n"
-"
Abbiamo riscontrato un errore irrecuperabile durante l’avvio. È stato probabilmente causato da alcuni file di configurazione errati. Suggeriamo di effettuare il backup e ripristinare la configurazione.
\n"
-"
I backup sono contenuti nella cartella configurazione.
\n"
-"
Si prega di inviare questo Rapporto su crash per correggere il problema.
\n"
-" "
+msgstr "
Oops, Ultimaker Cura ha rilevato qualcosa che non sembra corretto.
\n
Abbiamo riscontrato un errore irrecuperabile durante l’avvio. È stato probabilmente causato da alcuni file di configurazione errati. Suggeriamo di effettuare il backup e ripristinare la configurazione.
\n
I backup sono contenuti nella cartella configurazione.
\n
Si prega di inviare questo Rapporto su crash per correggere il problema.
A fatal error has occurred in Cura. Please send us this Crash Report to fix the problem
\n"
"
Please use the \"Send report\" button to post a bug report automatically to our servers
\n"
" "
-msgstr ""
-"
Si è verificato un errore fatale in Cura. Si prega di inviare questo Rapporto su crash per correggere il problema
\n"
-"
Usare il pulsante “Invia report\" per inviare automaticamente una segnalazione errore ai nostri server
\n"
-" "
+msgstr "
Si è verificato un errore fatale in Cura. Si prega di inviare questo Rapporto su crash per correggere il problema
\n
Usare il pulsante “Invia report\" per inviare automaticamente una segnalazione errore ai nostri server
\n "
#: /home/ruben/Projects/Cura/cura/CrashHandler.py:177
msgctxt "@title:groupbox"
@@ -1408,7 +1396,7 @@ msgstr "Scostamento Y ugello"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:451
msgctxt "@label"
msgid "Cooling Fan Number"
-msgstr ""
+msgstr "Numero ventola di raffreddamento"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:452
msgctxt "@label"
@@ -1512,7 +1500,7 @@ msgstr "Indietro"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:20
msgctxt "@title:window"
msgid "Confirm uninstall"
-msgstr ""
+msgstr "Conferma disinstalla"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:50
msgctxt "@text:window"
@@ -1590,10 +1578,7 @@ msgid ""
"This plugin contains a license.\n"
"You need to accept this license to install this plugin.\n"
"Do you agree with the terms below?"
-msgstr ""
-"Questo plugin contiene una licenza.\n"
-"È necessario accettare questa licenza per poter installare il plugin.\n"
-"Accetti i termini sotto riportati?"
+msgstr "Questo plugin contiene una licenza.\nÈ necessario accettare questa licenza per poter installare il plugin.\nAccetti i termini sotto riportati?"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml:54
msgctxt "@action:button"
@@ -1655,7 +1640,7 @@ msgstr "Chiudi"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:31
msgctxt "@title"
msgid "Update Firmware"
-msgstr ""
+msgstr "Aggiornamento firmware"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:39
msgctxt "@label"
@@ -1680,12 +1665,12 @@ msgstr "Carica il firmware personalizzato"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:83
msgctxt "@label"
msgid "Firmware can not be updated because there is no connection with the printer."
-msgstr ""
+msgstr "Impossibile aggiornare il firmware: nessun collegamento con la stampante."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:91
msgctxt "@label"
msgid "Firmware can not be updated because the connection with the printer does not support upgrading firmware."
-msgstr ""
+msgstr "Impossibile aggiornare il firmware: il collegamento con la stampante non supporta l’aggiornamento del firmware."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:98
msgctxt "@title:window"
@@ -1753,10 +1738,7 @@ msgid ""
"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"
"\n"
"Select your printer from the list below:"
-msgstr ""
-"Per stampare direttamente sulla stampante in rete, verificare che la stampante desiderata sia collegata alla rete mediante un cavo di rete o mediante collegamento alla rete WIFI. Se si collega Cura alla stampante, è comunque possibile utilizzare una chiavetta USB per trasferire i file codice G alla stampante.\n"
-"\n"
-"Selezionare la stampante dall’elenco seguente:"
+msgstr "Per stampare direttamente sulla stampante in rete, verificare che la stampante desiderata sia collegata alla rete mediante un cavo di rete o mediante collegamento alla rete WIFI. Se si collega Cura alla stampante, è comunque possibile utilizzare una chiavetta USB per trasferire i file codice G alla stampante.\n\nSelezionare la stampante dall’elenco seguente:"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml:85
#: /home/ruben/Projects/Cura/resources/qml/Preferences/MachinesPage.qml:42
@@ -1920,62 +1902,62 @@ msgstr "In attesa: "
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:299
msgctxt "@label"
msgid "Configuration change"
-msgstr ""
+msgstr "Modifica configurazione"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:365
msgctxt "@label"
msgid "The assigned printer, %1, requires the following configuration change(s):"
-msgstr ""
+msgstr "La stampante assegnata, %1, richiede le seguenti modifiche di configurazione:"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:367
msgctxt "@label"
msgid "The printer %1 is assigned, but the job contains an unknown material configuration."
-msgstr ""
+msgstr "La stampante %1 è assegnata, ma il processo contiene una configurazione materiale sconosciuta."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:375
msgctxt "@label"
msgid "Change material %1 from %2 to %3."
-msgstr ""
+msgstr "Cambia materiale %1 da %2 a %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:378
msgctxt "@label"
msgid "Load %3 as material %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Caricare %3 come materiale %1 (Operazione non annullabile)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:381
msgctxt "@label"
msgid "Change print core %1 from %2 to %3."
-msgstr ""
+msgstr "Cambia print core %1 da %2 a %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:384
msgctxt "@label"
msgid "Change build plate to %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Cambia piano di stampa a %1 (Operazione non annullabile)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:404
msgctxt "@label"
msgid "Override"
-msgstr ""
+msgstr "Override"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:432
msgctxt "@label"
msgid "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?"
-msgstr ""
+msgstr "L’avvio di un processo di stampa con una configurazione non compatibile potrebbe danneggiare la stampante 3D. Sei sicuro di voler annullare la configurazione e stampare %1?"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:435
msgctxt "@window:title"
msgid "Override configuration configuration and start print"
-msgstr ""
+msgstr "Annullare la configurazione e avviare la stampa"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:466
msgctxt "@label"
msgid "Glass"
-msgstr ""
+msgstr "Vetro"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:469
msgctxt "@label"
msgid "Aluminum"
-msgstr ""
+msgstr "Alluminio"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml:39
msgctxt "@label link to connect manager"
@@ -2664,9 +2646,7 @@ msgctxt "@text:window"
msgid ""
"You have customized some profile settings.\n"
"Would you like to keep or discard those settings?"
-msgstr ""
-"Sono state personalizzate alcune impostazioni del profilo.\n"
-"Mantenere o eliminare tali impostazioni?"
+msgstr "Sono state personalizzate alcune impostazioni del profilo.\nMantenere o eliminare tali impostazioni?"
#: /home/ruben/Projects/Cura/resources/qml/DiscardOrKeepProfileChangesDialog.qml:110
msgctxt "@title:column"
@@ -3368,9 +3348,7 @@ msgctxt "@info:credit"
msgid ""
"Cura is developed by Ultimaker B.V. in cooperation with the community.\n"
"Cura proudly uses the following open source projects:"
-msgstr ""
-"Cura è stato sviluppato da Ultimaker B.V. in cooperazione con la comunità.\n"
-"Cura è orgogliosa di utilizzare i seguenti progetti open source:"
+msgstr "Cura è stato sviluppato da Ultimaker B.V. in cooperazione con la comunità.\nCura è orgogliosa di utilizzare i seguenti progetti open source:"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:132
msgctxt "@label"
@@ -3435,17 +3413,17 @@ msgstr "Libreria di supporto per gestione file STL"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:145
msgctxt "@label"
msgid "Support library for handling planar objects"
-msgstr ""
+msgstr "Libreria di supporto per gestione oggetti planari"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:146
msgctxt "@label"
msgid "Support library for handling triangular meshes"
-msgstr ""
+msgstr "Libreria di supporto per gestione maglie triangolari"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:147
msgctxt "@label"
msgid "Support library for analysis of complex networks"
-msgstr ""
+msgstr "Libreria di supporto per l’analisi di reti complesse"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:148
msgctxt "@label"
@@ -3455,7 +3433,7 @@ msgstr "Libreria di supporto per gestione file 3MF"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:149
msgctxt "@label"
msgid "Support library for file metadata and streaming"
-msgstr ""
+msgstr "Libreria di supporto per metadati file e streaming"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:150
msgctxt "@label"
@@ -3503,10 +3481,7 @@ msgid ""
"Some setting/override values are different from the values stored in the profile.\n"
"\n"
"Click to open the profile manager."
-msgstr ""
-"Alcuni valori di impostazione/esclusione sono diversi dai valori memorizzati nel profilo.\n"
-"\n"
-"Fare clic per aprire la gestione profili."
+msgstr "Alcuni valori di impostazione/esclusione sono diversi dai valori memorizzati nel profilo.\n\nFare clic per aprire la gestione profili."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingView.qml:200
msgctxt "@label:textbox"
@@ -3560,10 +3535,7 @@ msgid ""
"Some hidden settings use values different from their normal calculated value.\n"
"\n"
"Click to make these settings visible."
-msgstr ""
-"Alcune impostazioni nascoste utilizzano valori diversi dal proprio valore normale calcolato.\n"
-"\n"
-"Fare clic per rendere visibili queste impostazioni."
+msgstr "Alcune impostazioni nascoste utilizzano valori diversi dal proprio valore normale calcolato.\n\nFare clic per rendere visibili queste impostazioni."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:61
msgctxt "@label Header for list of settings."
@@ -3591,10 +3563,7 @@ msgid ""
"This setting has a value that is different from the profile.\n"
"\n"
"Click to restore the value of the profile."
-msgstr ""
-"Questa impostazione ha un valore diverso dal profilo.\n"
-"\n"
-"Fare clic per ripristinare il valore del profilo."
+msgstr "Questa impostazione ha un valore diverso dal profilo.\n\nFare clic per ripristinare il valore del profilo."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:281
msgctxt "@label"
@@ -3602,10 +3571,7 @@ msgid ""
"This setting is normally calculated, but it currently has an absolute value set.\n"
"\n"
"Click to restore the calculated value."
-msgstr ""
-"Questa impostazione normalmente viene calcolata, ma attualmente ha impostato un valore assoluto.\n"
-"\n"
-"Fare clic per ripristinare il valore calcolato."
+msgstr "Questa impostazione normalmente viene calcolata, ma attualmente ha impostato un valore assoluto.\n\nFare clic per ripristinare il valore calcolato."
#: /home/ruben/Projects/Cura/resources/qml/PrinterOutput/ManualPrinterControl.qml:129
msgctxt "@label"
@@ -3830,9 +3796,7 @@ msgctxt "@label:listbox"
msgid ""
"Print Setup disabled\n"
"G-code files cannot be modified"
-msgstr ""
-"Impostazione di stampa disabilitata\n"
-"I file codice G non possono essere modificati"
+msgstr "Impostazione di stampa disabilitata\nI file codice G non possono essere modificati"
#: /home/ruben/Projects/Cura/resources/qml/PrepareSidebar.qml:340
msgctxt "@label Hours and minutes"
@@ -4606,12 +4570,12 @@ msgstr "Registro modifiche"
#: FirmwareUpdater/plugin.json
msgctxt "description"
msgid "Provides a machine actions for updating firmware."
-msgstr ""
+msgstr "Fornisce azioni macchina per l’aggiornamento del firmware."
#: FirmwareUpdater/plugin.json
msgctxt "name"
msgid "Firmware Updater"
-msgstr ""
+msgstr "Aggiornamento firmware"
#: ProfileFlattener/plugin.json
msgctxt "description"
diff --git a/resources/i18n/it_IT/fdmextruder.def.json.po b/resources/i18n/it_IT/fdmextruder.def.json.po
index 94439de443..aa170f18be 100644
--- a/resources/i18n/it_IT/fdmextruder.def.json.po
+++ b/resources/i18n/it_IT/fdmextruder.def.json.po
@@ -169,12 +169,12 @@ msgstr "Indica la coordinata Z della posizione in cui l’ugello si innesca all
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number label"
msgid "Extruder Print Cooling Fan"
-msgstr ""
+msgstr "Ventola di raffreddamento stampa estrusore"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number description"
msgid "The number of the print cooling fan associated with this extruder. Only change this from the default value of 0 when you have a different print cooling fan for each extruder."
-msgstr ""
+msgstr "Il numero di ventole di raffreddamento stampa abbinate a questo estrusore. Modificarlo dal valore predefinito 0 solo quando si ha una ventola di raffreddamento diversa per ciascun estrusore."
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
diff --git a/resources/i18n/it_IT/fdmprinter.def.json.po b/resources/i18n/it_IT/fdmprinter.def.json.po
index b4b425da8d..e2d013f74c 100644
--- a/resources/i18n/it_IT/fdmprinter.def.json.po
+++ b/resources/i18n/it_IT/fdmprinter.def.json.po
@@ -57,9 +57,7 @@ msgctxt "machine_start_gcode description"
msgid ""
"G-code commands to be executed at the very start - separated by \n"
"."
-msgstr ""
-"I comandi codice G da eseguire all’avvio, separati da \n"
-"."
+msgstr "I comandi codice G da eseguire all’avvio, separati da \n."
#: fdmprinter.def.json
msgctxt "machine_end_gcode label"
@@ -71,9 +69,7 @@ msgctxt "machine_end_gcode description"
msgid ""
"G-code commands to be executed at the very end - separated by \n"
"."
-msgstr ""
-"I comandi codice G da eseguire alla fine, separati da \n"
-"."
+msgstr "I comandi codice G da eseguire alla fine, separati da \n."
#: fdmprinter.def.json
msgctxt "material_guid label"
@@ -1078,7 +1074,7 @@ msgstr "Collega poligoni superiori/inferiori"
#: fdmprinter.def.json
msgctxt "connect_skin_polygons description"
msgid "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happen midway over infill this feature can reduce the top surface quality."
-msgstr ""
+msgstr "Collega i percorsi del rivestimento esterno superiore/inferiore quando corrono uno accanto all’altro. Per le configurazioni concentriche, l’abilitazione di questa impostazione riduce notevolmente il tempo di spostamento, tuttavia poiché i collegamenti possono aver luogo a metà del riempimento, con questa funzione la qualità della superficie superiore potrebbe risultare inferiore."
#: fdmprinter.def.json
msgctxt "skin_angles label"
@@ -1498,7 +1494,7 @@ msgstr "Configurazione di riempimento"
#: fdmprinter.def.json
msgctxt "infill_pattern description"
msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
-msgstr ""
+msgstr "Configurazione del materiale di riempimento della stampa. Il riempimento a linea e a zig zag cambia direzione su strati alternati, riducendo il costo del materiale. Le configurazioni a griglia, a triangolo, tri-esagonali, cubiche, ottagonali, a quarto di cubo, incrociate e concentriche sono stampate completamente su ogni strato. Le configurazioni gyroid, cubiche, a quarto di cubo e ottagonali variano per ciascuno strato per garantire una più uniforme distribuzione della forza in ogni direzione."
#: fdmprinter.def.json
msgctxt "infill_pattern option grid"
@@ -1563,7 +1559,7 @@ msgstr "Incrociata 3D"
#: fdmprinter.def.json
msgctxt "infill_pattern option gyroid"
msgid "Gyroid"
-msgstr ""
+msgstr "Gyroid"
#: fdmprinter.def.json
msgctxt "zig_zaggify_infill label"
@@ -1635,9 +1631,7 @@ msgctxt "infill_wall_line_count description"
msgid ""
"Add extra walls around the infill area. Such walls can make top/bottom skin lines sag down less which means you need less top/bottom skin layers for the same quality at the cost of some extra material.\n"
"This feature can combine with the Connect Infill Polygons to connect all the infill into a single extrusion path without the need for travels or retractions if configured right."
-msgstr ""
-"Aggiunge pareti supplementari intorno alla zona di riempimento. Queste pareti possono ridurre l’abbassamento delle linee del rivestimento esterno superiore/inferiore, pertanto saranno necessari meno strati di rivestimento esterno superiore/inferiore per ottenere la stessa qualità al costo del materiale supplementare.\n"
-"Questa funzione può essere abbinata a Collega poligoni riempimento per collegare tutto il riempimento in un unico percorso di estrusione senza necessità di avanzamenti o arretramenti, se configurata correttamente."
+msgstr "Aggiunge pareti supplementari intorno alla zona di riempimento. Queste pareti possono ridurre l’abbassamento delle linee del rivestimento esterno superiore/inferiore, pertanto saranno necessari meno strati di rivestimento esterno superiore/inferiore per ottenere la stessa qualità al costo del materiale supplementare.\nQuesta funzione può essere abbinata a Collega poligoni riempimento per collegare tutto il riempimento in un unico percorso di estrusione senza necessità di avanzamenti o arretramenti, se configurata correttamente."
#: fdmprinter.def.json
msgctxt "sub_div_rad_add label"
@@ -3272,32 +3266,32 @@ msgstr "Indica l’orientamento della configurazione del riempimento per i suppo
#: fdmprinter.def.json
msgctxt "support_brim_enable label"
msgid "Enable Support Brim"
-msgstr ""
+msgstr "Abilitazione brim del supporto"
#: fdmprinter.def.json
msgctxt "support_brim_enable description"
msgid "Generate a brim within the support infill regions of the first layer. This brim is printed underneath the support, not around it. Enabling this setting increases the adhesion of support to the build plate."
-msgstr ""
+msgstr "Genera un brim entro le zone di riempimento del supporto del primo strato. Questo brim viene stampato al di sotto del supporto, non intorno ad esso. L’abilitazione di questa impostazione aumenta l’adesione del supporto al piano di stampa."
#: fdmprinter.def.json
msgctxt "support_brim_width label"
msgid "Support Brim Width"
-msgstr ""
+msgstr "Larghezza del brim del supporto"
#: fdmprinter.def.json
msgctxt "support_brim_width description"
msgid "The width of the brim to print underneath the support. A larger brim enhances adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Corrisponde alla larghezza del brim da stampare al di sotto del supporto. Un brim più largo migliora l’adesione al piano di stampa, ma utilizza una maggiore quantità di materiale."
#: fdmprinter.def.json
msgctxt "support_brim_line_count label"
msgid "Support Brim Line Count"
-msgstr ""
+msgstr "Numero di linee del brim del supporto"
#: fdmprinter.def.json
msgctxt "support_brim_line_count description"
msgid "The number of lines used for the support brim. More brim lines enhance adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Corrisponde al numero di linee utilizzate per il brim del supporto. Più linee brim migliorano l’adesione al piano di stampa, ma utilizzano una maggiore quantità di materiale."
#: fdmprinter.def.json
msgctxt "support_z_distance label"
@@ -3834,9 +3828,7 @@ msgctxt "skirt_gap description"
msgid ""
"The horizontal distance between the skirt and the first layer of the print.\n"
"This is the minimum distance. Multiple skirt lines will extend outwards from this distance."
-msgstr ""
-"Indica la distanza orizzontale tra lo skirt ed il primo strato della stampa.\n"
-"Questa è la distanza minima. Più linee di skirt aumenteranno tale distanza."
+msgstr "Indica la distanza orizzontale tra lo skirt ed il primo strato della stampa.\nQuesta è la distanza minima. Più linee di skirt aumenteranno tale distanza."
#: fdmprinter.def.json
msgctxt "skirt_brim_minimal_length label"
@@ -3871,12 +3863,12 @@ msgstr "Corrisponde al numero di linee utilizzate per un brim. Più linee brim m
#: fdmprinter.def.json
msgctxt "brim_replaces_support label"
msgid "Brim Replaces Support"
-msgstr ""
+msgstr "Brim in sostituzione del supporto"
#: fdmprinter.def.json
msgctxt "brim_replaces_support description"
msgid "Enforce brim to be printed around the model even if that space would otherwise be occupied by support. This replaces some regions of the first layer of support by brim regions."
-msgstr ""
+msgstr "Abilita la stampa del brim intorno al modello anche se quello spazio dovrebbe essere occupato dal supporto. Sostituisce alcune zone del primo strato del supporto con zone del brim."
#: fdmprinter.def.json
msgctxt "brim_outside_only label"
@@ -5283,9 +5275,7 @@ msgctxt "wireframe_up_half_speed description"
msgid ""
"Distance of an upward move which is extruded with half speed.\n"
"This can cause better adhesion to previous layers, while not heating the material in those layers too much. Only applies to Wire Printing."
-msgstr ""
-"Indica la distanza di uno spostamento verso l'alto con estrusione a velocità dimezzata.\n"
-"Ciò può garantire una migliore adesione agli strati precedenti, senza eccessivo riscaldamento del materiale su questi strati. Applicabile solo alla funzione Wire Printing."
+msgstr "Indica la distanza di uno spostamento verso l'alto con estrusione a velocità dimezzata.\nCiò può garantire una migliore adesione agli strati precedenti, senza eccessivo riscaldamento del materiale su questi strati. Applicabile solo alla funzione Wire Printing."
#: fdmprinter.def.json
msgctxt "wireframe_top_jump label"
diff --git a/resources/i18n/ja_JP/cura.po b/resources/i18n/ja_JP/cura.po
index ddc9447004..13916ef1e2 100644
--- a/resources/i18n/ja_JP/cura.po
+++ b/resources/i18n/ja_JP/cura.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Cura 3.6\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2018-10-29 15:01+0100\n"
-"PO-Revision-Date: 2018-09-28 15:19+0200\n"
+"PO-Revision-Date: 2018-11-06 14:58+0100\n"
"Last-Translator: Bothof \n"
"Language-Team: Japanese\n"
"Language: ja_JP\n"
@@ -49,7 +49,7 @@ msgstr "GCodeWriter は非テキストモードはサポートしていません
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "エクスポートする前にG-codeの準備をしてください。"
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -78,7 +78,7 @@ msgstr "Changelogの表示"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "ファームウェアアップデート"
#: /home/ruben/Projects/Cura/plugins/ProfileFlattener/ProfileFlattener.py:23
msgctxt "@item:inmenu"
@@ -823,7 +823,7 @@ msgstr "スライス前ファイル {0}"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "ログインに失敗しました"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -874,7 +874,7 @@ msgstr "{0}にプロファイルを書き出すのに失敗
#, python-brace-format
msgctxt "@info:status Don't translate the XML tag !"
msgid "Failed to export profile to {0}: Writer plugin reported failure."
-msgstr " {0}にプロファイルを書き出すことに失敗しました。:ライタープラグイン失敗の報告。"
+msgstr "{0}にプロファイルを書き出すことに失敗しました。:ライタープラグイン失敗の報告。"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:143
#, python-brace-format
@@ -897,32 +897,32 @@ msgstr "{0}: {1}からプロファイル
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "ファイル{0}にはカスタムプロファイルがインポートされていません。"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "{0}からプロファイルの取り込に失敗しました。"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "このプロファイル{0}には、正しくないデータが含まれているため、インポートできません。"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "プロファイル{0}の中で定義されているマシン({1})は、現在お使いのマシン({2})と一致しないため、インポートできませんでした。"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "{0}からプロファイルの取り込に失敗しました。"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1409,7 +1409,7 @@ msgstr "ノズルオフセットY"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:451
msgctxt "@label"
msgid "Cooling Fan Number"
-msgstr ""
+msgstr "冷却ファンの番号"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:452
msgctxt "@label"
@@ -1513,7 +1513,7 @@ msgstr "戻る"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:20
msgctxt "@title:window"
msgid "Confirm uninstall"
-msgstr ""
+msgstr "アンインストール確認"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:50
msgctxt "@text:window"
@@ -1619,7 +1619,7 @@ msgstr "互換性"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml:16
msgctxt "@info"
msgid "Fetching packages..."
-msgstr "パッケージ取得中"
+msgstr "パッケージ取得中…"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml:88
msgctxt "@label"
@@ -1656,7 +1656,7 @@ msgstr "閉める"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:31
msgctxt "@title"
msgid "Update Firmware"
-msgstr ""
+msgstr "ファームウェアアップデート"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:39
msgctxt "@label"
@@ -1681,12 +1681,12 @@ msgstr "カスタムファームウェアをアップロードする"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:83
msgctxt "@label"
msgid "Firmware can not be updated because there is no connection with the printer."
-msgstr ""
+msgstr "プリンターと接続されていないため、ファームウェアをアップデートできません。"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:91
msgctxt "@label"
msgid "Firmware can not be updated because the connection with the printer does not support upgrading firmware."
-msgstr ""
+msgstr "プリンターとの接続はファームウェアのアップデートをサポートしていないため、ファームウェアをアップデートできません。"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:98
msgctxt "@title:window"
@@ -1918,62 +1918,62 @@ msgstr "待ち時間: "
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:299
msgctxt "@label"
msgid "Configuration change"
-msgstr ""
+msgstr "構成の変更"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:365
msgctxt "@label"
msgid "The assigned printer, %1, requires the following configuration change(s):"
-msgstr ""
+msgstr "割り当てられたプリンター %1 には以下の構成変更が必要です。"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:367
msgctxt "@label"
msgid "The printer %1 is assigned, but the job contains an unknown material configuration."
-msgstr ""
+msgstr "プリンター %1 が割り当てられましたが、ジョブには不明な材料構成があります。"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:375
msgctxt "@label"
msgid "Change material %1 from %2 to %3."
-msgstr ""
+msgstr "材料 %1 を %2 から %3 に変更します。"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:378
msgctxt "@label"
msgid "Load %3 as material %1 (This cannot be overridden)."
-msgstr ""
+msgstr "%3 を 材料 %1 にロードします(これは上書きできません)。"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:381
msgctxt "@label"
msgid "Change print core %1 from %2 to %3."
-msgstr ""
+msgstr "プリントコア %1 を %2 から %3 に変更します。"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:384
msgctxt "@label"
msgid "Change build plate to %1 (This cannot be overridden)."
-msgstr ""
+msgstr "ビルドプレートを %1 に変更します(これは上書きできません)。"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:404
msgctxt "@label"
msgid "Override"
-msgstr ""
+msgstr "上書き"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:432
msgctxt "@label"
msgid "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?"
-msgstr ""
+msgstr "互換性のない構成で印刷ジョブを開始すると3Dプリンターを損傷することがあります。構成と印刷 %1 を上書きしますか?"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:435
msgctxt "@window:title"
msgid "Override configuration configuration and start print"
-msgstr ""
+msgstr "構成を上書きしてから印刷を開始"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:466
msgctxt "@label"
msgid "Glass"
-msgstr ""
+msgstr "ガラス"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:469
msgctxt "@label"
msgid "Aluminum"
-msgstr ""
+msgstr "アルミニウム"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml:39
msgctxt "@label link to connect manager"
@@ -2625,7 +2625,7 @@ msgstr "プリンターへの接続が切断されました"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/MachinesPage.qml:187
msgctxt "@label:MonitorStatus"
msgid "Printing..."
-msgstr "プリント中"
+msgstr "プリント中…"
#: /home/ruben/Projects/Cura/resources/qml/MonitorButton.qml:149
#: /home/ruben/Projects/Cura/resources/qml/Preferences/MachinesPage.qml:189
@@ -2637,7 +2637,7 @@ msgstr "一時停止しました"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/MachinesPage.qml:191
msgctxt "@label:MonitorStatus"
msgid "Preparing..."
-msgstr "準備中"
+msgstr "準備中…"
#: /home/ruben/Projects/Cura/resources/qml/MonitorButton.qml:154
msgctxt "@label:MonitorStatus"
@@ -2862,12 +2862,12 @@ msgstr "フィラメントを取り込む"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/Materials/MaterialsPage.qml:286
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Could not import material %1: %2"
-msgstr " %1フィラメントを取り込むことができない: %2"
+msgstr "%1フィラメントを取り込むことができない: %2"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/Materials/MaterialsPage.qml:290
msgctxt "@info:status Don't translate the XML tag !"
msgid "Successfully imported material %1"
-msgstr "フィラメント%1の取り込みに成功しました。"
+msgstr "フィラメント%1の取り込みに成功しました"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/Materials/MaterialsPage.qml:308
#: /home/ruben/Projects/Cura/resources/qml/Preferences/Materials/MaterialsPage.qml:316
@@ -2883,7 +2883,7 @@ msgstr "フィラメントの書き出しに失敗しました %1!"
msgid "Successfully exported material to %1"
-msgstr "フィラメントの%1への書き出しが完了ました。"
+msgstr "フィラメントの%1への書き出しが完了ました"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/SettingVisibilityPage.qml:14
msgctxt "@title:tab"
@@ -3431,17 +3431,17 @@ msgstr "STLファイルを操作するためのライブラリーサポート"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:145
msgctxt "@label"
msgid "Support library for handling planar objects"
-msgstr ""
+msgstr "平面対象物を操作するためのライブラリーサポート"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:146
msgctxt "@label"
msgid "Support library for handling triangular meshes"
-msgstr ""
+msgstr "参画メッシュを操作するためのライブラリーサポート"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:147
msgctxt "@label"
msgid "Support library for analysis of complex networks"
-msgstr ""
+msgstr "複雑なネットワークを分析するためのライブラリーサポート"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:148
msgctxt "@label"
@@ -3451,7 +3451,7 @@ msgstr "3MFファイルを操作するためのライブラリーサポート"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:149
msgctxt "@label"
msgid "Support library for file metadata and streaming"
-msgstr ""
+msgstr "ファイルメタデータとストリーミングのためのライブラリーサポート"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:150
msgctxt "@label"
@@ -3537,7 +3537,7 @@ msgstr "常に見えるように設定する"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:417
msgctxt "@action:menu"
msgid "Configure setting visibility..."
-msgstr "視野のセッティングを構成する"
+msgstr "視野のセッティングを構成する…"
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingView.qml:644
msgctxt "@action:inmenu"
@@ -3766,7 +3766,7 @@ msgstr "すべての設定を表示"
#: /home/ruben/Projects/Cura/resources/qml/Menus/SettingVisibilityPresetsMenu.qml:53
msgctxt "@action:inmenu"
msgid "Manage Setting Visibility..."
-msgstr "視野のセッティングを管理する"
+msgstr "視野のセッティングを管理する…"
# can’t enter japanese texts
#: /home/ruben/Projects/Cura/resources/qml/Menus/ContextMenu.qml:27
@@ -3941,17 +3941,17 @@ msgstr "Curaを構成する…"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:156
msgctxt "@action:inmenu menubar:printer"
msgid "&Add Printer..."
-msgstr "&プリンターを追加する"
+msgstr "&プリンターを追加する…"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:162
msgctxt "@action:inmenu menubar:printer"
msgid "Manage Pr&inters..."
-msgstr "プリンターを管理する"
+msgstr "プリンターを管理する…"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:169
msgctxt "@action:inmenu"
msgid "Manage Materials..."
-msgstr "フィラメントを管理する"
+msgstr "フィラメントを管理する…"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:177
msgctxt "@action:inmenu menubar:profile"
@@ -3971,7 +3971,7 @@ msgstr "&今の設定/無効からプロファイルを作成する…"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:203
msgctxt "@action:inmenu menubar:profile"
msgid "Manage Profiles..."
-msgstr "プロファイルを管理する"
+msgstr "プロファイルを管理する…"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:210
msgctxt "@action:inmenu menubar:help"
@@ -4092,7 +4092,7 @@ msgstr "&新しいプロジェクト…"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:402
msgctxt "@action:inmenu menubar:help"
msgid "Show Engine &Log..."
-msgstr "エンジン&ログを表示する"
+msgstr "エンジン&ログを表示する…"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:410
msgctxt "@action:inmenu menubar:help"
@@ -4295,7 +4295,7 @@ msgstr "設定"
#: /home/ruben/Projects/Cura/resources/qml/Cura.qml:593
msgctxt "@title:window"
msgid "New project"
-msgstr "新しいプロジェクト…"
+msgstr "新しいプロジェクト"
#: /home/ruben/Projects/Cura/resources/qml/Cura.qml:594
msgctxt "@info:question"
@@ -4598,12 +4598,12 @@ msgstr "Changelog"
#: FirmwareUpdater/plugin.json
msgctxt "description"
msgid "Provides a machine actions for updating firmware."
-msgstr ""
+msgstr "ファームウェアアップデートのためのマシン操作を提供します。"
#: FirmwareUpdater/plugin.json
msgctxt "name"
msgid "Firmware Updater"
-msgstr ""
+msgstr "ファームウェアアップデーター"
#: ProfileFlattener/plugin.json
msgctxt "description"
diff --git a/resources/i18n/ja_JP/fdmextruder.def.json.po b/resources/i18n/ja_JP/fdmextruder.def.json.po
index 826048fa4f..95f0382823 100644
--- a/resources/i18n/ja_JP/fdmextruder.def.json.po
+++ b/resources/i18n/ja_JP/fdmextruder.def.json.po
@@ -170,12 +170,12 @@ msgstr "印刷開始時にノズルがポジションを確認するZ座標。"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number label"
msgid "Extruder Print Cooling Fan"
-msgstr ""
+msgstr "エクストルーダープリント冷却ファン"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number description"
msgid "The number of the print cooling fan associated with this extruder. Only change this from the default value of 0 when you have a different print cooling fan for each extruder."
-msgstr ""
+msgstr "このエクストルーダーに関連付けられているプリント冷却ファンの数です。デフォルト値は0(ゼロ)です。各エクストルーダーに対してプリント冷却ファンが異なる場合にのみ変更します。"
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
diff --git a/resources/i18n/ja_JP/fdmprinter.def.json.po b/resources/i18n/ja_JP/fdmprinter.def.json.po
index 72053ac7ac..3156e77288 100644
--- a/resources/i18n/ja_JP/fdmprinter.def.json.po
+++ b/resources/i18n/ja_JP/fdmprinter.def.json.po
@@ -61,9 +61,7 @@ msgctxt "machine_start_gcode description"
msgid ""
"G-code commands to be executed at the very start - separated by \n"
"."
-msgstr ""
-"最初に実行するG-codeコマンドは、\n"
-"で区切ります。"
+msgstr "最初に実行するG-codeコマンドは、\nで区切ります。"
#: fdmprinter.def.json
msgctxt "machine_end_gcode label"
@@ -75,9 +73,7 @@ msgctxt "machine_end_gcode description"
msgid ""
"G-code commands to be executed at the very end - separated by \n"
"."
-msgstr ""
-"最後に実行するG-codeコマンドは、\n"
-"で区切ります。"
+msgstr "最後に実行するG-codeコマンドは、\nで区切ります。"
#: fdmprinter.def.json
msgctxt "material_guid label"
@@ -1123,7 +1119,7 @@ msgstr "上層/底層ポリゴンに接合"
#: fdmprinter.def.json
msgctxt "connect_skin_polygons description"
msgid "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happen midway over infill this feature can reduce the top surface quality."
-msgstr ""
+msgstr "互いに次に実行する上層/底層スキンパスに接合します。同心円のパターンの場合、この設定を有効にすることにより、移動時間が短縮されますが、インフィルまでの途中で接合があるため、この機能で上層面の品質が損なわれることがあります。"
#: fdmprinter.def.json
msgctxt "skin_angles label"
@@ -1326,9 +1322,7 @@ msgstr "ZシームX"
#: fdmprinter.def.json
msgctxt "z_seam_x description"
msgid "The X coordinate of the position near where to start printing each part in a layer."
-msgstr ""
-"レイヤー内の各印刷を開始するX座\n"
-"標の位置。"
+msgstr "レイヤー内の各印刷を開始するX座\n標の位置。"
#: fdmprinter.def.json
msgctxt "z_seam_y label"
@@ -1569,7 +1563,7 @@ msgstr "インフィルパターン"
#: fdmprinter.def.json
msgctxt "infill_pattern description"
msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
-msgstr ""
+msgstr "印刷用インフィル材料のパターン。代替層のラインとジグザグの面詰めスワップ方向、材料コストを削減します。グリッド、トライアングル、トライ六角、キュービック、オクテット、クォーターキュービック、クロスと同心円のパターンは、すべてのレイヤーを完全に印刷されます。ジャイロイド、キュービック、クォーターキュービック、オクテットのインフィルは、各レイヤーを変更して各方向の強度をより均等な分布にします。"
#: fdmprinter.def.json
msgctxt "infill_pattern option grid"
@@ -1637,7 +1631,7 @@ msgstr "3Dクロス"
#: fdmprinter.def.json
msgctxt "infill_pattern option gyroid"
msgid "Gyroid"
-msgstr ""
+msgstr "ジャイロイド"
# msgstr "クロス3D"
#: fdmprinter.def.json
@@ -1711,9 +1705,7 @@ msgctxt "infill_wall_line_count description"
msgid ""
"Add extra walls around the infill area. Such walls can make top/bottom skin lines sag down less which means you need less top/bottom skin layers for the same quality at the cost of some extra material.\n"
"This feature can combine with the Connect Infill Polygons to connect all the infill into a single extrusion path without the need for travels or retractions if configured right."
-msgstr ""
-"インフィルエリア周辺に外壁を追加します。このような壁は、上層/底層ラインにたるみを作ります。つまり、一部の外壁材料の費用で同じ品質を実現するためには、必要な上層/底層スキンが少ないことを意味します。\n"
-"この機能は、インフィルポリゴン接合と組み合わせて、構成が正しい場合、移動または引き戻しが必要なく、すべてのインフィルを1つの押出経路に接続することができます。"
+msgstr "インフィルエリア周辺に外壁を追加します。このような壁は、上層/底層ラインにたるみを作ります。つまり、一部の外壁材料の費用で同じ品質を実現するためには、必要な上層/底層スキンが少ないことを意味します。\nこの機能は、インフィルポリゴン接合と組み合わせて、構成が正しい場合、移動または引き戻しが必要なく、すべてのインフィルを1つの押出経路に接続することができます。"
#: fdmprinter.def.json
msgctxt "sub_div_rad_add label"
@@ -1816,9 +1808,7 @@ msgstr "インフィル優先"
#: fdmprinter.def.json
msgctxt "infill_before_walls description"
msgid "Print the infill before printing the walls. Printing the walls first may lead to more accurate walls, but overhangs print worse. Printing the infill first leads to sturdier walls, but the infill pattern might sometimes show through the surface."
-msgstr ""
-"壁より前にインフィルをプリントします はじめに壁をプリントするとより精密な壁になりますが、オーバーハングのプリントは悪化します\n"
-"はじめにインフィルをプリントすると丈夫な壁になりますが、インフィルの模様が時折表面から透けて表れます。"
+msgstr "壁より前にインフィルをプリントします はじめに壁をプリントするとより精密な壁になりますが、オーバーハングのプリントは悪化します\nはじめにインフィルをプリントすると丈夫な壁になりますが、インフィルの模様が時折表面から透けて表れます。"
#: fdmprinter.def.json
msgctxt "min_infill_area label"
@@ -3374,32 +3364,32 @@ msgstr "対応するインフィルラインの向きです。サポートイン
#: fdmprinter.def.json
msgctxt "support_brim_enable label"
msgid "Enable Support Brim"
-msgstr ""
+msgstr "サポートブリムを有効にする"
#: fdmprinter.def.json
msgctxt "support_brim_enable description"
msgid "Generate a brim within the support infill regions of the first layer. This brim is printed underneath the support, not around it. Enabling this setting increases the adhesion of support to the build plate."
-msgstr ""
+msgstr "最初の層のインフィルエリア内ブリムを生成します。このブリムは、サポートの周囲ではなく、サポートの下に印刷されます。この設定を有効にすると、サポートのビルドプレートへの吸着性が高まります。"
#: fdmprinter.def.json
msgctxt "support_brim_width label"
msgid "Support Brim Width"
-msgstr ""
+msgstr "サポートブリムの幅"
#: fdmprinter.def.json
msgctxt "support_brim_width description"
msgid "The width of the brim to print underneath the support. A larger brim enhances adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "サポートの下に印刷されるブリムの幅。ブリムが大きいほど、追加材料の費用でビルドプレートへの接着性が強化されます。"
#: fdmprinter.def.json
msgctxt "support_brim_line_count label"
msgid "Support Brim Line Count"
-msgstr ""
+msgstr "サポートブリムのライン数"
#: fdmprinter.def.json
msgctxt "support_brim_line_count description"
msgid "The number of lines used for the support brim. More brim lines enhance adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "サポートブリムに使用される線の数。ブリムの線数を増やすと、追加材料の費用でビルドプレートへの接着性が強化されます。"
#: fdmprinter.def.json
msgctxt "support_z_distance label"
@@ -3964,9 +3954,7 @@ msgctxt "skirt_gap description"
msgid ""
"The horizontal distance between the skirt and the first layer of the print.\n"
"This is the minimum distance. Multiple skirt lines will extend outwards from this distance."
-msgstr ""
-"スカートと印刷の最初の層の間の水平距離。\n"
-"これは最小距離です。複数のスカートラインがこの距離から外側に展開されます。"
+msgstr "スカートと印刷の最初の層の間の水平距離。\nこれは最小距離です。複数のスカートラインがこの距離から外側に展開されます。"
#: fdmprinter.def.json
msgctxt "skirt_brim_minimal_length label"
@@ -4001,12 +3989,12 @@ msgstr "ブリムに使用される線数。ブリムの線数は、ビルドプ
#: fdmprinter.def.json
msgctxt "brim_replaces_support label"
msgid "Brim Replaces Support"
-msgstr ""
+msgstr "ブリム交換サポート"
#: fdmprinter.def.json
msgctxt "brim_replaces_support description"
msgid "Enforce brim to be printed around the model even if that space would otherwise be occupied by support. This replaces some regions of the first layer of support by brim regions."
-msgstr ""
+msgstr "スペースがサポートで埋まっている場合でも、モデルの周辺にブリムを印刷します。これにより、サポートの最初の層の一部のエリアがブリムになります。"
#: fdmprinter.def.json
msgctxt "brim_outside_only label"
diff --git a/resources/i18n/ko_KR/cura.po b/resources/i18n/ko_KR/cura.po
index ee93088df1..6f32d46cd7 100644
--- a/resources/i18n/ko_KR/cura.po
+++ b/resources/i18n/ko_KR/cura.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Cura 3.6\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-29 15:01+0100\n"
-"PO-Revision-Date: 2018-09-28 14:25+0100\n"
+"PO-Revision-Date: 2018-11-06 15:00+0100\n"
"Last-Translator: Jinbuhm Kim \n"
"Language-Team: Jinbum Kim , Korean \n"
"Language: ko_KR\n"
@@ -49,7 +49,7 @@ msgstr "GCodeWriter는 텍스트가 아닌 모드는 지원하지 않습니다."
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "내보내기 전에 G-code를 준비하십시오."
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -78,7 +78,7 @@ msgstr "변경 내역 표시"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "펌웨어 업데이트"
#: /home/ruben/Projects/Cura/plugins/ProfileFlattener/ProfileFlattener.py:23
msgctxt "@item:inmenu"
@@ -822,7 +822,7 @@ msgstr "미리 슬라이싱한 파일 {0}"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "로그인 실패"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -896,32 +896,32 @@ msgstr "{0}: {1} 에서 프로파일을
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "{0}(으)로 가져올 사용자 정의 프로파일이 없습니다"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "{0}에서 프로파일을 가져오지 못했습니다:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "프로파일 {0}에는 정확하지 않은 데이터가 포함되어 있으므로, 불러올 수 없습니다."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "프로필 {0}({1})에 정의된 제품이 현재 제품({2})과 일치하지 않으므로, 불러올 수 없습니다."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "{0}에서 프로파일을 가져오지 못했습니다:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1408,7 +1408,7 @@ msgstr "노즐 오프셋 Y"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:451
msgctxt "@label"
msgid "Cooling Fan Number"
-msgstr ""
+msgstr "냉각 팬 번호"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:452
msgctxt "@label"
@@ -1512,7 +1512,7 @@ msgstr "뒤로"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:20
msgctxt "@title:window"
msgid "Confirm uninstall"
-msgstr ""
+msgstr "제거 확인"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:50
msgctxt "@text:window"
@@ -1537,7 +1537,7 @@ msgstr "확인"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxFooter.qml:17
msgctxt "@info"
msgid "You will need to restart Cura before changes in packages have effect."
-msgstr "패키지의 변경 사항이 적용되기 전에 Cura를 다시 시작해야 합니다"
+msgstr "패키지의 변경 사항이 적용되기 전에 Cura를 다시 시작해야 합니다."
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxFooter.qml:34
msgctxt "@info:button"
@@ -1655,7 +1655,7 @@ msgstr "닫기"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:31
msgctxt "@title"
msgid "Update Firmware"
-msgstr ""
+msgstr "펌웨어 업데이트"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:39
msgctxt "@label"
@@ -1680,12 +1680,12 @@ msgstr "사용자 정의 펌웨어 업로드"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:83
msgctxt "@label"
msgid "Firmware can not be updated because there is no connection with the printer."
-msgstr ""
+msgstr "프린터와 연결되지 않아 펌웨어를 업데이트할 수 없습니다."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:91
msgctxt "@label"
msgid "Firmware can not be updated because the connection with the printer does not support upgrading firmware."
-msgstr ""
+msgstr "프린터와 연결이 펌웨어 업그레이드를 지원하지 않아 펌웨어를 업데이트할 수 없습니다."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:98
msgctxt "@title:window"
@@ -1920,62 +1920,62 @@ msgstr "대기: "
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:299
msgctxt "@label"
msgid "Configuration change"
-msgstr ""
+msgstr "구성 변경"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:365
msgctxt "@label"
msgid "The assigned printer, %1, requires the following configuration change(s):"
-msgstr ""
+msgstr "할당된 프린터 %1의 구성을 다음과 같이 변경해야 합니다:"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:367
msgctxt "@label"
msgid "The printer %1 is assigned, but the job contains an unknown material configuration."
-msgstr ""
+msgstr "프린터 %1이(가) 할당되었으나 작업에 알 수 없는 재료 구성이 포함되어 있습니다."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:375
msgctxt "@label"
msgid "Change material %1 from %2 to %3."
-msgstr ""
+msgstr "재료 %1을(를) %2에서 %3(으)로 변경합니다."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:378
msgctxt "@label"
msgid "Load %3 as material %1 (This cannot be overridden)."
-msgstr ""
+msgstr "%3을(를) 재료 %1(으)로 로드합니다(이 작업은 무효화할 수 없음)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:381
msgctxt "@label"
msgid "Change print core %1 from %2 to %3."
-msgstr ""
+msgstr "PrintCore %1을(를) %2에서 %3(으)로 변경합니다."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:384
msgctxt "@label"
msgid "Change build plate to %1 (This cannot be overridden)."
-msgstr ""
+msgstr "빌드 플레이트를 %1(으)로 변경합니다(이 작업은 무효화할 수 없음)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:404
msgctxt "@label"
msgid "Override"
-msgstr ""
+msgstr "무시하기"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:432
msgctxt "@label"
msgid "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?"
-msgstr ""
+msgstr "호환되지 않는 구성이 있는 인쇄 작업을 시작하면 3D 프린터가 손상될 수 있습니다. 구성을 재정의하고 %1을(를) 인쇄하시겠습니까?"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:435
msgctxt "@window:title"
msgid "Override configuration configuration and start print"
-msgstr ""
+msgstr "구성 재정의 및 인쇄 시작"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:466
msgctxt "@label"
msgid "Glass"
-msgstr ""
+msgstr "유리"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:469
msgctxt "@label"
msgid "Aluminum"
-msgstr ""
+msgstr "알루미늄"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml:39
msgctxt "@label link to connect manager"
@@ -2204,7 +2204,7 @@ msgstr "이미지 변환 ..."
#: /home/ruben/Projects/Cura/plugins/ImageReader/ConfigUI.qml:33
msgctxt "@info:tooltip"
msgid "The maximum distance of each pixel from \"Base.\""
-msgstr "\"Base\"에서 각 픽셀까지의 최대 거리"
+msgstr "\"Base\"에서 각 픽셀까지의 최대 거리."
#: /home/ruben/Projects/Cura/plugins/ImageReader/ConfigUI.qml:38
msgctxt "@action:label"
@@ -3433,17 +3433,17 @@ msgstr "STL 파일 처리를 위한 라이브러리"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:145
msgctxt "@label"
msgid "Support library for handling planar objects"
-msgstr ""
+msgstr "평면 개체 처리를 위한 지원 라이브러리"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:146
msgctxt "@label"
msgid "Support library for handling triangular meshes"
-msgstr ""
+msgstr "삼각형 메쉬 처리를 위한 지원 라이브러리"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:147
msgctxt "@label"
msgid "Support library for analysis of complex networks"
-msgstr ""
+msgstr "복잡한 네트워크 분석을 위한 지원 라이브러리"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:148
msgctxt "@label"
@@ -3453,7 +3453,7 @@ msgstr "3MF 파일 처리를 위한 라이브러리"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:149
msgctxt "@label"
msgid "Support library for file metadata and streaming"
-msgstr ""
+msgstr "파일 메타데이터 및 스트리밍을 위한 지원 라이브러리"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:150
msgctxt "@label"
@@ -4488,7 +4488,7 @@ msgstr "재료"
#: /home/ruben/Projects/Cura/resources/qml/SidebarHeader.qml:543
msgctxt "@label"
msgid "Use glue with this material combination"
-msgstr "이 재료 조합과 함께 접착제를 사용하십시오."
+msgstr "이 재료 조합과 함께 접착제를 사용하십시오"
#: /home/ruben/Projects/Cura/resources/qml/SidebarHeader.qml:575
msgctxt "@label"
@@ -4598,12 +4598,12 @@ msgstr "변경 내역"
#: FirmwareUpdater/plugin.json
msgctxt "description"
msgid "Provides a machine actions for updating firmware."
-msgstr ""
+msgstr "펌웨어 업데이트를 위한 기계 동작을 제공합니다."
#: FirmwareUpdater/plugin.json
msgctxt "name"
msgid "Firmware Updater"
-msgstr ""
+msgstr "펌웨어 업데이터"
#: ProfileFlattener/plugin.json
msgctxt "description"
@@ -4688,7 +4688,7 @@ msgstr "이동식 드라이브 출력 장치 플러그인"
#: UM3NetworkPrinting/plugin.json
msgctxt "description"
msgid "Manages network connections to Ultimaker 3 printers."
-msgstr "Ultimaker 3 프린터에 대한 네트워크 연결을 관리합니다"
+msgstr "Ultimaker 3 프린터에 대한 네트워크 연결을 관리합니다."
#: UM3NetworkPrinting/plugin.json
msgctxt "name"
diff --git a/resources/i18n/ko_KR/fdmextruder.def.json.po b/resources/i18n/ko_KR/fdmextruder.def.json.po
index cef9d4ba3d..bbfe9429fb 100644
--- a/resources/i18n/ko_KR/fdmextruder.def.json.po
+++ b/resources/i18n/ko_KR/fdmextruder.def.json.po
@@ -171,12 +171,12 @@ msgstr "프린팅이 시작될 때 노즐이 시작하는 위치의 Z 좌표입
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number label"
msgid "Extruder Print Cooling Fan"
-msgstr ""
+msgstr "익스트루더 프린팅 냉각 팬"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number description"
msgid "The number of the print cooling fan associated with this extruder. Only change this from the default value of 0 when you have a different print cooling fan for each extruder."
-msgstr ""
+msgstr "이 익스트루더와 관련된 프린팅 냉각 팬의 개수. 각 익스트루더마다 다른 프린팅 냉각 팬이 있을 때만 기본값 0에서 변경하십시오."
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
diff --git a/resources/i18n/ko_KR/fdmprinter.def.json.po b/resources/i18n/ko_KR/fdmprinter.def.json.po
index 72a8b763f0..37392395ef 100644
--- a/resources/i18n/ko_KR/fdmprinter.def.json.po
+++ b/resources/i18n/ko_KR/fdmprinter.def.json.po
@@ -58,9 +58,7 @@ msgctxt "machine_start_gcode description"
msgid ""
"G-code commands to be executed at the very start - separated by \n"
"."
-msgstr ""
-"시작과 동시에형실행될 G 코드 명령어 \n"
-"."
+msgstr "시작과 동시에형실행될 G 코드 명령어 \n."
#: fdmprinter.def.json
msgctxt "machine_end_gcode label"
@@ -72,9 +70,7 @@ msgctxt "machine_end_gcode description"
msgid ""
"G-code commands to be executed at the very end - separated by \n"
"."
-msgstr ""
-"맨 마지막에 실행될 G 코드 명령 \n"
-"."
+msgstr "맨 마지막에 실행될 G 코드 명령 \n."
#: fdmprinter.def.json
msgctxt "material_guid label"
@@ -1079,7 +1075,7 @@ msgstr "상단/하단 다각형 연결"
#: fdmprinter.def.json
msgctxt "connect_skin_polygons description"
msgid "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happen midway over infill this feature can reduce the top surface quality."
-msgstr ""
+msgstr "스킨 경로가 나란히 이어지는 상단/하단 스킨 경로를 연결합니다. 동심원 패턴의 경우 이 설정을 사용하면 이동 시간이 크게 감소하지만, 내부채움의 중간에 연결될 수 있기 때문에 이 기능은 상단 표면 품질을 저하시킬 수 있습니다."
#: fdmprinter.def.json
msgctxt "skin_angles label"
@@ -1499,7 +1495,7 @@ msgstr "내부채움 패턴"
#: fdmprinter.def.json
msgctxt "infill_pattern description"
msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
-msgstr ""
+msgstr "프린트 충진 재료의 패턴입니다. 선과 갈지자형 충진이 레이어를 하나 걸러서 방향을 바꾸므로 재료비가 절감됩니다. 격자, 삼각형, 삼육각형, 입방체, 옥텟, 4분 입방체, 십자, 동심원 패턴이 레이어마다 완전히 인쇄됩니다. 자이로이드, 입방체, 4분 입방체, 옥텟 충진이 레이어마다 변경되므로 각 방향으로 힘이 더 균등하게 분산됩니다."
#: fdmprinter.def.json
msgctxt "infill_pattern option grid"
@@ -1564,7 +1560,7 @@ msgstr "십자형 3D"
#: fdmprinter.def.json
msgctxt "infill_pattern option gyroid"
msgid "Gyroid"
-msgstr ""
+msgstr "자이로이드"
#: fdmprinter.def.json
msgctxt "zig_zaggify_infill label"
@@ -1636,9 +1632,7 @@ msgctxt "infill_wall_line_count description"
msgid ""
"Add extra walls around the infill area. Such walls can make top/bottom skin lines sag down less which means you need less top/bottom skin layers for the same quality at the cost of some extra material.\n"
"This feature can combine with the Connect Infill Polygons to connect all the infill into a single extrusion path without the need for travels or retractions if configured right."
-msgstr ""
-"내부채움 영역 주변에 여분의 벽을 추가합니다. 이러한 벽은 상단/하단 스킨 라인이 늘어지는 것을 줄여줄 수 있습니다. 일부 여분 재료를 사용해도 같은 품질을 유지하는 데 필요한 필요한 상단/하단 스킨 층이 감소한다는 의미입니다.\n"
-"이 기능을 올바르게 구성하는 경우 내부채움 다각형 연결과 함께 사용해 이동 또는 리트랙션없이 모든 내부채움을 단일 돌출 경로에 연결할 수 있습니다."
+msgstr "내부채움 영역 주변에 여분의 벽을 추가합니다. 이러한 벽은 상단/하단 스킨 라인이 늘어지는 것을 줄여줄 수 있습니다. 일부 여분 재료를 사용해도 같은 품질을 유지하는 데 필요한 필요한 상단/하단 스킨 층이 감소한다는 의미입니다.\n이 기능을 올바르게 구성하는 경우 내부채움 다각형 연결과 함께 사용해 이동 또는 리트랙션없이 모든 내부채움을 단일 돌출 경로에 연결할 수 있습니다."
#: fdmprinter.def.json
msgctxt "sub_div_rad_add label"
@@ -3273,32 +3267,32 @@ msgstr "서포트에 대한 내부채움 패턴 방향. 서포트 내부채움
#: fdmprinter.def.json
msgctxt "support_brim_enable label"
msgid "Enable Support Brim"
-msgstr ""
+msgstr "서포트 브림 사용"
#: fdmprinter.def.json
msgctxt "support_brim_enable description"
msgid "Generate a brim within the support infill regions of the first layer. This brim is printed underneath the support, not around it. Enabling this setting increases the adhesion of support to the build plate."
-msgstr ""
+msgstr "첫 번째 레이어의 서포트 내부채움 영역 내에서 브림을 생성합니다. 이 브림은 서포트 주변이 아니라 아래에 인쇄됩니다. 이 설정을 사용하면 빌드 플레이트에 대한 서포트력이 향상됩니다."
#: fdmprinter.def.json
msgctxt "support_brim_width label"
msgid "Support Brim Width"
-msgstr ""
+msgstr "서포트 브림 폭"
#: fdmprinter.def.json
msgctxt "support_brim_width description"
msgid "The width of the brim to print underneath the support. A larger brim enhances adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "서포트 아래를 인쇄하기 위한 브림 폭. 브림이 커질수록 추가 재료가 소요되지만 빌드 플레이트에 대한 접착력이 향상됩니다."
#: fdmprinter.def.json
msgctxt "support_brim_line_count label"
msgid "Support Brim Line Count"
-msgstr ""
+msgstr "서포트 브림 라인 수"
#: fdmprinter.def.json
msgctxt "support_brim_line_count description"
msgid "The number of lines used for the support brim. More brim lines enhance adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "서포트 브림에 사용되는 라인의 수. 브림 라인이 많아질수록 추가 재료가 소요되지만 빌드 플레이트에 대한 접착력이 향상됩니다."
#: fdmprinter.def.json
msgctxt "support_z_distance label"
@@ -3835,9 +3829,7 @@ msgctxt "skirt_gap description"
msgid ""
"The horizontal distance between the skirt and the first layer of the print.\n"
"This is the minimum distance. Multiple skirt lines will extend outwards from this distance."
-msgstr ""
-"프린트의 스커트와 첫 번째 레이어 사이의 수평 거리입니다.\n"
-"이것은 최소 거리입니다. 여러 개의 스커트 선이 이 거리에서 바깥쪽으로 연장됩니다."
+msgstr "프린트의 스커트와 첫 번째 레이어 사이의 수평 거리입니다.\n이것은 최소 거리입니다. 여러 개의 스커트 선이 이 거리에서 바깥쪽으로 연장됩니다."
#: fdmprinter.def.json
msgctxt "skirt_brim_minimal_length label"
@@ -3872,12 +3864,12 @@ msgstr "브림에 사용되는 선의 수입니다. 더 많은 브림 선이 빌
#: fdmprinter.def.json
msgctxt "brim_replaces_support label"
msgid "Brim Replaces Support"
-msgstr ""
+msgstr "브림이 서포트 대체"
#: fdmprinter.def.json
msgctxt "brim_replaces_support description"
msgid "Enforce brim to be printed around the model even if that space would otherwise be occupied by support. This replaces some regions of the first layer of support by brim regions."
-msgstr ""
+msgstr "서포트가 차지할 공간이더라도 모델 주변에 브림이 인쇄되도록 합니다. 이렇게 하면 서포트의 첫 번째 레이어 영역 일부가 브림 영역으로 대체됩니다."
#: fdmprinter.def.json
msgctxt "brim_outside_only label"
diff --git a/resources/i18n/nl_NL/cura.po b/resources/i18n/nl_NL/cura.po
index ed0d045cd5..60b7671e6c 100644
--- a/resources/i18n/nl_NL/cura.po
+++ b/resources/i18n/nl_NL/cura.po
@@ -8,13 +8,15 @@ msgstr ""
"Project-Id-Version: Cura 3.6\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2018-10-29 15:01+0100\n"
-"PO-Revision-Date: 2018-10-01 11:30+0100\n"
+"PO-Revision-Date: 2018-11-06 15:03+0100\n"
"Last-Translator: Bothof \n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 2.0.6\n"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:22
msgctxt "@action"
@@ -47,7 +49,7 @@ msgstr "GCodeWriter ondersteunt geen non-tekstmodus."
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "Bereid voorafgaand aan het exporteren G-code voor."
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -76,7 +78,7 @@ msgstr "Wijzigingenlogboek Weergeven"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "Firmware bijwerken"
#: /home/ruben/Projects/Cura/plugins/ProfileFlattener/ProfileFlattener.py:23
msgctxt "@item:inmenu"
@@ -439,7 +441,7 @@ msgstr "De PrintCores en/of materialen in de printer wijken af van de PrintCores
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py:91
msgctxt "@info:status"
msgid "Connected over the network"
-msgstr "Via het netwerk verbonden."
+msgstr "Via het netwerk verbonden"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py:303
msgctxt "@info:status"
@@ -820,7 +822,7 @@ msgstr "Vooraf geslicet bestand {0}"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "Inloggen mislukt"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -894,32 +896,32 @@ msgstr "Kan het profiel niet importeren uit {0}: {
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "Er is geen aangepast profiel om in het bestand {0} te importeren"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Kan het profiel niet importeren uit {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "Dit profiel {0} bevat incorrecte gegevens. Kan het profiel niet importeren."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "De machine die is vastgelegd in het profiel {0} ({1}), komt niet overeen met uw huidige machine ({2}). Kan het profiel niet importeren."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Kan het profiel niet importeren uit {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1346,7 +1348,7 @@ msgstr "Hoogte rijbrug"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:238
msgctxt "@tooltip"
msgid "The height difference between the tip of the nozzle and the gantry system (X and Y axes). Used to prevent collisions between previous prints and the gantry when printing \"One at a Time\"."
-msgstr "Het hoogteverschil tussen de punt van de nozzle en het rijbrugsysteem (X- en Y-as). Wordt tijdens \"een voor een\"-printen gebruikt om botsingen tussen eerder geprinte voorwerpen en het rijbrugsysteem te voorkomen"
+msgstr "Het hoogteverschil tussen de punt van de nozzle en het rijbrugsysteem (X- en Y-as). Wordt tijdens \"een voor een\"-printen gebruikt om botsingen tussen eerder geprinte voorwerpen en het rijbrugsysteem te voorkomen."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:257
msgctxt "@label"
@@ -1406,7 +1408,7 @@ msgstr "Nozzle-offset Y"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:451
msgctxt "@label"
msgid "Cooling Fan Number"
-msgstr ""
+msgstr "Nummer van koelventilator"
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
@@ -1525,7 +1527,7 @@ msgstr "Terug"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:20
msgctxt "@title:window"
msgid "Confirm uninstall"
-msgstr ""
+msgstr "De-installeren bevestigen"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:50
msgctxt "@text:window"
@@ -1668,7 +1670,7 @@ msgstr "Sluiten"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:31
msgctxt "@title"
msgid "Update Firmware"
-msgstr ""
+msgstr "Firmware bijwerken"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:39
msgctxt "@label"
@@ -1693,12 +1695,12 @@ msgstr "Aangepaste Firmware Uploaden"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:83
msgctxt "@label"
msgid "Firmware can not be updated because there is no connection with the printer."
-msgstr ""
+msgstr "Kan de firmware niet bijwerken omdat er geen verbinding met de printer is."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:91
msgctxt "@label"
msgid "Firmware can not be updated because the connection with the printer does not support upgrading firmware."
-msgstr ""
+msgstr "Kan de firmware niet bijwerken omdat de verbinding met de printer geen ondersteuning biedt voor het uitvoeren van een firmware-upgrade."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:98
msgctxt "@title:window"
@@ -1933,62 +1935,62 @@ msgstr "Wachten op: "
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:299
msgctxt "@label"
msgid "Configuration change"
-msgstr ""
+msgstr "Configuratiewijziging"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:365
msgctxt "@label"
msgid "The assigned printer, %1, requires the following configuration change(s):"
-msgstr ""
+msgstr "Voor de toegewezen printer, 1%, is/zijn de volgende configuratiewijziging/configuratiewijzigingen vereist:"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:367
msgctxt "@label"
msgid "The printer %1 is assigned, but the job contains an unknown material configuration."
-msgstr ""
+msgstr "De printer 1% is toegewezen. De taak bevat echter een onbekende materiaalconfiguratie."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:375
msgctxt "@label"
msgid "Change material %1 from %2 to %3."
-msgstr ""
+msgstr "Wijzig het materiaal %1 van %2 in %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:378
msgctxt "@label"
msgid "Load %3 as material %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Laad %3 als materiaal %1 (kan niet worden overschreven)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:381
msgctxt "@label"
msgid "Change print core %1 from %2 to %3."
-msgstr ""
+msgstr "Wijzig de print core %1 van %2 in %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:384
msgctxt "@label"
msgid "Change build plate to %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Wijzig het platform naar %1 (kan niet worden overschreven)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:404
msgctxt "@label"
msgid "Override"
-msgstr ""
+msgstr "Overschrijven"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:432
msgctxt "@label"
msgid "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?"
-msgstr ""
+msgstr "Als u een printtaak met een incompatibele configuratie start, kan dit leiden tot schade aan de 3D-printer. Weet u zeker dat u de configuratie en print %1 wilt overschrijven?"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:435
msgctxt "@window:title"
msgid "Override configuration configuration and start print"
-msgstr ""
+msgstr "Configuratie overschrijven en printen starten"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:466
msgctxt "@label"
msgid "Glass"
-msgstr ""
+msgstr "Glas"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:469
msgctxt "@label"
msgid "Aluminum"
-msgstr ""
+msgstr "Aluminium"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml:39
msgctxt "@label link to connect manager"
@@ -2202,12 +2204,12 @@ msgstr "Cura verzendt anonieme gegevens naar Ultimaker om de printkwaliteit en g
#: /home/ruben/Projects/Cura/plugins/SliceInfoPlugin/MoreInfoWindow.qml:101
msgctxt "@text:window"
msgid "I don't want to send these data"
-msgstr "Ik wil deze gegevens niet verzenden."
+msgstr "Ik wil deze gegevens niet verzenden"
#: /home/ruben/Projects/Cura/plugins/SliceInfoPlugin/MoreInfoWindow.qml:111
msgctxt "@text:window"
msgid "Allow sending these data to Ultimaker and help us improve Cura"
-msgstr "Verzenden van deze gegevens naar Ultimaker toestaan en ons helpen Cura te verbeteren."
+msgstr "Verzenden van deze gegevens naar Ultimaker toestaan en ons helpen Cura te verbeteren"
#: /home/ruben/Projects/Cura/plugins/ImageReader/ConfigUI.qml:19
msgctxt "@title:window"
@@ -2247,7 +2249,7 @@ msgstr "Breedte (mm)"
#: /home/ruben/Projects/Cura/plugins/ImageReader/ConfigUI.qml:103
msgctxt "@info:tooltip"
msgid "The depth in millimeters on the build plate"
-msgstr "De diepte op het platform in millimeters."
+msgstr "De diepte op het platform in millimeters"
#: /home/ruben/Projects/Cura/plugins/ImageReader/ConfigUI.qml:108
msgctxt "@action:label"
@@ -2478,7 +2480,7 @@ msgstr "Printerupgrades Selecteren"
#: /home/ruben/Projects/Cura/plugins/UltimakerMachineActions/UM2UpgradeSelectionMachineAction.qml:38
msgctxt "@label"
msgid "Please select any upgrades made to this Ultimaker 2."
-msgstr "Selecteer eventuele upgrades die op deze Ultimaker 2 zijn uitgevoerd"
+msgstr "Selecteer eventuele upgrades die op deze Ultimaker 2 zijn uitgevoerd."
#: /home/ruben/Projects/Cura/plugins/UltimakerMachineActions/UM2UpgradeSelectionMachineAction.qml:47
msgctxt "@label"
@@ -2866,7 +2868,7 @@ msgstr "Verwijderen Bevestigen"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/ProfilesPage.qml:240
msgctxt "@label (%1 is object name)"
msgid "Are you sure you wish to remove %1? This cannot be undone!"
-msgstr "Weet u zeker dat u %1 wilt verwijderen? Deze bewerking kan niet ongedaan worden gemaakt."
+msgstr "Weet u zeker dat u %1 wilt verwijderen? Deze bewerking kan niet ongedaan worden gemaakt!"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/Materials/MaterialsPage.qml:277
#: /home/ruben/Projects/Cura/resources/qml/Preferences/Materials/MaterialsPage.qml:285
@@ -3448,17 +3450,17 @@ msgstr "Ondersteuningsbibliotheek voor het verwerken van STL-bestanden"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:145
msgctxt "@label"
msgid "Support library for handling planar objects"
-msgstr ""
+msgstr "Ondersteuningsbibliotheek voor het verwerken van tweedimensionale objecten"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:146
msgctxt "@label"
msgid "Support library for handling triangular meshes"
-msgstr ""
+msgstr "Ondersteuningsbibliotheek voor het verwerken van driehoekig rasters"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:147
msgctxt "@label"
msgid "Support library for analysis of complex networks"
-msgstr ""
+msgstr "Ondersteuningsbibliotheek voor de analyse van complexe netwerken"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:148
msgctxt "@label"
@@ -3468,7 +3470,7 @@ msgstr "Ondersteuningsbibliotheek voor het verwerken van 3MF-bestanden"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:149
msgctxt "@label"
msgid "Support library for file metadata and streaming"
-msgstr ""
+msgstr "Ondersteuningsbibliotheek voor bestandsmetadata en streaming"
#: /home/ruben/Projects/Cura/resources/qml/AboutDialog.qml:150
msgctxt "@label"
@@ -3591,7 +3593,7 @@ msgstr "Beïnvloed door"
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:155
msgctxt "@label"
msgid "This setting is always shared between all extruders. Changing it here will change the value for all extruders."
-msgstr "Deze instelling wordt altijd door alle extruders gedeeld. Als u hier de instelling wijzigt, wordt de waarde voor alle extruders gewijzigd"
+msgstr "Deze instelling wordt altijd door alle extruders gedeeld. Als u hier de instelling wijzigt, wordt de waarde voor alle extruders gewijzigd."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:158
msgctxt "@label"
@@ -4539,7 +4541,7 @@ msgstr "Huidig platform schikken"
#: MachineSettingsAction/plugin.json
msgctxt "description"
msgid "Provides a way to change machine settings (such as build volume, nozzle size, etc.)."
-msgstr "Biedt een manier om de machine-instellingen (zoals bouwvolume, maat nozzle, enz.) te wijzigen"
+msgstr "Biedt een manier om de machine-instellingen (zoals bouwvolume, maat nozzle, enz.) te wijzigen."
#: MachineSettingsAction/plugin.json
msgctxt "name"
@@ -4619,12 +4621,12 @@ msgstr "Wijzigingenlogboek"
#: FirmwareUpdater/plugin.json
msgctxt "description"
msgid "Provides a machine actions for updating firmware."
-msgstr ""
+msgstr "Biedt machineacties voor het bijwerken van de firmware."
#: FirmwareUpdater/plugin.json
msgctxt "name"
msgid "Firmware Updater"
-msgstr ""
+msgstr "Firmware-updater"
#: ProfileFlattener/plugin.json
msgctxt "description"
@@ -4649,7 +4651,7 @@ msgstr "USB-printen"
#: UserAgreement/plugin.json
msgctxt "description"
msgid "Ask the user once if he/she agrees with our license."
-msgstr "Vraag de gebruiker één keer of deze akkoord gaat met de licentie"
+msgstr "Vraag de gebruiker één keer of deze akkoord gaat met de licentie."
#: UserAgreement/plugin.json
msgctxt "name"
@@ -4709,7 +4711,7 @@ msgstr "Invoegtoepassing voor Verwijderbaar uitvoerapparaat"
#: UM3NetworkPrinting/plugin.json
msgctxt "description"
msgid "Manages network connections to Ultimaker 3 printers."
-msgstr "Hiermee beheert u netwerkverbindingen naar Ultimaker 3-printers"
+msgstr "Hiermee beheert u netwerkverbindingen naar Ultimaker 3-printers."
#: UM3NetworkPrinting/plugin.json
msgctxt "name"
@@ -4844,7 +4846,7 @@ msgstr "Hiermee worden configuraties bijgewerkt van Cura 2.5 naar Cura 2.6."
#: VersionUpgrade/VersionUpgrade25to26/plugin.json
msgctxt "name"
msgid "Version Upgrade 2.5 to 2.6"
-msgstr "Versie-upgrade van 2.5 naar 2.6."
+msgstr "Versie-upgrade van 2.5 naar 2.6"
#: VersionUpgrade/VersionUpgrade27to30/plugin.json
msgctxt "description"
@@ -4884,7 +4886,7 @@ msgstr "Hiermee worden configuraties bijgewerkt van Cura 2.6 naar Cura 2.7."
#: VersionUpgrade/VersionUpgrade26to27/plugin.json
msgctxt "name"
msgid "Version Upgrade 2.6 to 2.7"
-msgstr "Versie-upgrade van 2.6 naar 2.7."
+msgstr "Versie-upgrade van 2.6 naar 2.7"
#: VersionUpgrade/VersionUpgrade21to22/plugin.json
msgctxt "description"
@@ -4904,7 +4906,7 @@ msgstr "Hiermee worden configuraties bijgewerkt van Cura 2.2 naar Cura 2.4."
#: VersionUpgrade/VersionUpgrade22to24/plugin.json
msgctxt "name"
msgid "Version Upgrade 2.2 to 2.4"
-msgstr "Versie-upgrade van 2.2 naar 2.4."
+msgstr "Versie-upgrade van 2.2 naar 2.4"
#: ImageReader/plugin.json
msgctxt "description"
diff --git a/resources/i18n/nl_NL/fdmextruder.def.json.po b/resources/i18n/nl_NL/fdmextruder.def.json.po
index 9fbf5e269a..9dfe5e859e 100644
--- a/resources/i18n/nl_NL/fdmextruder.def.json.po
+++ b/resources/i18n/nl_NL/fdmextruder.def.json.po
@@ -169,12 +169,12 @@ msgstr "De Z-coördinaat van de positie waar filament in de nozzle wordt terugge
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number label"
msgid "Extruder Print Cooling Fan"
-msgstr ""
+msgstr "Printkoelventilator van extruder"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number description"
msgid "The number of the print cooling fan associated with this extruder. Only change this from the default value of 0 when you have a different print cooling fan for each extruder."
-msgstr ""
+msgstr "Het nummer van de bij deze extruder behorende printkoelventilator. Verander de standaardwaarde 0 alleen als u voor elke extruder een andere printkoelventilator hebt."
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
diff --git a/resources/i18n/nl_NL/fdmprinter.def.json.po b/resources/i18n/nl_NL/fdmprinter.def.json.po
index 8ebbaee3d6..1733d1830e 100644
--- a/resources/i18n/nl_NL/fdmprinter.def.json.po
+++ b/resources/i18n/nl_NL/fdmprinter.def.json.po
@@ -8,13 +8,14 @@ msgstr ""
"Project-Id-Version: Cura 3.6\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2018-10-29 15:01+0000\n"
-"PO-Revision-Date: 2018-10-01 14:10+0100\n"
+"PO-Revision-Date: 2018-11-06 15:03+0100\n"
"Last-Translator: Bothof \n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 2.0.6\n"
#: fdmprinter.def.json
msgctxt "machine_settings label"
@@ -547,7 +548,7 @@ msgstr "Maximale Acceleratie X"
#: fdmprinter.def.json
msgctxt "machine_max_acceleration_x description"
msgid "Maximum acceleration for the motor of the X-direction"
-msgstr "De maximale acceleratie van de motor in de X-richting."
+msgstr "De maximale acceleratie van de motor in de X-richting"
#: fdmprinter.def.json
msgctxt "machine_max_acceleration_y label"
@@ -697,7 +698,7 @@ msgstr "Minimale Doorvoersnelheid"
#: fdmprinter.def.json
msgctxt "machine_minimum_feedrate description"
msgid "The minimal movement speed of the print head."
-msgstr "De minimale bewegingssnelheid van de printkop"
+msgstr "De minimale bewegingssnelheid van de printkop."
#: fdmprinter.def.json
msgctxt "machine_feeder_wheel_diameter label"
@@ -747,7 +748,7 @@ msgstr "Lijnbreedte"
#: fdmprinter.def.json
msgctxt "line_width description"
msgid "Width of a single line. Generally, the width of each line should correspond to the width of the nozzle. However, slightly reducing this value could produce better prints."
-msgstr "De breedte van een enkele lijn. Over het algemeen dient de breedte van elke lijn overeen te komen met de breedte van de nozzle. Wanneer deze waarde echter iets wordt verlaagd, resulteert dit in betere prints"
+msgstr "De breedte van een enkele lijn. Over het algemeen dient de breedte van elke lijn overeen te komen met de breedte van de nozzle. Wanneer deze waarde echter iets wordt verlaagd, resulteert dit in betere prints."
#: fdmprinter.def.json
msgctxt "wall_line_width label"
@@ -1077,7 +1078,7 @@ msgstr "Boven-/onderkant Polygonen Verbinden"
#: fdmprinter.def.json
msgctxt "connect_skin_polygons description"
msgid "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happen midway over infill this feature can reduce the top surface quality."
-msgstr ""
+msgstr "Verbind skinpaden aan de boven-/onderkant waar ze naast elkaar lopen. Met deze instelling wordt bij concentrische patronen de bewegingstijd aanzienlijk verkort. Dit kan echter ten koste gaan van de kwaliteit van de bovenste laag aangezien de verbindingen in het midden van de vulling kunnen komen te liggen."
#: fdmprinter.def.json
msgctxt "skin_angles label"
@@ -1497,7 +1498,7 @@ msgstr "Vulpatroon"
#: fdmprinter.def.json
msgctxt "infill_pattern description"
msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
-msgstr ""
+msgstr "Het patroon van het vulmateriaal van de print. De lijn- en zigzagvulling veranderen per vullaag van richting, waardoor wordt bespaard op materiaalkosten. De raster-, driehoeks-, tri-hexagonale, kubische, achtvlaks-, afgeknotte kubus-, kruis- en concentrische patronen worden elke laag volledig geprint. Gyroïde, kubische, afgeknotte kubus- en achtvlaksvullingen veranderen elke laag voor een meer gelijke krachtverdeling in elke richting."
#: fdmprinter.def.json
msgctxt "infill_pattern option grid"
@@ -1562,7 +1563,7 @@ msgstr "Kruis 3D"
#: fdmprinter.def.json
msgctxt "infill_pattern option gyroid"
msgid "Gyroid"
-msgstr ""
+msgstr "Gyroïde"
#: fdmprinter.def.json
msgctxt "zig_zaggify_infill label"
@@ -1866,7 +1867,7 @@ msgstr "Standaard printtemperatuur"
#: fdmprinter.def.json
msgctxt "default_material_print_temperature description"
msgid "The default temperature used for printing. This should be the \"base\" temperature of a material. All other print temperatures should use offsets based on this value"
-msgstr "De standaardtemperatuur waarmee wordt geprint. Dit moet overeenkomen met de basistemperatuur van een materiaal. Voor alle andere printtemperaturen moet een offset worden gebruikt die gebaseerd is op deze waarde."
+msgstr "De standaardtemperatuur waarmee wordt geprint. Dit moet overeenkomen met de basistemperatuur van een materiaal. Voor alle andere printtemperaturen moet een offset worden gebruikt die gebaseerd is op deze waarde"
#: fdmprinter.def.json
msgctxt "material_print_temperature label"
@@ -1926,7 +1927,7 @@ msgstr "Standaardtemperatuur platform"
#: fdmprinter.def.json
msgctxt "default_material_bed_temperature description"
msgid "The default temperature used for the heated build plate. This should be the \"base\" temperature of a build plate. All other print temperatures should use offsets based on this value"
-msgstr "De standaardtemperatuur die wordt gebruikt voor het verwarmde platform. Dit moet overeenkomen met de basistemperatuur van een platform. Voor alle andere printtemperaturen moet een offset worden gebruikt die is gebaseerd op deze waarde."
+msgstr "De standaardtemperatuur die wordt gebruikt voor het verwarmde platform. Dit moet overeenkomen met de basistemperatuur van een platform. Voor alle andere printtemperaturen moet een offset worden gebruikt die is gebaseerd op deze waarde"
#: fdmprinter.def.json
msgctxt "material_bed_temperature label"
@@ -2016,7 +2017,7 @@ msgstr "Intrekken bij laagwisseling"
#: fdmprinter.def.json
msgctxt "retract_at_layer_change description"
msgid "Retract the filament when the nozzle is moving to the next layer."
-msgstr "Trek het filament in wanneer de nozzle naar de volgende laag beweegt. "
+msgstr "Trek het filament in wanneer de nozzle naar de volgende laag beweegt."
#: fdmprinter.def.json
msgctxt "retraction_amount label"
@@ -2386,7 +2387,7 @@ msgstr "Maximale Snelheid voor het Afstemmen van Doorvoer"
#: fdmprinter.def.json
msgctxt "speed_equalize_flow_max description"
msgid "Maximum print speed when adjusting the print speed in order to equalize flow."
-msgstr "Maximale printsnelheid tijdens het aanpassen van de printsnelheid om de doorvoer af te stemmen"
+msgstr "Maximale printsnelheid tijdens het aanpassen van de printsnelheid om de doorvoer af te stemmen."
#: fdmprinter.def.json
msgctxt "acceleration_enabled label"
@@ -3271,32 +3272,32 @@ msgstr "Richting van het vulpatroon voor supportstructuren. Het vulpatroon voor
#: fdmprinter.def.json
msgctxt "support_brim_enable label"
msgid "Enable Support Brim"
-msgstr ""
+msgstr "Supportbrim inschakelen"
#: fdmprinter.def.json
msgctxt "support_brim_enable description"
msgid "Generate a brim within the support infill regions of the first layer. This brim is printed underneath the support, not around it. Enabling this setting increases the adhesion of support to the build plate."
-msgstr ""
+msgstr "Genereer een brim binnen de supportvulgebieden van de eerste laag. Deze brim wordt niet rondom maar onder de supportstructuur geprint. Als u deze instelling inschakelt, hecht de supportstructuur beter aan het platform."
#: fdmprinter.def.json
msgctxt "support_brim_width label"
msgid "Support Brim Width"
-msgstr ""
+msgstr "Breedte supportbrim"
#: fdmprinter.def.json
msgctxt "support_brim_width description"
msgid "The width of the brim to print underneath the support. A larger brim enhances adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "De breedte van de brim die onder de support wordt geprint. Een bredere brim kost meer materiaal, maar hecht beter aan het platform."
#: fdmprinter.def.json
msgctxt "support_brim_line_count label"
msgid "Support Brim Line Count"
-msgstr ""
+msgstr "Aantal supportbrimlijnen"
#: fdmprinter.def.json
msgctxt "support_brim_line_count description"
msgid "The number of lines used for the support brim. More brim lines enhance adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "Het aantal lijnen dat voor de supportbrim wordt gebruikt. Meer brimlijnen zorgen voor betere hechting aan het platform, maar kosten wat extra materiaal."
#: fdmprinter.def.json
msgctxt "support_z_distance label"
@@ -3870,12 +3871,12 @@ msgstr "Het aantal lijnen dat voor een brim wordt gebruikt. Meer lijnen zorgen v
#: fdmprinter.def.json
msgctxt "brim_replaces_support label"
msgid "Brim Replaces Support"
-msgstr ""
+msgstr "Brim vervangt supportstructuur"
#: fdmprinter.def.json
msgctxt "brim_replaces_support description"
msgid "Enforce brim to be printed around the model even if that space would otherwise be occupied by support. This replaces some regions of the first layer of support by brim regions."
-msgstr ""
+msgstr "Dwing af dat de brim rond het model wordt geprint, zelfs als deze ruimte anders door supportstructuur zou worden ingenomen. Hierdoor worden enkele gebieden van de eerste supportlaag vervangen door brimgebieden."
#: fdmprinter.def.json
msgctxt "brim_outside_only label"
diff --git a/resources/i18n/pt_BR/cura.po b/resources/i18n/pt_BR/cura.po
index 8aad16ed27..73b8d759ce 100644
--- a/resources/i18n/pt_BR/cura.po
+++ b/resources/i18n/pt_BR/cura.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Cura 3.6\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2018-10-29 15:01+0100\n"
-"PO-Revision-Date: 2018-10-01 03:20-0300\n"
+"PO-Revision-Date: 2018-11-06 02:20-0300\n"
"Last-Translator: Cláudio Sampaio \n"
"Language-Team: Cláudio Sampaio \n"
"Language: pt_BR\n"
@@ -16,6 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Poedit 2.0.6\n"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:22
msgctxt "@action"
@@ -48,7 +49,7 @@ msgstr "O GCodeWriter não suporta modo binário."
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "Por favor prepare o G-Code antes de exportar."
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -77,7 +78,7 @@ msgstr "Exibir registro de alterações"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "Atualizar Firmware"
#: /home/ruben/Projects/Cura/plugins/ProfileFlattener/ProfileFlattener.py:23
msgctxt "@item:inmenu"
@@ -414,7 +415,7 @@ msgstr "Nenhum material carregado no slot {slot_number}"
#, python-brace-format
msgctxt "@label"
msgid "Different PrintCore (Cura: {cura_printcore_name}, Printer: {remote_printcore_name}) selected for extruder {extruder_id}"
-msgstr "PrintCore Diferente (Cura: {cure_printcore_name}, Impressora: {remote_printcore_name}) selecionado para o extrusor {extruder_id}"
+msgstr "PrintCore Diferente (Cura: {cura_printcore_name}, Impressora: {remote_printcore_name}) selecionado para o extrusor {extruder_id}"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/src/LegacyUM3OutputDevice.py:361
#, python-brace-format
@@ -821,7 +822,7 @@ msgstr "Arquivo pré-fatiado {0}"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "Login falhou"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -895,32 +896,32 @@ msgstr "Falha ao importa perfil de {0}: {1}!"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "Não há perfil personalizado a importar no arquivo {0}"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Erro ao importar perfil de {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "Este perfil {0} contém dados incorretos, não foi possível importá-lo."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "A máquina definida no perfil {0} ({1}) não equivale à sua máquina atual ({2}), não foi possível importá-lo."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Erro ao importar perfil de {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1407,7 +1408,7 @@ msgstr "Deslocamento Y do Bico"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:451
msgctxt "@label"
msgid "Cooling Fan Number"
-msgstr ""
+msgstr "Número da Ventoinha de Resfriamento"
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.qml:452
msgctxt "@label"
@@ -1511,7 +1512,7 @@ msgstr "Voltar"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:20
msgctxt "@title:window"
msgid "Confirm uninstall"
-msgstr ""
+msgstr "Confirme a desinstalação"
#: /home/ruben/Projects/Cura/plugins/Toolbox/resources/qml/ToolboxConfirmUninstallResetDialog.qml:50
msgctxt "@text:window"
@@ -1654,7 +1655,7 @@ msgstr "Fechar"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:31
msgctxt "@title"
msgid "Update Firmware"
-msgstr ""
+msgstr "Atualizar Firmware"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:39
msgctxt "@label"
@@ -1679,12 +1680,12 @@ msgstr "Carregar Firmware personalizado"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:83
msgctxt "@label"
msgid "Firmware can not be updated because there is no connection with the printer."
-msgstr ""
+msgstr "O firmware não pode ser atualizado porque não há conexão com a impressora."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:91
msgctxt "@label"
msgid "Firmware can not be updated because the connection with the printer does not support upgrading firmware."
-msgstr ""
+msgstr "O firmware não pode ser atualizado porque a conexão com a impressora não suporta atualização de firmware."
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml:98
msgctxt "@title:window"
@@ -1919,62 +1920,62 @@ msgstr "Aguardando por: "
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:299
msgctxt "@label"
msgid "Configuration change"
-msgstr ""
+msgstr "Alteração de configuração"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:365
msgctxt "@label"
msgid "The assigned printer, %1, requires the following configuration change(s):"
-msgstr ""
+msgstr "A impressora atribuída, %1, requer as seguintes alterações de configuração:"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:367
msgctxt "@label"
msgid "The printer %1 is assigned, but the job contains an unknown material configuration."
-msgstr ""
+msgstr "A impressora %1 está atribuída, mas o trabalho contém configuração de material desconhecida."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:375
msgctxt "@label"
msgid "Change material %1 from %2 to %3."
-msgstr ""
+msgstr "Alterar material %1 de %2 para %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:378
msgctxt "@label"
msgid "Load %3 as material %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Carregar %3 como material %1 (isto não pode ser sobreposto)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:381
msgctxt "@label"
msgid "Change print core %1 from %2 to %3."
-msgstr ""
+msgstr "Alterar núcleo de impressão %1 de %2 para %3."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:384
msgctxt "@label"
msgid "Change build plate to %1 (This cannot be overridden)."
-msgstr ""
+msgstr "Alterar mesa de impressão para %1 (Isto não pode ser sobreposto)."
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:404
msgctxt "@label"
msgid "Override"
-msgstr ""
+msgstr "Sobrepôr"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:432
msgctxt "@label"
msgid "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?"
-msgstr ""
+msgstr "Iniciar um trabalho de impressão com configuração incompatível pode danificar sua impressora 3D. Voce tem certeza que quer sobrepôr a configuração e imprimir %1?"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:435
msgctxt "@window:title"
msgid "Override configuration configuration and start print"
-msgstr ""
+msgstr "Sobrepôr configuração e iniciar impressão"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:466
msgctxt "@label"
msgid "Glass"
-msgstr ""
+msgstr "Vidro"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/PrintJobInfoBlock.qml:469
msgctxt "@label"
msgid "Aluminum"
-msgstr ""
+msgstr "Alumínio"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/ClusterMonitorItem.qml:39
msgctxt "@label link to connect manager"
@@ -2058,7 +2059,7 @@ msgstr "Abortar impressão"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml:43
msgctxt "@info:tooltip"
msgid "Connect to a printer"
-msgstr "Conecta a uma impressora."
+msgstr "Conecta a uma impressora"
#: /home/ruben/Projects/Cura/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml:121
msgctxt "@action:button"
@@ -2602,7 +2603,7 @@ msgstr "Tudo está em ordem! A verificação terminou."
#: /home/ruben/Projects/Cura/resources/qml/MonitorButton.qml:119
msgctxt "@label:MonitorStatus"
msgid "Not connected to a printer"
-msgstr "Não conectado a nenhuma impressora."
+msgstr "Não conectado a nenhuma impressora"
#: /home/ruben/Projects/Cura/resources/qml/MonitorButton.qml:123
msgctxt "@label:MonitorStatus"
@@ -2980,7 +2981,7 @@ msgstr "Exibir seções pendentes"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/GeneralPage.qml:355
msgctxt "@info:tooltip"
msgid "Moves the camera so the model is in the center of the view when a model is selected"
-msgstr "Move a câmera de modo que o modelo fique no centro da visão quando for selecionado."
+msgstr "Move a câmera de modo que o modelo fique no centro da visão quando for selecionado"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/GeneralPage.qml:360
msgctxt "@action:button"
@@ -3025,7 +3026,7 @@ msgstr "Os modelos devem ser movidos pra baixo pra se assentar na plataforma de
#: /home/ruben/Projects/Cura/resources/qml/Preferences/GeneralPage.qml:418
msgctxt "@option:check"
msgid "Automatically drop models to the build plate"
-msgstr "Automaticamente fazer os modelos caírem na mesa de impressão."
+msgstr "Automaticamente fazer os modelos caírem na mesa de impressão"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/GeneralPage.qml:430
msgctxt "@info:tooltip"
@@ -3110,7 +3111,7 @@ msgstr "Comportamento default ao abrir um arquivo de projeto"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/GeneralPage.qml:557
msgctxt "@window:text"
msgid "Default behavior when opening a project file: "
-msgstr "Comportamento default ao abrir um arquivo de projeto"
+msgstr "Comportamento default ao abrir um arquivo de projeto: "
#: /home/ruben/Projects/Cura/resources/qml/Preferences/GeneralPage.qml:571
msgctxt "@option:openProject"
@@ -3175,7 +3176,7 @@ msgstr "Dados anônimos sobre sua impressão podem ser enviados para a Ultimaker
#: /home/ruben/Projects/Cura/resources/qml/Preferences/GeneralPage.qml:702
msgctxt "@option:check"
msgid "Send (anonymous) print information"
-msgstr "Enviar informação (anônima) de impressão."
+msgstr "Enviar informação (anônima) de impressão"
#: /home/ruben/Projects/Cura/resources/qml/Preferences/GeneralPage.qml:711
msgctxt "@action:button"
@@ -3562,7 +3563,7 @@ msgid ""
msgstr ""
"Alguns ajustes ocultados usam valores diferentes de seu valor calculado normal.\n"
"\n"
-"Clique para tornar estes ajustes visíveis. "
+"Clique para tornar estes ajustes visíveis."
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:61
msgctxt "@label Header for list of settings."
@@ -3582,7 +3583,7 @@ msgstr "Este ajuste é sempre compartilhado entre todos os extrusores. Modificá
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:158
msgctxt "@label"
msgid "The value is resolved from per-extruder values "
-msgstr "O valor é resolvido de valores específicos de cada extrusor"
+msgstr "O valor é resolvido de valores específicos de cada extrusor "
#: /home/ruben/Projects/Cura/resources/qml/Settings/SettingItem.qml:189
msgctxt "@label"
@@ -3655,7 +3656,7 @@ msgstr "A temperatura-alvo do hotend. O hotend vai aquecer ou esfriar na direç
#: /home/ruben/Projects/Cura/resources/qml/PrinterOutput/ExtruderBox.qml:98
msgctxt "@tooltip"
msgid "The current temperature of this hotend."
-msgstr "A temperatura atual deste hotend"
+msgstr "A temperatura atual deste hotend."
#: /home/ruben/Projects/Cura/resources/qml/PrinterOutput/ExtruderBox.qml:172
msgctxt "@tooltip of temperature input"
@@ -4403,7 +4404,7 @@ msgstr "Você modificou alguns ajustes de perfil. Se você quiser alterá-los, u
#: /home/ruben/Projects/Cura/resources/qml/SidebarSimple.qml:541
msgctxt "@label"
msgid "Infill"
-msgstr "Preenchimento:"
+msgstr "Preenchimento"
#: /home/ruben/Projects/Cura/resources/qml/SidebarSimple.qml:777
msgctxt "@label"
@@ -4495,7 +4496,7 @@ msgstr "Material"
#: /home/ruben/Projects/Cura/resources/qml/SidebarHeader.qml:543
msgctxt "@label"
msgid "Use glue with this material combination"
-msgstr "Use cola com esta combinação de materiais."
+msgstr "Use cola com esta combinação de materiais"
#: /home/ruben/Projects/Cura/resources/qml/SidebarHeader.qml:575
msgctxt "@label"
@@ -4845,7 +4846,7 @@ msgstr "Atualização de Versão de 2.7 para 3.0"
#: VersionUpgrade/VersionUpgrade34to35/plugin.json
msgctxt "description"
msgid "Upgrades configurations from Cura 3.4 to Cura 3.5."
-msgstr "Atualiza configurações do Cura 3.4 para o Cura 3.5"
+msgstr "Atualiza configurações do Cura 3.4 para o Cura 3.5."
#: VersionUpgrade/VersionUpgrade34to35/plugin.json
msgctxt "name"
diff --git a/resources/i18n/pt_BR/fdmextruder.def.json.po b/resources/i18n/pt_BR/fdmextruder.def.json.po
index b8ea7ec1e4..10db723a69 100644
--- a/resources/i18n/pt_BR/fdmextruder.def.json.po
+++ b/resources/i18n/pt_BR/fdmextruder.def.json.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Cura 3.6\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2018-10-29 15:01+0000\n"
-"PO-Revision-Date: 2018-10-02 05:00-0300\n"
+"PO-Revision-Date: 2018-11-06 04:00-0300\n"
"Last-Translator: Cláudio Sampaio \n"
"Language-Team: Cláudio Sampaio \n"
"Language: pt_BR\n"
@@ -170,12 +170,12 @@ msgstr "A coordenada Z da posição onde o bico faz a purga no início da impres
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number label"
msgid "Extruder Print Cooling Fan"
-msgstr ""
+msgstr "Ventoinha de Refrigeração da Impressão"
#: fdmextruder.def.json
msgctxt "machine_extruder_cooling_fan_number description"
msgid "The number of the print cooling fan associated with this extruder. Only change this from the default value of 0 when you have a different print cooling fan for each extruder."
-msgstr ""
+msgstr "O número da ventoinha de refrigeração da impressão associada a este extrusor. Somente altere o valor default de 0 quando você tiver uma ventoinha diferente para cada extrusor."
#: fdmextruder.def.json
msgctxt "platform_adhesion label"
diff --git a/resources/i18n/pt_BR/fdmprinter.def.json.po b/resources/i18n/pt_BR/fdmprinter.def.json.po
index 1b746e8b0b..bd55d331ae 100644
--- a/resources/i18n/pt_BR/fdmprinter.def.json.po
+++ b/resources/i18n/pt_BR/fdmprinter.def.json.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Cura 3.6\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2018-10-29 15:01+0000\n"
-"PO-Revision-Date: 2018-10-02 06:30-0300\n"
+"PO-Revision-Date: 2018-10-06 04:30-0300\n"
"Last-Translator: Cláudio Sampaio \n"
"Language-Team: Cláudio Sampaio \n"
"Language: pt_BR\n"
@@ -16,6 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Poedit 2.0.6\n"
#: fdmprinter.def.json
msgctxt "machine_settings label"
@@ -458,7 +459,7 @@ msgstr "ID do Bico"
#: fdmprinter.def.json
msgctxt "machine_nozzle_id description"
msgid "The nozzle ID for an extruder train, such as \"AA 0.4\" and \"BB 0.8\"."
-msgstr "O identificador do bico para o carro extrusor, tais como \"AA 0.4\" ou \"BB 0.8\""
+msgstr "O identificador do bico para o carro extrusor, tais como \"AA 0.4\" ou \"BB 0.8.\""
#: fdmprinter.def.json
msgctxt "machine_nozzle_size label"
@@ -548,7 +549,7 @@ msgstr "Aceleração Máxima em X"
#: fdmprinter.def.json
msgctxt "machine_max_acceleration_x description"
msgid "Maximum acceleration for the motor of the X-direction"
-msgstr "A aceleração máxima para o motor da impressora na direção X."
+msgstr "A aceleração máxima para o motor da impressora na direção X"
#: fdmprinter.def.json
msgctxt "machine_max_acceleration_y label"
@@ -598,7 +599,7 @@ msgstr "Jerk Default nos eixos X-Y"
#: fdmprinter.def.json
msgctxt "machine_max_jerk_xy description"
msgid "Default jerk for movement in the horizontal plane."
-msgstr "O valor default de jerk para movimentos no plano horizontal"
+msgstr "O valor default de jerk para movimentos no plano horizontal."
#: fdmprinter.def.json
msgctxt "machine_max_jerk_z label"
@@ -1078,7 +1079,7 @@ msgstr "Conectar Polígonos do Topo e Base"
#: fdmprinter.def.json
msgctxt "connect_skin_polygons description"
msgid "Connect top/bottom skin paths where they run next to each other. For the concentric pattern enabling this setting greatly reduces the travel time, but because the connections can happen midway over infill this feature can reduce the top surface quality."
-msgstr ""
+msgstr "Conectar caminhos de contorno da base e topo quando estiverem próximos entre si. Para o padrão concêntrico, habilitar este ajuste reduzirá bastante o tempo de percurso, mas por as conexões poderem acontecer no meio do preenchimento, este recurso pode reduzir a qualidade da superfície superior."
#: fdmprinter.def.json
msgctxt "skin_angles label"
@@ -1498,7 +1499,7 @@ msgstr "Padrão de Preenchimento"
#: fdmprinter.def.json
msgctxt "infill_pattern description"
msgid "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Gyroid, cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction."
-msgstr ""
+msgstr "O padrão do material de preenchimento da impressão. Os preenchimentos de linha e ziguezague mudam de direção em camadas alternadas, reduzindo o custo do material. Os padrões de grade, triângulo, tri-hexágono, cúbico, octeto, quarto cúbico, cruzado e concêntrico são impressos em totalidade a cada camada. Os padrões giróide, cúbico, quarto cúbico e octeto mudam a cada camada para prover uma distribuição mais igualitária de força em cada direção."
#: fdmprinter.def.json
msgctxt "infill_pattern option grid"
@@ -1563,7 +1564,7 @@ msgstr "Cruzado 3D"
#: fdmprinter.def.json
msgctxt "infill_pattern option gyroid"
msgid "Gyroid"
-msgstr ""
+msgstr "Giróide"
#: fdmprinter.def.json
msgctxt "zig_zaggify_infill label"
@@ -1867,7 +1868,7 @@ msgstr "Temperatura Default de Impressão"
#: fdmprinter.def.json
msgctxt "default_material_print_temperature description"
msgid "The default temperature used for printing. This should be the \"base\" temperature of a material. All other print temperatures should use offsets based on this value"
-msgstr "A temperatura default usada para a impressão. Esta deve ser a temperatura \"base\" de um material. Todas as outras temperaturas de impressão devem usar diferenças baseadas neste valor."
+msgstr "A temperatura default usada para a impressão. Esta deve ser a temperatura \"base\" de um material. Todas as outras temperaturas de impressão devem usar diferenças baseadas neste valor"
#: fdmprinter.def.json
msgctxt "material_print_temperature label"
@@ -1957,7 +1958,7 @@ msgstr "Tendência à Aderência"
#: fdmprinter.def.json
msgctxt "material_adhesion_tendency description"
msgid "Surface adhesion tendency."
-msgstr "Tendência de aderência da superfície"
+msgstr "Tendência de aderência da superfície."
#: fdmprinter.def.json
msgctxt "material_surface_energy label"
@@ -2007,7 +2008,7 @@ msgstr "Habilitar Retração"
#: fdmprinter.def.json
msgctxt "retraction_enable description"
msgid "Retract the filament when the nozzle is moving over a non-printed area. "
-msgstr "Retrai o filamento quando o bico está se movendo sobre uma área não impressa."
+msgstr "Retrai o filamento quando o bico está se movendo sobre uma área não impressa. "
#: fdmprinter.def.json
msgctxt "retract_at_layer_change label"
@@ -3272,32 +3273,32 @@ msgstr "Orientação do padrão de preenchimento para suportes. O padrão de pre
#: fdmprinter.def.json
msgctxt "support_brim_enable label"
msgid "Enable Support Brim"
-msgstr ""
+msgstr "Habilitar Brim de Suporte"
#: fdmprinter.def.json
msgctxt "support_brim_enable description"
msgid "Generate a brim within the support infill regions of the first layer. This brim is printed underneath the support, not around it. Enabling this setting increases the adhesion of support to the build plate."
-msgstr ""
+msgstr "Gera o brim dentro das regiões de preenchimento de suporte da primeira camada. Este brim é impresso sob o suporte, não em volta dele. Habilitar este ajuste aumenta a aderência de suporte à mesa de impressão."
#: fdmprinter.def.json
msgctxt "support_brim_width label"
msgid "Support Brim Width"
-msgstr ""
+msgstr "Largura do Brim de Suporte"
#: fdmprinter.def.json
msgctxt "support_brim_width description"
msgid "The width of the brim to print underneath the support. A larger brim enhances adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "A largura do brim a ser impresso sob o suporte. Um brim mais largo melhora a aderência à mesa de impressão, ao custo de material extra."
#: fdmprinter.def.json
msgctxt "support_brim_line_count label"
msgid "Support Brim Line Count"
-msgstr ""
+msgstr "Número de Filetes do Brim de Suporte"
#: fdmprinter.def.json
msgctxt "support_brim_line_count description"
msgid "The number of lines used for the support brim. More brim lines enhance adhesion to the build plate, at the cost of some extra material."
-msgstr ""
+msgstr "O número de filetes usado para o brim de suporte. Mais filetes melhoram a aderência na mesa de impressão, ao custo de material extra."
#: fdmprinter.def.json
msgctxt "support_z_distance label"
@@ -3547,7 +3548,7 @@ msgstr "Densidade da Base do Suporte"
#: fdmprinter.def.json
msgctxt "support_bottom_density description"
msgid "The density of the floors of the support structure. A higher value results in better adhesion of the support on top of the model."
-msgstr "A densidade das bases da estrutura de suporte. Um valor maior resulta em melhor aderência do suporte no topo da superfície"
+msgstr "A densidade das bases da estrutura de suporte. Um valor maior resulta em melhor aderência do suporte no topo da superfície."
#: fdmprinter.def.json
msgctxt "support_bottom_line_distance label"
@@ -3672,7 +3673,7 @@ msgstr "Sobrepor Velocidade de Ventoinha"
#: fdmprinter.def.json
msgctxt "support_fan_enable description"
msgid "When enabled, the print cooling fan speed is altered for the skin regions immediately above the support."
-msgstr "Quando habilitado, a velocidade da ventoinha de resfriamento é alterada para as regiões de contorno imediatamente acima do suporte"
+msgstr "Quando habilitado, a velocidade da ventoinha de resfriamento é alterada para as regiões de contorno imediatamente acima do suporte."
#: fdmprinter.def.json
msgctxt "support_supported_skin_fan_speed label"
@@ -3871,12 +3872,12 @@ msgstr "O número de linhas usada para o brim. Mais linhas de brim melhoram a ad
#: fdmprinter.def.json
msgctxt "brim_replaces_support label"
msgid "Brim Replaces Support"
-msgstr ""
+msgstr "Brim Substitui Suporte"
#: fdmprinter.def.json
msgctxt "brim_replaces_support description"
msgid "Enforce brim to be printed around the model even if that space would otherwise be occupied by support. This replaces some regions of the first layer of support by brim regions."
-msgstr ""
+msgstr "Força que o brim seja impresso em volta do modelo mesmo se este espaço fosse ser ocupado por suporte. Isto substitui algumas regiões da primeira camada de suporte por regiões de brim."
#: fdmprinter.def.json
msgctxt "brim_outside_only label"
@@ -3946,7 +3947,7 @@ msgstr "Espessura da Camada Superior do Raft"
#: fdmprinter.def.json
msgctxt "raft_surface_thickness description"
msgid "Layer thickness of the top raft layers."
-msgstr "Espessura de camada das camadas superiores do raft"
+msgstr "Espessura de camada das camadas superiores do raft."
#: fdmprinter.def.json
msgctxt "raft_surface_line_width label"
@@ -5116,7 +5117,7 @@ msgstr "A distância média entre os pontos aleatórios introduzidos em cada seg
#: fdmprinter.def.json
msgctxt "flow_rate_max_extrusion_offset label"
msgid "Flow rate compensation max extrusion offset"
-msgstr "Deslocamento de extrusão máxima da compensação de taxa de fluxo."
+msgstr "Deslocamento de extrusão máxima da compensação de taxa de fluxo"
#: fdmprinter.def.json
msgctxt "flow_rate_max_extrusion_offset description"
diff --git a/resources/i18n/pt_PT/cura.po b/resources/i18n/pt_PT/cura.po
index 14e7e89801..bcfa154d11 100644
--- a/resources/i18n/pt_PT/cura.po
+++ b/resources/i18n/pt_PT/cura.po
@@ -49,7 +49,7 @@ msgstr "O GCodeWriter não suporta modo sem texto."
#: /home/ruben/Projects/Cura/plugins/GCodeWriter/GCodeWriter.py:89
msgctxt "@warning:status"
msgid "Please prepare G-code before exporting."
-msgstr ""
+msgstr "Prepare um G-code antes de exportar."
#: /home/ruben/Projects/Cura/plugins/ModelChecker/ModelChecker.py:30
msgctxt "@info:title"
@@ -65,11 +65,7 @@ msgid ""
"
{model_names}
\n"
"
Find out how to ensure the best possible print quality and reliability.
"
#: /home/ruben/Projects/Cura/plugins/ChangeLogPlugin/ChangeLog.py:32
msgctxt "@item:inmenu"
@@ -79,7 +75,7 @@ msgstr "Mostrar Lista das Alterações de cada Versão"
#: /home/ruben/Projects/Cura/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py:25
msgctxt "@action"
msgid "Update Firmware"
-msgstr ""
+msgstr "Atualizar firmware"
# rever!
# flatten -ver contexto!
@@ -846,7 +842,7 @@ msgstr "Ficheiro pré-seccionado {0}"
#: /home/ruben/Projects/Cura/cura/API/Account.py:71
msgctxt "@info:title"
msgid "Login failed"
-msgstr ""
+msgstr "Falha no início de sessão"
#: /home/ruben/Projects/Cura/cura/Settings/ContainerManager.py:201
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:121
@@ -920,32 +916,32 @@ msgstr "Falha ao importar perfil de {0}: {1}!"
msgid "No custom profile to import in file {0}"
-msgstr ""
+msgstr "Nenhum perfil personalizado para importar no ficheiro {0}"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:194
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Falha ao importar perfil de {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:218
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:228
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "This profile {0} contains incorrect data, could not import it."
-msgstr ""
+msgstr "O perfil {0} contém dados incorretos, não foi possível importá-lo."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:241
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags !"
msgid "The machine defined in profile {0} ({1}) doesn't match with your current machine ({2}), could not import it."
-msgstr ""
+msgstr "A máquina definida no perfil {0} ({1}) não corresponde à sua máquina atual ({2}), não foi possível importá-la."
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:312
#, python-brace-format
msgctxt "@info:status Don't translate the XML tags or !"
msgid "Failed to import profile from {0}:"
-msgstr ""
+msgstr "Falha ao importar perfil de {0}:"
#: /home/ruben/Projects/Cura/cura/Settings/CuraContainerRegistry.py:315
#, python-brace-format
@@ -1100,12 +1096,7 @@ msgid ""
"
Backups can be found in the configuration folder.
\n"
"
Please send us this Crash Report to fix the problem.
\n"
" "
-msgstr ""
-"
Ups, o Ultimaker Cura encontrou um possível problema.
\n"
-"
Foi encontrado um erro irrecuperável durante o arranque da aplicação. Este pode ter sido causado por alguns ficheiros de configuração incorrectos. Sugerimos que faça um backup e reponha a sua configuração.
\n"
-"
Os backups estão localizados na pasta de configuração.
\n"
-"
Por favor envie-nos este Relatório de Falhas para podermos resolver o problema.
\n"
-" "
+msgstr "
Ups, o Ultimaker Cura encontrou um possível problema.
\n
Foi encontrado um erro irrecuperável durante o arranque da aplicação. Este pode ter sido causado por alguns ficheiros de configuração incorrectos. Sugerimos que faça um backup e reponha a sua configuração.
\n
Os backups estão localizados na pasta de configuração.
\n
Por favor envie-nos este Relatório de Falhas para podermos resolver o problema.
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..35c5f008b6
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml
@@ -0,0 +1,181 @@
+// 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 = UM.Preferences.getValue("view/settings_list_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);
+ }
+ }
+ }
+ }
+}
\ 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..5ae9488cd3
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.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.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"
+ }
+ 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..6885f8c041
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedPrintSetup.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.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
+ }
+ }
+
+ 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/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..9f0d3b4ac6
--- /dev/null
+++ b/resources/qml/PrinterSelector/MachineSelector.qml
@@ -0,0 +1,157 @@
+// 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.activeMachineHasRemoteConnection
+ property bool isPrinterConnected: Cura.MachineManager.printerConnected
+ property var outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
+
+ contentPadding: UM.Theme.getSize("default_lining").width
+ contentAlignment: Cura.ExpandablePopup.ContentAlignment.AlignLeft
+
+ UM.I18nCatalog
+ {
+ id: catalog
+ name: "cura"
+ }
+
+ headerItem: Cura.IconWithText
+ {
+ text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName
+ source:
+ {
+ if (isNetworkPrinter)
+ {
+ if (machineSelector.outputDevice != null && machineSelector.outputDevice.clusterSize > 1)
+ {
+ return UM.Theme.getIcon("printer_group")
+ }
+ return UM.Theme.getIcon("printer_single")
+ }
+ 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: UM.Theme.getIcon("printer_connected")
+ width: UM.Theme.getSize("printer_status_icon").width
+ height: UM.Theme.getSize("printer_status_icon").height
+
+ color: UM.Theme.getColor("primary")
+ visible: isNetworkPrinter && isPrinterConnected
+
+ // 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..b9c20d0de1
--- /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
+ }
+ }
+}
\ No newline at end of file
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 += "