diff --git a/cura/API/Account.py b/cura/API/Account.py
index 64d63c7025..397e220478 100644
--- a/cura/API/Account.py
+++ b/cura/API/Account.py
@@ -38,12 +38,13 @@ class Account(QObject):
self._callback_port = 32118
self._oauth_root = "https://account.ultimaker.com"
+ self._cloud_api_root = "https://api.ultimaker.com"
self._oauth_settings = OAuth2Settings(
OAUTH_SERVER_URL= self._oauth_root,
CALLBACK_PORT=self._callback_port,
CALLBACK_URL="http://localhost:{}/callback".format(self._callback_port),
- CLIENT_ID="um----------------------------ultimaker_cura",
+ CLIENT_ID="um---------------ultimaker_cura_drive_plugin",
CLIENT_SCOPES="account.user.read drive.backup.read drive.backup.write packages.download packages.rating.read packages.rating.write",
AUTH_DATA_PREFERENCE_KEY="general/ultimaker_auth_data",
AUTH_SUCCESS_REDIRECT="{}/app/auth-success".format(self._oauth_root),
diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py
index f837f5cef7..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.
@@ -526,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/CuraApplication.py b/cura/CuraApplication.py
index 95b94c01c7..e59c4e2895 100755
--- a/cura/CuraApplication.py
+++ b/cura/CuraApplication.py
@@ -434,6 +434,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.
@@ -626,9 +627,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
@@ -1659,7 +1658,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/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/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/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py
index ef2e760330..629e5c2b48 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,8 +106,10 @@ class BaseMaterialsModel(ListModel):
return False
extruder_stack = global_stack.extruders[extruder_position]
-
- self._available_materials = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, extruder_stack)
+ available_materials = self._material_manager.getAvailableMaterialsForMachineExtruder(global_stack, extruder_stack)
+ if available_materials == self._available_materials:
+ return False
+ self._available_materials = available_materials
if self._available_materials is None:
return False
diff --git a/cura/Machines/Models/FavoriteMaterialsModel.py b/cura/Machines/Models/FavoriteMaterialsModel.py
index 18fe310c44..cc273e55ce 100644
--- a/cura/Machines/Models/FavoriteMaterialsModel.py
+++ b/cura/Machines/Models/FavoriteMaterialsModel.py
@@ -4,17 +4,14 @@
from UM.Logger import Logger
from cura.Machines.Models.BaseMaterialsModel import BaseMaterialsModel
-class FavoriteMaterialsModel(BaseMaterialsModel):
+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/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/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 22c3eb1734..e863689e21 100644
--- a/cura/PrintInformation.py
+++ b/cura/PrintInformation.py
@@ -394,21 +394,7 @@ 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:
diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py
index 969aa3c460..99c48189cc 100644
--- a/cura/PrinterOutputDevice.py
+++ b/cura/PrinterOutputDevice.py
@@ -211,6 +211,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(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 +243,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 0c03ae615b..661106dec7 100644
--- a/cura/Scene/ConvexHullDecorator.py
+++ b/cura/Scene/ConvexHullDecorator.py
@@ -187,7 +187,10 @@ class ConvexHullDecorator(SceneNodeDecorator):
for child in self._node.getChildren():
child_hull = child.callDecoration("_compute2DConvexHull")
if child_hull:
- points = numpy.append(points, child_hull.getPoints(), axis = 0)
+ try:
+ points = numpy.append(points, child_hull.getPoints(), axis = 0)
+ except ValueError:
+ pass
if points.size < 3:
return None
diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py
index 9089ba96e9..8fa0172305 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"]:
@@ -344,6 +345,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..e19617c8ef 100644
--- a/cura/Settings/ExtrudersModel.py
+++ b/cura/Settings/ExtrudersModel.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 PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, pyqtProperty, QTimer
@@ -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,7 +71,8 @@ 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)
@@ -160,7 +165,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 +177,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 +188,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 +201,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)
@@ -216,6 +224,6 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
"definition": ""
}
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..44ceee9511 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
diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py
index 33c386bae2..c375ce01d1 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
@@ -872,7 +874,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()
@@ -1534,9 +1536,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/Stages/CuraStage.py b/cura/Stages/CuraStage.py
index b2f6d61799..e8537fb6b9 100644
--- a/cura/Stages/CuraStage.py
+++ b/cura/Stages/CuraStage.py
@@ -1,23 +1,33 @@
-# 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):
+ def sidebarComponent(self) -> QUrl:
return self.getDisplayComponent("sidebar")
+
+ @pyqtProperty(QUrl, constant = True)
+ def stageMenuComponent(self) -> QUrl:
+ return self.getDisplayComponent("menu")
\ No newline at end of file
diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py
index 58bc74f3f1..7ede6b6736 100755
--- a/plugins/CuraEngineBackend/CuraEngineBackend.py
+++ b/plugins/CuraEngineBackend/CuraEngineBackend.py
@@ -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()
@@ -322,7 +322,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 +331,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 +362,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 +386,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,16 +395,16 @@ 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
@@ -413,10 +413,10 @@ class CuraEngineBackend(QObject, Backend):
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."),
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 +424,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 +442,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 +451,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 +518,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 +567,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 +613,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 +632,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 9679360ad5..d3882a1209 100644
--- a/plugins/CuraEngineBackend/StartSliceJob.py
+++ b/plugins/CuraEngineBackend/StartSliceJob.py
@@ -323,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/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/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/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml
index 004b4e3cfc..c88a721a84 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
@@ -23,7 +23,7 @@ Cura.MachineAction
target: base.extrudersModel
onModelChanged:
{
- var extruderCount = base.extrudersModel.rowCount();
+ var extruderCount = base.extrudersModel.count;
base.extruderTabsCount = extruderCount;
}
}
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/MonitorStage/MonitorMainView.qml b/plugins/MonitorStage/MonitorMain.qml
similarity index 67%
rename from plugins/MonitorStage/MonitorMainView.qml
rename to plugins/MonitorStage/MonitorMain.qml
index c48f6d0aab..1f287fc0fa 100644
--- a/plugins/MonitorStage/MonitorMainView.qml
+++ b/plugins/MonitorStage/MonitorMain.qml
@@ -1,45 +1,40 @@
-// 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
+ MouseArea
+ {
+ anchors.fill: parent
+ acceptedButtons: Qt.AllButtons
+ onWheel: wheel.accepted = true
+ }
+ }
+
+ 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/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/PostProcessingPlugin/PostProcessingPlugin.qml b/plugins/PostProcessingPlugin/PostProcessingPlugin.qml
index d492e06462..b962f4d53b 100644
--- a/plugins/PostProcessingPlugin/PostProcessingPlugin.qml
+++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.qml
@@ -31,7 +31,7 @@ UM.Dialog
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)
@@ -141,7 +141,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 +175,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 +209,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")
@@ -260,7 +257,7 @@ UM.Dialog
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
@@ -415,7 +412,7 @@ UM.Dialog
}
}
- Cura.SidebarTooltip
+ Cura.PrintSetupTooltip
{
id: tooltip
}
@@ -498,7 +495,6 @@ UM.Dialog
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") :
diff --git a/plugins/PrepareStage/PrepareMenu.qml b/plugins/PrepareStage/PrepareMenu.qml
new file mode 100644
index 0000000000..b7980bc30b
--- /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("toolbar_button_text")
+
+ 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..b22f3385b8 100644
--- a/plugins/PrepareStage/PrepareStage.py
+++ b/plugins/PrepareStage/PrepareStage.py
@@ -2,13 +2,14 @@
# 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)
@@ -16,4 +17,7 @@ class PrepareStage(CuraStage):
def _engineCreated(self):
sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles),
"PrepareSidebar.qml")
+
+ menu_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("PrepareStage"), "PrepareMenu.qml")
+ self.addDisplayComponent("menu", menu_component_path)
self.addDisplayComponent("sidebar", sidebar_component_path)
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..1543536160
--- /dev/null
+++ b/plugins/PreviewStage/PreviewMenu.qml
@@ -0,0 +1,74 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+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
+
+ 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")
+ }
+
+ Loader
+ {
+ id: viewPanel
+ height: parent.height
+ width: childrenRect.width
+ 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..9349da2b0e
--- /dev/null
+++ b/plugins/PreviewStage/plugin.json
@@ -0,0 +1,8 @@
+{
+ "name": "Preview Stage",
+ "author": "Ultimaker B.V.",
+ "version": "1.0.0",
+ "description": "Provides a preview stage in Cura.",
+ "api": 5,
+ "i18n-catalog": "cura"
+}
\ No newline at end of file
diff --git a/plugins/SimulationView/LayerSlider.qml b/plugins/SimulationView/LayerSlider.qml
index 1552506969..42b8cf0ba0 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
}
@@ -167,9 +163,9 @@ Item
id: rangleHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
- x: parent.x - width - UM.Theme.getSize("default_margin").width
+ x: parent.x + parent.width + UM.Theme.getSize("default_margin").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
@@ -275,7 +271,7 @@ Item
id: upperHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
- x: parent.x - width - UM.Theme.getSize("default_margin").width
+ x: parent.x - parent.width - width
anchors.verticalCenter: parent.verticalCenter
target: Qt.point(sliderRoot.width, y + height / 2)
visible: sliderRoot.activeHandle == parent
@@ -385,9 +381,9 @@ Item
id: lowerHandleLabel
height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
- x: parent.x - width - UM.Theme.getSize("default_margin").width
+ x: parent.x - parent.width - width
anchors.verticalCenter: parent.verticalCenter
- target: Qt.point(sliderRoot.width, y + height / 2)
+ target: Qt.point(sliderRoot.width + width, y + height / 2)
visible: sliderRoot.activeHandle == parent
// custom properties
diff --git a/plugins/SimulationView/PathSlider.qml b/plugins/SimulationView/PathSlider.qml
index f3c28fb5f7..c7a43c6407 100644
--- a/plugins/SimulationView/PathSlider.qml
+++ b/plugins/SimulationView/PathSlider.qml
@@ -14,19 +14,17 @@ Item
id: sliderRoot
// handle properties
- property real handleSize: 10
+ property real handleSize: UM.Theme.getSize("slider_handle").width
property real handleRadius: handleSize / 2
- property color handleColor: "black"
- property color handleActiveColor: "white"
- property color rangeColor: "black"
+ property color handleColor: UM.Theme.getColor("slider_handle")
+ property color handleActiveColor: UM.Theme.getColor("slider_handle_active")
+ property color rangeColor: UM.Theme.getColor("slider_groove_fill")
property real handleLabelWidth: width
// track properties
- property real trackThickness: 4 // width of the slider track
- property real trackRadius: trackThickness / 2
- property color trackColor: "white"
- property real trackBorderWidth: 1 // width of the slider track border
- property color trackBorderColor: "black"
+ property real trackThickness: UM.Theme.getSize("slider_groove").width
+ property real trackRadius: UM.Theme.getSize("slider_groove_radius").width
+ property color trackColor: UM.Theme.getColor("slider_groove")
// value properties
property real maximumValue: 100
@@ -68,8 +66,6 @@ Item
radius: sliderRoot.trackRadius
anchors.centerIn: sliderRoot
color: sliderRoot.trackColor
- border.width: sliderRoot.trackBorderWidth
- border.color: sliderRoot.trackBorderColor
visible: sliderRoot.pathsVisible
}
@@ -86,9 +82,10 @@ Item
Rectangle
{
- height: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth
+ height: sliderRoot.trackThickness
width: parent.width + sliderRoot.handleSize
anchors.centerIn: parent
+ radius: sliderRoot.trackRadius
color: sliderRoot.rangeColor
}
}
diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py
index 0ae8b4d9e4..6a0ffc1666 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):
+class SimulationView(CuraView):
# Must match SimulationView.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"))
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..58b2bfe520
--- /dev/null
+++ b/plugins/SimulationView/SimulationViewMenuComponent.qml
@@ -0,0 +1,530 @@
+// 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
+
+ width: UM.Theme.getSize("layerview_menu_size").width
+ 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: Label
+ {
+ id: layerViewTypesLabel
+ text: catalog.i18nc("@label", "Color scheme")
+ font: UM.Theme.getFont("default")
+ color: UM.Theme.getColor("setting_control_text")
+ height: base.height
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ 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: Math.round(UM.Theme.getSize("default_margin").width / 2)
+ width: width
+ }
+
+ Repeater
+ {
+ model: Cura.ExtrudersModel{}
+
+ 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
+
+ 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
+ }
+
+ 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", "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)
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ 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/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/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..7b026566c3 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
@@ -59,6 +59,7 @@ Item
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..edb1967fee 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
@@ -64,6 +64,7 @@ Item
font: UM.Theme.getFont("default_bold")
horizontalAlignment: Text.AlignRight
width: control.width
+ renderType: Text.NativeRendering
}
}
}
diff --git a/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml b/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml
index 9121b97eca..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
@@ -67,6 +67,7 @@ Item
wrapMode: Text.WordWrap
color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("medium")
+ renderType: Text.NativeRendering
}
TableView
@@ -90,7 +91,7 @@ Item
model: packageData.supported_configs
headerDelegate: Rectangle
{
- color: UM.Theme.getColor("sidebar")
+ color: UM.Theme.getColor("main_background")
height: UM.Theme.getSize("toolbox_chart_row").height
Label
{
@@ -99,6 +100,7 @@ Item
text: styleData.value || ""
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("default_bold")
+ renderType: Text.NativeRendering
}
Rectangle
{
@@ -118,6 +120,7 @@ Item
text: styleData.value || ""
color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("default")
+ renderType: Text.NativeRendering
}
}
itemDelegate: Item
@@ -130,6 +133,7 @@ Item
text: styleData.value || ""
color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("default")
+ renderType: Text.NativeRendering
}
}
@@ -144,6 +148,7 @@ Item
elide: Text.ElideRight
color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("default")
+ renderType: Text.NativeRendering
}
}
@@ -228,9 +233,10 @@ Item
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 7b48aaebef..7983be8aef 100644
--- a/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxDetailPage.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
@@ -37,7 +37,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: "white" //Always a white background for image (regardless of theme).
Image
{
anchors.fill: parent
@@ -65,6 +65,7 @@ Item
wrapMode: Text.WordWrap
width: parent.width
height: UM.Theme.getSize("toolbox_property_label").height
+ renderType: Text.NativeRendering
}
Column
@@ -82,26 +83,30 @@ Item
Label
{
text: catalog.i18nc("@label", "Version") + ":"
- 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", "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
@@ -119,8 +124,9 @@ Item
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 +139,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
{
@@ -149,16 +156,18 @@ Item
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
diff --git a/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml b/plugins/Toolbox/resources/qml/ToolboxDetailTile.qml
index 1d701543ce..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,6 +31,7 @@ Item
wrapMode: Text.WordWrap
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("medium_bold")
+ renderType: Text.NativeRendering
}
Label
{
@@ -42,6 +43,7 @@ Item
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..85f0ff8be4 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
@@ -23,8 +23,9 @@ Column
width: parent.width
color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("medium")
+ 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..357e9e9a72 100644
--- a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.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 QtQuick.Layouts 1.3
@@ -52,7 +52,6 @@ Item
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")
@@ -63,6 +62,8 @@ Item
{
width: parent.width - thumbnail.width - parent.spacing
spacing: Math.floor(UM.Theme.getSize("narrow_margin").width)
+ anchors.top: parent.top
+ anchors.topMargin: UM.Theme.getSize("default_margin").height
Label
{
id: name
@@ -71,6 +72,7 @@ Item
wrapMode: Text.WordWrap
color: UM.Theme.getColor("text")
font: UM.Theme.getFont("default_bold")
+ renderType: Text.NativeRendering
}
Label
{
@@ -81,7 +83,8 @@ Item
width: parent.width
wrapMode: Text.WordWrap
color: UM.Theme.getColor("text_medium")
- font: UM.Theme.getFont("very_small")
+ font: UM.Theme.getFont("default")
+ renderType: Text.NativeRendering
}
}
}
diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml
index 46f5debfdd..820b74554a 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
@@ -24,29 +24,33 @@ Rectangle
width: parent.width
color: UM.Theme.getColor("text_medium")
font: UM.Theme.getFont("medium")
+ 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..d1130cf63f 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
@@ -48,8 +48,6 @@ Rectangle
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"
@@ -81,6 +79,7 @@ Rectangle
wrapMode: Text.WordWrap
color: UM.Theme.getColor("button_text")
font: UM.Theme.getFont("medium_bold")
+ renderType: Text.NativeRendering
}
}
MouseArea
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..2d42ca7269 100644
--- a/plugins/Toolbox/resources/qml/ToolboxFooter.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxFooter.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
@@ -26,7 +26,7 @@ Item
right: restartButton.right
rightMargin: UM.Theme.getSize("default_margin").width
}
-
+ renderType: Text.NativeRendering
}
Button
{
@@ -56,6 +56,7 @@ Item
text: control.text
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
+ renderType: Text.NativeRendering
}
}
}
diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml
index e683f89823..e1d01db59a 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")
+ 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..593e024309 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
@@ -51,6 +51,7 @@ Item
wrapMode: Text.WordWrap
font: UM.Theme.getFont("default_bold")
color: pluginInfo.color
+ renderType: Text.NativeRendering
}
Label
{
@@ -60,6 +61,7 @@ Item
width: parent.width
wrapMode: Text.WordWrap
color: pluginInfo.color
+ renderType: Text.NativeRendering
}
}
Column
@@ -88,6 +90,7 @@ 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
@@ -98,6 +101,7 @@ Item
color: UM.Theme.getColor("text")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
+ renderType: Text.NativeRendering
}
}
ToolboxInstalledTileActions
diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml
index 8fd88b1cfd..61af84fbe5 100644
--- a/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxInstalledTileActions.qml
@@ -1,15 +1,18 @@
// Copyright (c) 2018 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher.
-import QtQuick 2.7
+import QtQuick 2.10
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM
+import Cura 1.1 as Cura
+
Column
{
property bool canUpdate: false
property bool canDowngrade: false
+ property bool loginRequired: model.login_required && !Cura.API.account.isLoggedIn
width: UM.Theme.getSize("toolbox_action_button").width
spacing: UM.Theme.getSize("narrow_margin").height
@@ -21,6 +24,7 @@ Column
font: UM.Theme.getFont("default")
wrapMode: Text.WordWrap
width: parent.width
+ renderType: Text.NativeRendering
}
ToolboxProgressButton
@@ -30,59 +34,49 @@ Column
readyLabel: catalog.i18nc("@action:button", "Update")
activeLabel: catalog.i18nc("@action:button", "Updating")
completeLabel: catalog.i18nc("@action:button", "Updated")
- readyAction: function()
+ onReadyAction:
{
toolbox.activePackage = model
toolbox.update(model.id)
}
- activeAction: function()
- {
- toolbox.cancelDownload()
- }
+ onActiveAction: toolbox.cancelDownload()
+
// Don't allow installing while another download is running
- enabled: !(toolbox.isDownloading && toolbox.activePackage != model)
+ enabled: !(toolbox.isDownloading && toolbox.activePackage != model) && !loginRequired
opacity: enabled ? 1.0 : 0.5
visible: canUpdate
}
- Button
+ Label
+ {
+ wrapMode: Text.WordWrap
+ text: catalog.i18nc("@label:The string between and is the highlighted link", "Log in is required to update")
+ font: UM.Theme.getFont("default")
+ color: UM.Theme.getColor("text")
+ linkColor: UM.Theme.getColor("text_link")
+ visible: loginRequired
+ width: updateButton.width
+ renderType: Text.NativeRendering
+
+ MouseArea
+ {
+ anchors.fill: parent
+ onClicked: Cura.API.account.login()
+ }
+ }
+
+ Cura.SecondaryButton
{
id: removeButton
text: canDowngrade ? catalog.i18nc("@action:button", "Downgrade") : catalog.i18nc("@action:button", "Uninstall")
visible: !model.is_bundled && model.is_installed
enabled: !toolbox.isDownloading
- style: ButtonStyle
- {
- background: Rectangle
- {
- implicitWidth: UM.Theme.getSize("toolbox_action_button").width
- implicitHeight: UM.Theme.getSize("toolbox_action_button").height
- color: "transparent"
- border
- {
- width: UM.Theme.getSize("default_lining").width
- color:
- {
- if (control.hovered)
- {
- return UM.Theme.getColor("primary_hover")
- }
- else
- {
- return UM.Theme.getColor("lining")
- }
- }
- }
- }
- label: Label
- {
- text: control.text
- color: UM.Theme.getColor("text")
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- font: UM.Theme.getFont("default")
- }
- }
+
+ width: UM.Theme.getSize("toolbox_action_button").width
+ height: UM.Theme.getSize("toolbox_action_button").height
+
+ fixedWidthMode: true
+
onClicked: toolbox.checkPackageUsageAndUninstall(model.id)
Connections
{
diff --git a/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml b/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml
index b8baf7bc83..40b22c268d 100644
--- a/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxLicenseDialog.qml
@@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher.
-import QtQuick 2.2
+import QtQuick 2.10
import QtQuick.Dialogs 1.1
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
@@ -32,6 +32,7 @@ UM.Dialog
anchors.right: parent.right
text: licenseDialog.pluginName + catalog.i18nc("@label", "This plugin contains a license.\nYou need to accept this license to install this plugin.\nDo you agree with the terms below?")
wrapMode: Text.Wrap
+ renderType: Text.NativeRendering
}
TextArea
{
diff --git a/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml b/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml
index 1ba271dcab..025239bd43 100644
--- a/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxLoadingPage.qml
@@ -1,7 +1,7 @@
// Copyright (c) 2018 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher.
-import QtQuick 2.7
+import QtQuick 2.10
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
@@ -18,5 +18,6 @@ Rectangle
{
centerIn: parent
}
+ renderType: Text.NativeRendering
}
}
diff --git a/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml b/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml
index 2744e40ec9..933e3a5900 100644
--- a/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxProgressButton.qml
@@ -5,6 +5,7 @@ import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import UM 1.1 as UM
+import Cura 1.0 as Cura
Item
@@ -18,16 +19,19 @@ Item
property var activeLabel: catalog.i18nc("@action:button", "Cancel")
property var completeLabel: catalog.i18nc("@action:button", "Installed")
- property var readyAction: null // Action when button is ready and clicked (likely install)
- property var activeAction: null // Action when button is active and clicked (likely cancel)
- property var completeAction: null // Action when button is complete and clicked (likely go to installed)
+ signal readyAction() // Action when button is ready and clicked (likely install)
+ signal activeAction() // Action when button is active and clicked (likely cancel)
+ signal completeAction() // Action when button is complete and clicked (likely go to installed)
width: UM.Theme.getSize("toolbox_action_button").width
height: UM.Theme.getSize("toolbox_action_button").height
- Button
+ Cura.PrimaryButton
{
id: button
+ width: UM.Theme.getSize("toolbox_action_button").width
+ height: UM.Theme.getSize("toolbox_action_button").height
+ fixedWidthMode: true
text:
{
if (complete)
@@ -47,101 +51,15 @@ Item
{
if (complete)
{
- return completeAction()
+ completeAction()
}
else if (active)
{
- return activeAction()
+ activeAction()
}
else
{
- return readyAction()
- }
- }
- style: ButtonStyle
- {
- background: Rectangle
- {
- implicitWidth: UM.Theme.getSize("toolbox_action_button").width
- implicitHeight: UM.Theme.getSize("toolbox_action_button").height
- color:
- {
- if (base.complete)
- {
- return "transparent"
- }
- else
- {
- if (control.hovered)
- {
- return UM.Theme.getColor("primary_hover")
- }
- else
- {
- return UM.Theme.getColor("primary")
- }
- }
- }
- border
- {
- width:
- {
- if (base.complete)
- {
- UM.Theme.getSize("default_lining").width
- }
- else
- {
- return 0
- }
- }
- color:
- {
- if (control.hovered)
- {
- return UM.Theme.getColor("primary_hover")
- }
- else
- {
- return UM.Theme.getColor("lining")
- }
- }
- }
- }
- label: Label
- {
- text: control.text
- color:
- {
- if (base.complete)
- {
- return UM.Theme.getColor("text")
- }
- else
- {
- if (control.hovered)
- {
- return UM.Theme.getColor("button_text_hover")
- }
- else
- {
- return UM.Theme.getColor("button_text")
- }
- }
- }
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- font:
- {
- if (base.complete)
- {
- return UM.Theme.getFont("default")
- }
- else
- {
- return UM.Theme.getFont("default_bold")
- }
- }
+ readyAction()
}
}
}
diff --git a/plugins/Toolbox/resources/qml/ToolboxTabButton.qml b/plugins/Toolbox/resources/qml/ToolboxTabButton.qml
index 22fb6d73ca..5e1aeaa636 100644
--- a/plugins/Toolbox/resources/qml/ToolboxTabButton.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxTabButton.qml
@@ -1,51 +1,51 @@
// Copyright (c) 2018 Ultimaker B.V.
// Toolbox is released under the terms of the LGPLv3 or higher.
-import QtQuick 2.2
-import QtQuick.Controls 1.4
-import QtQuick.Controls.Styles 1.4
+import QtQuick 2.10
+import QtQuick.Controls 2.3
import UM 1.1 as UM
Button
{
+ id: control
property bool active: false
- style: ButtonStyle
+ hoverEnabled: true
+
+ background: Item
{
- background: Rectangle
+ implicitWidth: UM.Theme.getSize("toolbox_header_tab").width
+ implicitHeight: UM.Theme.getSize("toolbox_header_tab").height
+ Rectangle
{
- color: "transparent"
- implicitWidth: UM.Theme.getSize("toolbox_header_tab").width
- implicitHeight: UM.Theme.getSize("toolbox_header_tab").height
- Rectangle
- {
- visible: control.active
- color: UM.Theme.getColor("sidebar_header_highlight_hover")
- anchors.bottom: parent.bottom
- width: parent.width
- height: UM.Theme.getSize("sidebar_header_highlight").height
- }
- }
- label: Label
- {
- text: control.text
- color:
- {
- if(control.hovered)
- {
- return UM.Theme.getColor("topbar_button_text_hovered");
- }
- if(control.active)
- {
- return UM.Theme.getColor("topbar_button_text_active");
- }
- else
- {
- return UM.Theme.getColor("topbar_button_text_inactive");
- }
- }
- font: control.enabled ? (control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")) : UM.Theme.getFont("default_italic")
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
+ visible: control.active
+ color: UM.Theme.getColor("primary")
+ anchors.bottom: parent.bottom
+ width: parent.width
+ height: UM.Theme.getSize("toolbox_header_highlight").height
}
}
-}
+ contentItem: Label
+ {
+ id: label
+ text: control.text
+ color:
+ {
+ if(control.hovered)
+ {
+ return UM.Theme.getColor("toolbox_header_button_text_hovered");
+ }
+ if(control.active)
+ {
+ return UM.Theme.getColor("toolbox_header_button_text_active");
+ }
+ else
+ {
+ return UM.Theme.getColor("toolbox_header_button_text_inactive");
+ }
+ }
+ font: control.enabled ? (control.active ? UM.Theme.getFont("medium_bold") : UM.Theme.getFont("medium")) : UM.Theme.getFont("default_italic")
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ renderType: Text.NativeRendering
+ }
+}
\ No newline at end of file
diff --git a/plugins/Toolbox/src/AuthorsModel.py b/plugins/Toolbox/src/AuthorsModel.py
index bea3893504..877f8256ee 100644
--- a/plugins/Toolbox/src/AuthorsModel.py
+++ b/plugins/Toolbox/src/AuthorsModel.py
@@ -2,18 +2,19 @@
# Cura is released under the terms of the LGPLv3 or higher.
import re
-from typing import Dict
+from typing import Dict, List, Optional, Union
from PyQt5.QtCore import Qt, pyqtProperty, pyqtSignal
from UM.Qt.ListModel import ListModel
+
## Model that holds cura packages. By setting the filter property the instances held by this model can be changed.
class AuthorsModel(ListModel):
- def __init__(self, parent = None):
+ def __init__(self, parent = None) -> None:
super().__init__(parent)
- self._metadata = None
+ self._metadata = None # type: Optional[List[Dict[str, Union[str, List[str], int]]]]
self.addRoleName(Qt.UserRole + 1, "id")
self.addRoleName(Qt.UserRole + 2, "name")
@@ -25,39 +26,40 @@ class AuthorsModel(ListModel):
self.addRoleName(Qt.UserRole + 8, "description")
# List of filters for queries. The result is the union of the each list of results.
- self._filter = {} # type: Dict[str,str]
+ self._filter = {} # type: Dict[str, str]
- def setMetadata(self, data):
- self._metadata = data
- self._update()
+ def setMetadata(self, data: List[Dict[str, Union[str, List[str], int]]]):
+ if self._metadata != data:
+ self._metadata = data
+ self._update()
- def _update(self):
- items = []
+ def _update(self) -> None:
+ items = [] # type: List[Dict[str, Union[str, List[str], int, None]]]
if not self._metadata:
- self.setItems([])
+ self.setItems(items)
return
for author in self._metadata:
items.append({
- "id": author["author_id"],
- "name": author["display_name"],
- "email": author["email"] if "email" in author else None,
- "website": author["website"],
- "package_count": author["package_count"] if "package_count" in author else 0,
- "package_types": author["package_types"] if "package_types" in author else [],
- "icon_url": author["icon_url"] if "icon_url" in author else None,
- "description": "Material and quality profiles from {author_name}".format(author_name = author["display_name"])
+ "id": author.get("author_id"),
+ "name": author.get("display_name"),
+ "email": author.get("email"),
+ "website": author.get("website"),
+ "package_count": author.get("package_count", 0),
+ "package_types": author.get("package_types", []),
+ "icon_url": author.get("icon_url"),
+ "description": "Material and quality profiles from {author_name}".format(author_name = author.get("display_name", ""))
})
# Filter on all the key-word arguments.
for key, value in self._filter.items():
if key is "package_types":
- key_filter = lambda item, value = value: value in item["package_types"]
+ key_filter = lambda item, value = value: value in item["package_types"] # type: ignore
elif "*" in value:
- key_filter = lambda item, key = key, value = value: self._matchRegExp(item, key, value)
+ key_filter = lambda item, key = key, value = value: self._matchRegExp(item, key, value) # type: ignore
else:
- key_filter = lambda item, key = key, value = value: self._matchString(item, key, value)
- items = filter(key_filter, items)
+ key_filter = lambda item, key = key, value = value: self._matchString(item, key, value) # type: ignore
+ items = filter(key_filter, items) # type: ignore
# Execute all filters.
filtered_items = list(items)
diff --git a/plugins/Toolbox/src/PackagesModel.py b/plugins/Toolbox/src/PackagesModel.py
index a31facf75a..bcc02955a2 100644
--- a/plugins/Toolbox/src/PackagesModel.py
+++ b/plugins/Toolbox/src/PackagesModel.py
@@ -33,20 +33,22 @@ 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")
# List of filters for queries. The result is the union of the each list of results.
self._filter = {} # type: Dict[str, str]
def setMetadata(self, data):
- self._metadata = data
- self._update()
+ if self._metadata != data:
+ self._metadata = data
+ self._update()
def _update(self):
items = []
@@ -99,6 +101,7 @@ 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", [])
})
# Filter on all the key-word arguments.
diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py
index 667b28c018..b3c0277658 100644
--- a/plugins/Toolbox/src/Toolbox.py
+++ b/plugins/Toolbox/src/Toolbox.py
@@ -32,8 +32,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__()
@@ -67,31 +67,26 @@ class Toolbox(QObject, Extension):
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:
# ----------------------------------------------------------------------
@@ -176,12 +171,7 @@ class Toolbox(QObject, Extension):
)
self._request_urls = {
"authors": QUrl("{base_url}/authors".format(base_url = self._api_url)),
- "packages": QUrl("{base_url}/packages".format(base_url = self._api_url)),
- "plugins_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)),
- "plugins_available": QUrl("{base_url}/packages?package_type=plugin".format(base_url = self._api_url)),
- "materials_showcase": QUrl("{base_url}/showcase".format(base_url = self._api_url)),
- "materials_available": QUrl("{base_url}/packages?package_type=material".format(base_url = self._api_url)),
- "materials_generic": QUrl("{base_url}/packages?package_type=material&tags=generic".format(base_url = self._api_url))
+ "packages": QUrl("{base_url}/packages".format(base_url = self._api_url))
}
@pyqtSlot()
@@ -199,12 +189,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()
@@ -249,7 +233,7 @@ class Toolbox(QObject, Extension):
"description": plugin_data["plugin"]["description"]
}
return formatted
- except:
+ except KeyError:
Logger.log("w", "Unable to convert plugin meta data %s", str(plugin_data))
return None
@@ -287,13 +271,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)
@@ -447,7 +428,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
@@ -459,11 +440,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)
@@ -513,8 +491,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
@@ -522,7 +500,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
@@ -536,34 +514,30 @@ 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])
+ def _makeRequestByType(self, request_type: str) -> None:
+ Logger.log("i", "Requesting %s metadata from server.", request_type)
+ request = QNetworkRequest(self._request_urls[request_type])
request.setRawHeader(*self._request_header)
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"):
@@ -580,15 +554,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
@@ -614,22 +588,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:
@@ -642,38 +602,32 @@ 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:
# Ignore any operation that is not a get operation
pass
@@ -684,7 +638,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
@@ -694,10 +654,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)
@@ -706,7 +666,6 @@ class Toolbox(QObject, Extension):
return
self.install(file_path)
- return
# Getter & Setters for Properties:
# --------------------------------------------------------------------------
@@ -729,8 +688,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)
@@ -738,16 +698,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:
@@ -755,48 +717,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()
@@ -804,7 +766,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()
@@ -812,21 +774,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"]
@@ -835,30 +797,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/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/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml
index 58443115a9..e5f668c70d 100644
--- a/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml
+++ b/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml
@@ -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)
}
@@ -221,6 +225,7 @@ Cura.MachineAction
text: base.selectedDevice ? base.selectedDevice.name : ""
font: UM.Theme.getFont("large")
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/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
index 9ffb1eabb4..44bd47f904 100644
--- a/plugins/UM3NetworkPrinting/resources/qml/MonitorBuildplateConfiguration.qml
+++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorBuildplateConfiguration.qml
@@ -27,7 +27,7 @@ Item
Row
{
height: parent.height
- spacing: 12 * screenScaleFactor // TODO: Theme! (Should be same as extruder spacing)
+ 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.
@@ -52,7 +52,7 @@ Item
id: buildplateLabel
color: "#191919" // TODO: Theme!
elide: Text.ElideRight
- font: UM.Theme.getFont("very_small") // 12pt, regular
+ font: UM.Theme.getFont("default") // 12pt, regular
text: ""
// FIXED-LINE-HEIGHT:
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;
- }
- background: Rectangle {
- border {
- color: UM.Theme.getColor("monitor_lining_heavy");
- width: UM.Theme.getSize("default_lining").width;
- }
- color: parent.hovered ? UM.Theme.getColor("monitor_card_background_inactive") : UM.Theme.getColor("monitor_card_background");
- implicitHeight: UM.Theme.getSize("default_margin").height * 3;
- implicitWidth: UM.Theme.getSize("default_margin").height * 8;
- }
- contentItem: Label {
- color: UM.Theme.getColor("text");
- font: UM.Theme.getFont("medium");
- horizontalAlignment: Text.AlignHCenter;
- text: parent.text;
- verticalAlignment: Text.AlignVCenter;
- }
- onClicked: {
- overrideConfirmationDialog.visible = true;
- }
- text: catalog.i18nc("@label", "Override");
- visible: {
- if (printJob && printJob.configurationChanges) {
- var length = printJob.configurationChanges.length;
- for (var i = 0; i < length; i++) {
- var typeOfChange = printJob.configurationChanges[i].typeOfChange;
- if (typeOfChange === "material_insert" || typeOfChange === "buildplate_change") {
- return false;
- }
- }
- }
- return true;
- }
- }
- }
- }
-
- MessageDialog {
- id: overrideConfirmationDialog;
- Component.onCompleted: visible = false;
- icon: StandardIcon.Warning;
- onYes: OutputDevice.forceSendJob(printJob.key);
- standardButtons: StandardButton.Yes | StandardButton.No;
- text: {
- if (!printJob) {
- return "";
- }
- var printJobName = formatPrintJobName(printJob.name);
- var confirmText = catalog.i18nc("@label", "Starting a print job with an incompatible configuration could damage your 3D printer. Are you sure you want to override the configuration and print %1?").arg(printJobName);
- return confirmText;
- }
- title: catalog.i18nc("@window:title", "Override configuration configuration and start print");
- }
- }
- }
- }
- // Utils
- function formatPrintJobName(name) {
- var extensions = [ ".gz", ".gcode", ".ufp" ];
- for (var i = 0; i < extensions.length; i++) {
- var extension = extensions[i];
- if (name.slice(-extension.length) === extension) {
- name = name.substring(0, name.length - extension.length);
- }
- }
- return name;
- }
- function materialsAreKnown(job) {
- var conf0 = job.configuration[0];
- if (conf0 && !conf0.material.material) {
- return false;
- }
- var conf1 = job.configuration[1];
- if (conf1 && !conf1.material.material) {
- return false;
- }
- return true;
- }
- function formatBuildPlateType(buildPlateType) {
- var translationText = "";
- switch (buildPlateType) {
- case "glass":
- translationText = catalog.i18nc("@label", "Glass");
- break;
- case "aluminum":
- translationText = catalog.i18nc("@label", "Aluminum");
- break;
- default:
- translationText = null;
- }
- return translationText;
- }
-}
diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml
deleted file mode 100644
index b1a73255f4..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrintJobPreview.qml
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2018 Ultimaker B.V.
-// Cura is released under the terms of the LGPLv3 or higher.
-
-import QtQuick 2.3
-import QtQuick.Dialogs 1.1
-import QtQuick.Controls 2.0
-import QtQuick.Controls.Styles 1.3
-import QtGraphicalEffects 1.0
-import QtQuick.Controls 1.4 as LegacyControls
-import UM 1.3 as UM
-
-// Includes print job name, owner, and preview
-
-Item {
- property var job: null;
- property var useUltibot: false;
- height: 100 * screenScaleFactor;
- width: height;
-
- // Skeleton
- Rectangle {
- anchors.fill: parent;
- color: UM.Theme.getColor("monitor_skeleton_fill");
- radius: UM.Theme.getSize("default_margin").width;
- visible: !job;
- }
-
- // Actual content
- Image {
- id: previewImage;
- visible: job;
- source: job ? job.previewImageUrl : "";
- opacity: {
- if (job == null) {
- return 1.0;
- }
- var states = ["wait_cleanup", "wait_user_action", "error", "paused"];
- if (states.indexOf(job.state) !== -1) {
- return 0.5;
- }
- return 1.0;
- }
- anchors.fill: parent;
- }
-
- UM.RecolorImage {
- id: ultibotImage;
- anchors.centerIn: parent;
- color: UM.Theme.getColor("monitor_placeholder_image"); // TODO: Theme!
- height: parent.height;
- source: "../svg/ultibot.svg";
- sourceSize {
- height: height;
- width: width;
- }
- /* Since print jobs ALWAYS have an image url, we have to check if that image URL errors or
- not in order to determine if we show the placeholder (ultibot) image instead. */
- visible: job && previewImage.status == Image.Error;
- width: parent.width;
- }
-
- UM.RecolorImage {
- id: statusImage;
- anchors.centerIn: parent;
- color: "black"; // TODO: Theme!
- height: Math.round(0.5 * parent.height);
- source: job && job.state == "error" ? "../svg/aborted-icon.svg" : "";
- sourceSize {
- height: height;
- width: width;
- }
- visible: source != "";
- width: Math.round(0.5 * parent.width);
- }
-}
\ No newline at end of file
diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml b/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml
deleted file mode 100644
index f9f7b5ae87..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrintJobTitle.qml
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2018 Ultimaker B.V.
-// Cura is released under the terms of the LGPLv3 or higher.
-
-import QtQuick 2.3
-import QtQuick.Controls 2.0
-import UM 1.3 as UM
-
-Column {
- property var job: null;
- height: childrenRect.height;
- spacing: Math.floor( UM.Theme.getSize("default_margin").height / 2); // TODO: Use explicit theme size
- width: parent.width;
-
- Item {
- id: jobName;
- height: UM.Theme.getSize("monitor_text_line").height;
- width: parent.width;
-
- // Skeleton loading
- Rectangle {
- color: UM.Theme.getColor("monitor_skeleton_fill");
- height: parent.height;
- visible: !job;
- width: Math.round(parent.width / 3);
- }
-
- Label {
- anchors.fill: parent;
- color: UM.Theme.getColor("text");
- elide: Text.ElideRight;
- font: UM.Theme.getFont("default_bold");
- text: job && job.name ? job.name : "";
- visible: job;
- }
- }
-
- Item {
- id: ownerName;
- height: UM.Theme.getSize("monitor_text_line").height;
- width: parent.width;
-
- // Skeleton loading
- Rectangle {
- color: UM.Theme.getColor("monitor_skeleton_fill");
- height: parent.height;
- visible: !job;
- width: Math.round(parent.width / 2);
- }
-
- Label {
- anchors.fill: parent;
- color: UM.Theme.getColor("text")
- elide: Text.ElideRight;
- font: UM.Theme.getFont("default");
- text: job ? job.owner : "";
- visible: job;
- }
- }
-}
\ No newline at end of file
diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml
deleted file mode 100644
index 24beaf70fe..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrinterCard.qml
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright (c) 2018 Ultimaker B.V.
-// Cura is released under the terms of the LGPLv3 or higher.
-
-import QtQuick 2.3
-import QtQuick.Dialogs 1.1
-import QtQuick.Controls 2.0
-import QtQuick.Controls.Styles 1.3
-import QtGraphicalEffects 1.0
-import UM 1.3 as UM
-
-Item {
- id: root;
- property var shadowRadius: UM.Theme.getSize("monitor_shadow_radius").width;
- property var shadowOffset: UM.Theme.getSize("monitor_shadow_offset").width;
- property var printer: null;
- property var collapsed: true;
- height: childrenRect.height + shadowRadius * 2; // Bubbles upward
- width: parent.width; // Bubbles downward
-
- // The actual card (white block)
- Rectangle {
- // 5px margin, but shifted 2px vertically because of the shadow
- anchors {
- bottomMargin: root.shadowRadius + root.shadowOffset;
- leftMargin: root.shadowRadius;
- rightMargin: root.shadowRadius;
- topMargin: root.shadowRadius - root.shadowOffset;
- }
- color: {
- if (!printer) {
- return UM.Theme.getColor("monitor_card_background_inactive");
- }
- if (printer.state == "disabled") {
- return UM.Theme.getColor("monitor_card_background_inactive");
- } else {
- return UM.Theme.getColor("monitor_card_background");
- }
- }
- height: childrenRect.height;
- layer.effect: DropShadow {
- radius: root.shadowRadius;
- verticalOffset: root.shadowOffset;
- color: "#3F000000"; // 25% shadow
- }
- layer.enabled: true
- width: parent.width - 2 * shadowRadius;
-
- Column {
- id: cardContents;
- height: childrenRect.height;
- width: parent.width;
-
- // Main card
- Item {
- id: mainCard;
- anchors {
- left: parent.left;
- leftMargin: UM.Theme.getSize("default_margin").width;
- right: parent.right;
- rightMargin: UM.Theme.getSize("default_margin").width;
- }
- height: 60 * screenScaleFactor + 2 * UM.Theme.getSize("default_margin").height;
- width: parent.width;
-
- // Machine icon
- Item {
- id: machineIcon;
- anchors.verticalCenter: parent.verticalCenter;
- height: parent.height - 2 * UM.Theme.getSize("default_margin").width;
- width: height;
-
- // Skeleton
- Rectangle {
- anchors.fill: parent;
- color: UM.Theme.getColor("monitor_skeleton_fill_dark");
- radius: UM.Theme.getSize("default_margin").width;
- visible: !printer;
- }
-
- // Content
- UM.RecolorImage {
- anchors.centerIn: parent;
- color: {
- if (printer && printer.activePrintJob != undefined) {
- return UM.Theme.getColor("monitor_printer_icon");
- }
- return UM.Theme.getColor("monitor_printer_icon_inactive");
- }
- height: sourceSize.height;
- source: {
- if (!printer) {
- return "";
- }
- switch(printer.type) {
- case "Ultimaker 3":
- return "../svg/UM3-icon.svg";
- case "Ultimaker 3 Extended":
- return "../svg/UM3x-icon.svg";
- case "Ultimaker S5":
- return "../svg/UMs5-icon.svg";
- }
- }
- visible: printer;
- width: sourceSize.width;
- }
- }
-
- // Printer info
- Item {
- id: printerInfo;
- anchors {
- left: machineIcon.right;
- leftMargin: UM.Theme.getSize("wide_margin").width;
- right: collapseIcon.left;
- verticalCenter: machineIcon.verticalCenter;
- }
- height: childrenRect.height;
-
- // Machine name
- Item {
- id: machineNameLabel;
- height: UM.Theme.getSize("monitor_text_line").height;
- width: {
- var percent = printer ? 0.75 : 0.3;
- return Math.round(parent.width * percent);
- }
-
- // Skeleton
- Rectangle {
- anchors.fill: parent;
- color: UM.Theme.getColor("monitor_skeleton_fill_dark");
- visible: !printer;
- }
-
- // Actual content
- Label {
- anchors.fill: parent;
- color: UM.Theme.getColor("text");
- elide: Text.ElideRight;
- font: UM.Theme.getFont("default_bold");
- text: printer ? printer.name : "";
- visible: printer;
- width: parent.width;
- }
- }
-
- // Job name
- Item {
- id: activeJobLabel;
- anchors {
- top: machineNameLabel.bottom;
- topMargin: Math.round(UM.Theme.getSize("default_margin").height / 2);
- }
- height: UM.Theme.getSize("monitor_text_line").height;
- width: Math.round(parent.width * 0.75);
-
- // Skeleton
- Rectangle {
- anchors.fill: parent;
- color: UM.Theme.getColor("monitor_skeleton_fill_dark");
- visible: !printer;
- }
-
- // Actual content
- Label {
- anchors.fill: parent;
- color: UM.Theme.getColor("monitor_text_inactive");
- elide: Text.ElideRight;
- font: UM.Theme.getFont("default");
- text: {
- if (!printer) {
- return "";
- }
- if (printer.state == "disabled") {
- return catalog.i18nc("@label", "Not available");
- } else if (printer.state == "unreachable") {
- return catalog.i18nc("@label", "Unreachable");
- }
- if (printer.activePrintJob != null && printer.activePrintJob.name) {
- return printer.activePrintJob.name;
- }
- return catalog.i18nc("@label", "Available");
- }
- visible: printer;
- }
- }
- }
-
- // Collapse icon
- UM.RecolorImage {
- id: collapseIcon;
- anchors {
- right: parent.right;
- rightMargin: UM.Theme.getSize("default_margin").width;
- verticalCenter: parent.verticalCenter;
- }
- color: UM.Theme.getColor("text");
- height: 15 * screenScaleFactor; // TODO: Theme!
- source: root.collapsed ? UM.Theme.getIcon("arrow_left") : UM.Theme.getIcon("arrow_bottom");
- sourceSize {
- height: height;
- width: width;
- }
- visible: printer;
- width: 15 * screenScaleFactor; // TODO: Theme!
- }
-
- MouseArea {
- anchors.fill: parent;
- enabled: printer;
- onClicked: {
- if (model && root.collapsed) {
- printerList.currentIndex = model.index;
- } else {
- printerList.currentIndex = -1;
- }
- }
- }
-
- Connections {
- target: printerList;
- onCurrentIndexChanged: {
- root.collapsed = printerList.currentIndex != model.index;
- }
- }
- }
- // Detailed card
- PrinterCardDetails {
- collapsed: root.collapsed;
- printer: root.printer;
- visible: root.printer;
- }
-
- // Progress bar
- PrinterCardProgressBar {
- visible: printer && printer.activePrintJob != null;
- width: parent.width;
- }
- }
- }
-}
diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml
deleted file mode 100644
index 31da388b00..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardDetails.qml
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2018 Ultimaker B.V.
-// Cura is released under the terms of the LGPLv3 or higher.
-
-import QtQuick 2.3
-import QtQuick.Dialogs 1.1
-import QtQuick.Controls 2.0
-import QtQuick.Controls.Styles 1.3
-import QtGraphicalEffects 1.0
-import QtQuick.Controls 1.4 as LegacyControls
-import UM 1.3 as UM
-
-Item {
- id: root;
- property var printer: null;
- property var printJob: printer ? printer.activePrintJob : null;
- property var collapsed: true;
- Behavior on height { NumberAnimation { duration: 100 } }
- Behavior on opacity { NumberAnimation { duration: 100 } }
- height: collapsed ? 0 : childrenRect.height;
- opacity: collapsed ? 0 : 1;
- width: parent.width;
-
- Column {
- id: contentColumn;
- anchors {
- left: parent.left;
- leftMargin: UM.Theme.getSize("default_margin").width;
- right: parent.right;
- rightMargin: UM.Theme.getSize("default_margin").width;
- }
- height: childrenRect.height + UM.Theme.getSize("default_margin").height;
- spacing: UM.Theme.getSize("default_margin").height;
- width: parent.width;
-
- HorizontalLine {}
-
- PrinterInfoBlock {
- printer: root.printer;
- printJob: root.printer ? root.printer.activePrintJob : null;
- }
-
- HorizontalLine {}
-
- Row {
- height: childrenRect.height;
- visible: root.printJob;
- width: parent.width;
-
- PrintJobTitle {
- job: root.printer ? root.printer.activePrintJob : null;
- }
- PrintJobContextMenu {
- id: contextButton;
- anchors {
- right: parent.right;
- rightMargin: UM.Theme.getSize("wide_margin").width;
- }
- printJob: root.printer ? root.printer.activePrintJob : null;
- visible: printJob;
- }
- }
-
- PrintJobPreview {
- anchors.horizontalCenter: parent.horizontalCenter;
- job: root.printer && root.printer.activePrintJob ? root.printer.activePrintJob : null;
- visible: root.printJob;
- }
-
- CameraButton {
- id: showCameraButton;
- iconSource: "../svg/camera-icon.svg";
- visible: root.printer;
- }
- }
-}
diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml
deleted file mode 100644
index e86c959b8c..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrinterCardProgressBar.qml
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 2018 Ultimaker B.V.
-// Cura is released under the terms of the LGPLv3 or higher.
-
-import QtQuick 2.3
-import QtQuick.Controls.Styles 1.3
-import QtQuick.Controls 1.4
-import UM 1.3 as UM
-
-ProgressBar {
- property var progress: {
- if (!printer || printer.activePrintJob == null) {
- return 0;
- }
- var result = printer.activePrintJob.timeElapsed / printer.activePrintJob.timeTotal;
- if (result > 1.0) {
- result = 1.0;
- }
- return result;
- }
- style: ProgressBarStyle {
- property var remainingTime: {
- if (!printer || printer.activePrintJob == null) {
- return 0;
- }
- /* Sometimes total minus elapsed is less than 0. Use Math.max() to prevent remaining
- time from ever being less than 0. Negative durations cause strange behavior such
- as displaying "-1h -1m". */
- return Math.max(printer.activePrintJob.timeTotal - printer.activePrintJob.timeElapsed, 0);
- }
- property var progressText: {
- if (printer === null ) {
- return "";
- }
- switch (printer.activePrintJob.state) {
- case "wait_cleanup":
- if (printer.activePrintJob.timeTotal > printer.activePrintJob.timeElapsed) {
- return catalog.i18nc("@label:status", "Aborted");
- }
- return catalog.i18nc("@label:status", "Finished");
- case "pre_print":
- case "sent_to_printer":
- return catalog.i18nc("@label:status", "Preparing");
- case "aborted":
- return catalog.i18nc("@label:status", "Aborted");
- case "wait_user_action":
- return catalog.i18nc("@label:status", "Aborted");
- case "pausing":
- return catalog.i18nc("@label:status", "Pausing");
- case "paused":
- return OutputDevice.formatDuration( remainingTime );
- case "resuming":
- return catalog.i18nc("@label:status", "Resuming");
- case "queued":
- return catalog.i18nc("@label:status", "Action required");
- default:
- return OutputDevice.formatDuration( remainingTime );
- }
- }
- background: Rectangle {
- color: UM.Theme.getColor("monitor_progress_background");
- implicitHeight: visible ? 24 : 0;
- implicitWidth: 100;
- }
- progress: Rectangle {
- id: progressItem;
- color: {
- if (! printer || !printer.activePrintJob) {
- return "black";
- }
- var state = printer.activePrintJob.state
- var inactiveStates = [
- "pausing",
- "paused",
- "resuming",
- "wait_cleanup"
- ];
- if (inactiveStates.indexOf(state) > -1 && remainingTime > 0) {
- return UM.Theme.getColor("monitor_progress_fill_inactive");
- } else {
- return UM.Theme.getColor("monitor_progress_fill");
- }
- }
-
- Label {
- id: progressLabel;
- anchors {
- left: parent.left;
- leftMargin: getTextOffset();
- }
- text: progressText;
- anchors.verticalCenter: parent.verticalCenter;
- color: progressItem.width + progressLabel.width < control.width ? UM.Theme.getColor("text") : UM.Theme.getColor("monitor_progress_fill_text");
- width: contentWidth;
- font: UM.Theme.getFont("default");
- }
-
- function getTextOffset() {
- if (progressItem.width + progressLabel.width + 16 < control.width) {
- return progressItem.width + UM.Theme.getSize("default_margin").width;
- } else {
- return progressItem.width - progressLabel.width - UM.Theme.getSize("default_margin").width;
- }
- }
- }
- }
- value: progress;
- width: parent.width;
-}
\ No newline at end of file
diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml
deleted file mode 100644
index 0a88b053a8..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrinterFamilyPill.qml
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2018 Ultimaker B.V.
-// Cura is released under the terms of the LGPLv3 or higher.
-
-import QtQuick 2.2
-import QtQuick.Controls 1.4
-import UM 1.2 as UM
-
-Item {
- property alias text: familyNameLabel.text;
- property var padding: 3 * screenScaleFactor; // TODO: Theme!
- implicitHeight: familyNameLabel.contentHeight + 2 * padding; // Apply the padding to top and bottom.
- implicitWidth: Math.max(48 * screenScaleFactor, familyNameLabel.contentWidth + implicitHeight); // The extra height is added to ensure the radius doesn't cut something off.
-
- Rectangle {
- id: background;
- anchors {
- horizontalCenter: parent.horizontalCenter;
- right: parent.right;
- }
- color: familyNameLabel.text.length < 1 ? UM.Theme.getColor("monitor_skeleton_fill") : UM.Theme.getColor("monitor_pill_background");
- height: parent.height;
- radius: 0.5 * height;
- width: parent.width;
- }
-
- Label {
- id: familyNameLabel;
- anchors.centerIn: parent;
- color: UM.Theme.getColor("text");
- text: "";
- }
-}
\ No newline at end of file
diff --git a/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml b/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml
deleted file mode 100644
index 92a8f1dcb3..0000000000
--- a/plugins/UM3NetworkPrinting/resources/qml/PrinterInfoBlock.qml
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2018 Ultimaker B.V.
-// Cura is released under the terms of the LGPLv3 or higher.
-
-import QtQuick 2.3
-import QtQuick.Dialogs 1.1
-import QtQuick.Controls 2.0
-import QtQuick.Controls.Styles 1.3
-import QtGraphicalEffects 1.0
-import QtQuick.Controls 1.4 as LegacyControls
-import UM 1.3 as UM
-
-// Includes printer type pill and extuder configurations
-
-Item {
- id: root;
- property var printer: null;
- property var printJob: null;
- width: parent.width;
- height: childrenRect.height;
-
- // Printer family pills
- Row {
- id: printerFamilyPills;
- anchors {
- left: parent.left;
- right: parent.right;
- }
- height: childrenRect.height;
- spacing: Math.round(0.5 * UM.Theme.getSize("default_margin").width);
- width: parent.width;
-
- Repeater {
- id: compatiblePills;
- delegate: PrinterFamilyPill {
- text: modelData;
- }
- model: printJob ? printJob.compatibleMachineFamilies : [];
- visible: printJob;
-
- }
-
- PrinterFamilyPill {
- text: printer ? printer.type : "";
- visible: !compatiblePills.visible && printer;
- }
- }
-
- // Extruder info
- Row {
- id: extrudersInfo;
- anchors {
- left: parent.left;
- right: parent.right;
- rightMargin: UM.Theme.getSize("default_margin").width;
- top: printerFamilyPills.bottom;
- topMargin: UM.Theme.getSize("default_margin").height;
- }
- height: childrenRect.height;
- spacing: UM.Theme.getSize("default_margin").width;
- width: parent.width;
-
- PrintCoreConfiguration {
- width: Math.round(parent.width / 2) * screenScaleFactor;
- printCoreConfiguration: getExtruderConfig(0);
- }
-
- PrintCoreConfiguration {
- width: Math.round(parent.width / 2) * screenScaleFactor;
- printCoreConfiguration: getExtruderConfig(1);
- }
- }
-
- function getExtruderConfig( i ) {
- if (root.printJob) {
- // Use more-specific print job if possible
- return root.printJob.configuration.extruderConfigurations[i];
- }
- if (root.printer) {
- return root.printer.printerConfiguration.extruderConfigurations[i];
- }
- return null;
- }
-}
\ No newline at end of file
diff --git a/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml b/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml
index 105143c851..643c8164a7 100644
--- a/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml
+++ b/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml
@@ -29,7 +29,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 +38,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;
diff --git a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py
index e31229680c..ef890fc4ed 100644
--- a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py
+++ b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py
@@ -64,7 +64,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._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)
@@ -607,17 +607,24 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
def _createMaterialOutputModel(self, material_data: Dict[str, Any]) -> "MaterialOutputModel":
material_manager = CuraApplication.getInstance().getMaterialManager()
- material_group_list = material_manager.getMaterialGroupListByGUID(material_data["guid"])
- # 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.
+ 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 = "Empty" if len(material_data["guid"]) == 0 else "Unknown"
- return MaterialOutputModel(guid = material_data["guid"],
- type = material_data.get("type", ""),
- color = material_data.get("color", ""),
- brand = material_data.get("brand", ""),
- name = material_data.get("name", material_name)
- )
+ 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("type", ""),
+ 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))
@@ -643,9 +650,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/USBPrinting/MonitorItem.qml b/plugins/USBPrinting/MonitorItem.qml
new file mode 100644
index 0000000000..8041698ef0
--- /dev/null
+++ b/plugins/USBPrinting/MonitorItem.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.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
+ {
+ 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..1d42e70366 100644
--- a/plugins/USBPrinting/USBPrinterOutputDevice.py
+++ b/plugins/USBPrinting/USBPrinterOutputDevice.py
@@ -1,5 +1,6 @@
# 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
@@ -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
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/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/resources/bundled_packages/cura.json b/resources/bundled_packages/cura.json
index 33c6304fc5..e1c55992f9 100644
--- a/resources/bundled_packages/cura.json
+++ b/resources/bundled_packages/cura.json
@@ -373,6 +373,23 @@
}
}
},
+ "PreviewStage": {
+ "package_info": {
+ "package_id": "PreviewStage",
+ "package_type": "plugin",
+ "display_name": "Preview Stage",
+ "description": "Provides a preview stage in Cura.",
+ "package_version": "1.0.0",
+ "sdk_version": 5,
+ "website": "https://ultimaker.com",
+ "author": {
+ "author_id": "UltimakerPackages",
+ "display_name": "Ultimaker B.V.",
+ "email": "plugins@ultimaker.com",
+ "website": "https://ultimaker.com"
+ }
+ }
+ },
"RemovableDriveOutputDevice": {
"package_info": {
"package_id": "RemovableDriveOutputDevice",
diff --git a/resources/qml/AboutDialog.qml b/resources/qml/AboutDialog.qml
deleted file mode 100644
index 9a7e53260b..0000000000
--- a/resources/qml/AboutDialog.qml
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright (c) 2015 Ultimaker B.V.
-// Cura is released under the terms of the LGPLv3 or higher.
-
-import QtQuick 2.2
-import QtQuick.Controls 1.1
-import QtQuick.Window 2.1
-
-import UM 1.1 as UM
-
-UM.Dialog
-{
- id: base
-
- //: About dialog title
- title: catalog.i18nc("@title:window","About Cura")
-
- minimumWidth: 500 * screenScaleFactor
- minimumHeight: 650 * screenScaleFactor
- width: minimumWidth
- height: minimumHeight
-
- Rectangle
- {
- width: parent.width + 2 * margin // margin from Dialog.qml
- height: version.y + version.height + margin
-
- anchors.top: parent.top
- anchors.topMargin: - margin
- anchors.horizontalCenter: parent.horizontalCenter
-
- color: UM.Theme.getColor("viewport_background")
- }
-
- Image
- {
- id: logo
- width: (base.minimumWidth * 0.85) | 0
- height: (width * (1/4.25)) | 0
-
- source: UM.Theme.getImage("logo")
-
- sourceSize.width: width
- sourceSize.height: height
- anchors.top: parent.top
- anchors.topMargin: ((base.minimumWidth - width) / 2) | 0
- anchors.horizontalCenter: parent.horizontalCenter
-
- UM.I18nCatalog{id: catalog; name:"cura"}
- }
-
- Label
- {
- id: version
-
- text: catalog.i18nc("@label","version: %1").arg(UM.Application.version)
- font: UM.Theme.getFont("large")
- color: UM.Theme.getColor("text")
- anchors.right : logo.right
- anchors.top: logo.bottom
- anchors.topMargin: (UM.Theme.getSize("default_margin").height / 2) | 0
- }
-
- Label
- {
- id: description
- width: parent.width
-
- //: About dialog application description
- text: catalog.i18nc("@label","End-to-end solution for fused filament 3D printing.")
- font: UM.Theme.getFont("system")
- wrapMode: Text.WordWrap
- anchors.top: version.bottom
- anchors.topMargin: UM.Theme.getSize("default_margin").height
- }
-
- Label
- {
- id: creditsNotes
- width: parent.width
-
- //: About dialog application author note
- text: catalog.i18nc("@info:credit","Cura is developed by Ultimaker B.V. in cooperation with the community.\nCura proudly uses the following open source projects:")
- font: UM.Theme.getFont("system")
- wrapMode: Text.WordWrap
- anchors.top: description.bottom
- anchors.topMargin: UM.Theme.getSize("default_margin").height
- }
-
- ScrollView
- {
- id: credits
- anchors.top: creditsNotes.bottom
- anchors.topMargin: UM.Theme.getSize("default_margin").height
-
- width: parent.width
- height: base.height - y - (2 * UM.Theme.getSize("default_margin").height + closeButton.height)
-
- ListView
- {
- id: projectsList
-
- width: parent.width
-
- delegate: Row
- {
- Label
- {
- text: "%2".arg(model.url).arg(model.name)
- width: (projectsList.width * 0.25) | 0
- elide: Text.ElideRight
- onLinkActivated: Qt.openUrlExternally(link)
- }
- Label
- {
- text: model.description
- elide: Text.ElideRight
- width: (projectsList.width * 0.6) | 0
- }
- Label
- {
- text: model.license
- elide: Text.ElideRight
- width: (projectsList.width * 0.15) | 0
- }
- }
- model: ListModel
- {
- id: projectsModel
- }
- Component.onCompleted:
- {
- projectsModel.append({ name:"Cura", description: catalog.i18nc("@label", "Graphical user interface"), license: "LGPLv3", url: "https://github.com/Ultimaker/Cura" });
- projectsModel.append({ name:"Uranium", description: catalog.i18nc("@label", "Application framework"), license: "LGPLv3", url: "https://github.com/Ultimaker/Uranium" });
- projectsModel.append({ name:"CuraEngine", description: catalog.i18nc("@label", "G-code generator"), license: "AGPLv3", url: "https://github.com/Ultimaker/CuraEngine" });
- projectsModel.append({ name:"libArcus", description: catalog.i18nc("@label", "Interprocess communication library"), license: "LGPLv3", url: "https://github.com/Ultimaker/libArcus" });
-
- projectsModel.append({ name:"Python", description: catalog.i18nc("@label", "Programming language"), license: "Python", url: "http://python.org/" });
- projectsModel.append({ name:"Qt5", description: catalog.i18nc("@label", "GUI framework"), license: "LGPLv3", url: "https://www.qt.io/" });
- projectsModel.append({ name:"PyQt", description: catalog.i18nc("@label", "GUI framework bindings"), license: "GPL", url: "https://riverbankcomputing.com/software/pyqt" });
- projectsModel.append({ name:"SIP", description: catalog.i18nc("@label", "C/C++ Binding library"), license: "GPL", url: "https://riverbankcomputing.com/software/sip" });
- projectsModel.append({ name:"Protobuf", description: catalog.i18nc("@label", "Data interchange format"), license: "BSD", url: "https://developers.google.com/protocol-buffers" });
- projectsModel.append({ name:"SciPy", description: catalog.i18nc("@label", "Support library for scientific computing"), license: "BSD-new", url: "https://www.scipy.org/" });
- projectsModel.append({ name:"NumPy", description: catalog.i18nc("@label", "Support library for faster math"), license: "BSD", url: "http://www.numpy.org/" });
- projectsModel.append({ name:"NumPy-STL", description: catalog.i18nc("@label", "Support library for handling STL files"), license: "BSD", url: "https://github.com/WoLpH/numpy-stl" });
- projectsModel.append({ name:"Shapely", description: catalog.i18nc("@label", "Support library for handling planar objects"), license: "BSD", url: "https://github.com/Toblerity/Shapely" });
- projectsModel.append({ name:"Trimesh", description: catalog.i18nc("@label", "Support library for handling triangular meshes"), license: "MIT", url: "https://trimsh.org" });
- projectsModel.append({ name:"NetworkX", description: catalog.i18nc("@label", "Support library for analysis of complex networks"), license: "3-clause BSD", url: "https://networkx.github.io/" });
- projectsModel.append({ name:"libSavitar", description: catalog.i18nc("@label", "Support library for handling 3MF files"), license: "LGPLv3", url: "https://github.com/ultimaker/libsavitar" });
- projectsModel.append({ name:"libCharon", description: catalog.i18nc("@label", "Support library for file metadata and streaming"), license: "LGPLv3", url: "https://github.com/ultimaker/libcharon" });
- projectsModel.append({ name:"PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" });
- projectsModel.append({ name:"python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" });
- projectsModel.append({ name:"Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" });
- projectsModel.append({ name:"Requests", description: catalog.i18nc("@Label", "Python HTTP library"), license: "GPL", url: "http://docs.python-requests.org" });
-
- projectsModel.append({ name:"Noto Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://www.google.com/get/noto/" });
- projectsModel.append({ name:"Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" });
- projectsModel.append({ name:"AppImageKit", description: catalog.i18nc("@label", "Linux cross-distribution application deployment"), license: "MIT", url: "https://github.com/AppImage/AppImageKit" });
- }
- }
- }
-
- rightButtons: Button
- {
- //: Close about dialog button
- id: closeButton
- text: catalog.i18nc("@action:button","Close");
-
- onClicked: base.visible = false;
- }
-}
diff --git a/resources/qml/Account/AccountDetails.qml b/resources/qml/Account/AccountDetails.qml
new file mode 100644
index 0000000000..bfb23930c6
--- /dev/null
+++ b/resources/qml/Account/AccountDetails.qml
@@ -0,0 +1,69 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+
+import UM 1.4 as UM
+import Cura 1.1 as Cura
+
+Column
+{
+ property var profile: null
+ property var loggedIn: false
+ property var profileImage: ""
+
+ padding: UM.Theme.getSize("wide_margin").height
+ spacing: UM.Theme.getSize("wide_margin").height
+
+ AvatarImage
+ {
+ id: avatar
+ width: UM.Theme.getSize("avatar_image").width
+ height: UM.Theme.getSize("avatar_image").height
+ anchors.horizontalCenter: parent.horizontalCenter
+ source:
+ {
+ if(loggedIn)
+ {
+ if(profileImage)
+ {
+ return profileImage
+ }
+ return UM.Theme.getImage("avatar_no_user")
+ }
+ return UM.Theme.getImage("avatar_no_user")
+ }
+ outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining")
+ }
+
+ Label
+ {
+ id: information
+ anchors.horizontalCenter: parent.horizontalCenter
+ horizontalAlignment: Text.AlignHCenter
+ renderType: Text.NativeRendering
+ text: loggedIn ? profile["username"] : catalog.i18nc("@label", "Please log in or create an account to\nenjoy all features of Ultimaker Cura.")
+ font: loggedIn ? UM.Theme.getFont("large") : UM.Theme.getFont("default")
+ color: UM.Theme.getColor("text")
+ }
+
+ Loader
+ {
+ id: accountOperations
+ anchors.horizontalCenter: parent.horizontalCenter
+ sourceComponent: loggedIn ? userOperations : generalOperations
+ }
+
+ Component
+ {
+ id: userOperations
+ UserOperations { }
+ }
+
+ Component
+ {
+ id: generalOperations
+ GeneralOperations { }
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/Account/AccountWidget.qml b/resources/qml/Account/AccountWidget.qml
new file mode 100644
index 0000000000..d3bd6fd130
--- /dev/null
+++ b/resources/qml/Account/AccountWidget.qml
@@ -0,0 +1,76 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+
+import UM 1.4 as UM
+import Cura 1.1 as Cura
+
+Button
+{
+ id: accountWidget
+ property var profile: Cura.API.account.userProfile
+ property var loggedIn: Cura.API.account.isLoggedIn
+
+ implicitHeight: UM.Theme.getSize("main_window_header").height
+ implicitWidth: UM.Theme.getSize("main_window_header").height
+
+ background: AvatarImage
+ {
+ id: avatar
+
+ width: Math.round(0.8 * accountWidget.width)
+ height: Math.round(0.8 * accountWidget.height)
+ anchors.verticalCenter: accountWidget.verticalCenter
+ anchors.horizontalCenter: accountWidget.horizontalCenter
+
+ source:
+ {
+ if(loggedIn)
+ {
+ if(profile["profile_image_url"])
+ {
+ return profile["profile_image_url"]
+ }
+ return UM.Theme.getImage("avatar_no_user")
+ }
+ return UM.Theme.getImage("avatar_no_user")
+ }
+ outlineColor: loggedIn ? UM.Theme.getColor("account_widget_outline_active") : UM.Theme.getColor("lining")
+ }
+
+ onClicked: popup.opened ? popup.close() : popup.open()
+
+ Popup
+ {
+ id: popup
+
+ y: parent.height + UM.Theme.getSize("default_arrow").height
+ x: parent.width - width
+
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+
+ opacity: opened ? 1 : 0
+ Behavior on opacity { NumberAnimation { duration: 100 } }
+
+ contentItem: AccountDetails
+ {
+ id: panel
+ profile: Cura.API.account.userProfile
+ loggedIn: Cura.API.account.isLoggedIn
+ profileImage: Cura.API.account.profileImageUrl
+ }
+
+ background: UM.PointingRectangle
+ {
+ color: UM.Theme.getColor("tool_panel_background")
+ borderColor: UM.Theme.getColor("lining")
+ borderWidth: UM.Theme.getSize("default_lining").width
+
+ target: Qt.point(width - (accountWidget.width / 2), -10)
+
+ arrowSize: UM.Theme.getSize("default_arrow").width
+ }
+ }
+}
diff --git a/resources/qml/Account/AvatarImage.qml b/resources/qml/Account/AvatarImage.qml
new file mode 100644
index 0000000000..b76aff6990
--- /dev/null
+++ b/resources/qml/Account/AvatarImage.qml
@@ -0,0 +1,56 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+import QtGraphicalEffects 1.0
+
+import UM 1.4 as UM
+
+Item
+{
+ // This item shows the provided image while applying a round mask to it.
+ // It also shows a round border around it. The color is defined by the outlineColor property.
+
+ id: avatar
+
+ property alias source: profileImage.source
+ property alias outlineColor: profileImageOutline.color
+
+ Image
+ {
+ id: profileImage
+ anchors.fill: parent
+ source: UM.Theme.getImage("avatar_default")
+ fillMode: Image.PreserveAspectCrop
+ visible: false
+ mipmap: true
+ }
+
+ Rectangle
+ {
+ id: profileImageMask
+ anchors.fill: parent
+ radius: width
+ }
+
+ OpacityMask
+ {
+ anchors.fill: parent
+ source: profileImage
+ maskSource: profileImageMask
+ cached: true
+ }
+
+ UM.RecolorImage
+ {
+ id: profileImageOutline
+ anchors.centerIn: parent
+ // Make it a bit bigger than it has to, otherwise it sometimes shows a white border.
+ width: parent.width + 2
+ height: parent.height + 2
+ source: UM.Theme.getIcon("circle_outline")
+ sourceSize: Qt.size(parent.width, parent.height)
+ color: UM.Theme.getColor("account_widget_ouline_active")
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/Account/GeneralOperations.qml b/resources/qml/Account/GeneralOperations.qml
new file mode 100644
index 0000000000..b9f1025d5e
--- /dev/null
+++ b/resources/qml/Account/GeneralOperations.qml
@@ -0,0 +1,31 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.2
+import QtQuick.Controls 1.1
+
+import UM 1.4 as UM
+import Cura 1.1 as Cura
+
+Row
+{
+ spacing: UM.Theme.getSize("default_margin").width
+
+ Cura.SecondaryButton
+ {
+ width: UM.Theme.getSize("account_button").width
+ height: UM.Theme.getSize("account_button").height
+ text: catalog.i18nc("@button", "Create account")
+ onClicked: Qt.openUrlExternally("https://account.ultimaker.com/app/create")
+ fixedWidthMode: true
+ }
+
+ Cura.PrimaryButton
+ {
+ width: UM.Theme.getSize("account_button").width
+ height: UM.Theme.getSize("account_button").height
+ text: catalog.i18nc("@button", "Login")
+ onClicked: Cura.API.account.login()
+ fixedWidthMode: true
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/Account/UserOperations.qml b/resources/qml/Account/UserOperations.qml
new file mode 100644
index 0000000000..b9ffa395d6
--- /dev/null
+++ b/resources/qml/Account/UserOperations.qml
@@ -0,0 +1,31 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.2
+import QtQuick.Controls 1.1
+
+import UM 1.4 as UM
+import Cura 1.1 as Cura
+
+Row
+{
+ spacing: UM.Theme.getSize("default_margin").width
+
+ Cura.SecondaryButton
+ {
+ width: UM.Theme.getSize("account_button").width
+ height: UM.Theme.getSize("account_button").height
+ text: catalog.i18nc("@button", "Manage account")
+ onClicked: Qt.openUrlExternally("https://account.ultimaker.com")
+ fixedWidthMode: true
+ }
+
+ Cura.PrimaryButton
+ {
+ width: UM.Theme.getSize("account_button").width
+ height: UM.Theme.getSize("account_button").height
+ text: catalog.i18nc("@button", "Logout")
+ onClicked: Cura.API.account.logout()
+ fixedWidthMode: true
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/ActionButton.qml b/resources/qml/ActionButton.qml
new file mode 100644
index 0000000000..7177120f35
--- /dev/null
+++ b/resources/qml/ActionButton.qml
@@ -0,0 +1,119 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+import QtGraphicalEffects 1.0 // For the dropshadow
+import UM 1.1 as UM
+import Cura 1.0 as Cura
+
+
+Button
+{
+ id: button
+ property bool isIconOnRightSide: false
+
+ property alias iconSource: buttonIconLeft.source
+ property alias textFont: buttonText.font
+ property alias cornerRadius: backgroundRect.radius
+ property alias tooltip: tooltip.text
+ property alias cornerSide: backgroundRect.cornerSide
+
+ property color color: UM.Theme.getColor("primary")
+ property color hoverColor: UM.Theme.getColor("primary_hover")
+ property color disabledColor: color
+ property color textColor: UM.Theme.getColor("button_text")
+ property color textHoverColor: textColor
+ property color textDisabledColor: textColor
+ property color outlineColor: color
+ property color outlineHoverColor: hoverColor
+ property color outlineDisabledColor: outlineColor
+ property alias shadowColor: shadow.color
+ property alias shadowEnabled: shadow.visible
+
+ // This property is used to indicate whether the button has a fixed width or the width would depend on the contents
+ // Be careful when using fixedWidthMode, the translated texts can be too long that they won't fit. In any case,
+ // we elide the text to the right so the text will be cut off with the three dots at the end.
+ property var fixedWidthMode: false
+
+ leftPadding: UM.Theme.getSize("default_margin").width
+ rightPadding: UM.Theme.getSize("default_margin").width
+ height: UM.Theme.getSize("action_button").height
+ hoverEnabled: true
+
+ contentItem: Row
+ {
+ //Left side icon. Only displayed if !isIconOnRightSide.
+ UM.RecolorImage
+ {
+ id: buttonIconLeft
+ source: ""
+ height: buttonText.height
+ width: visible ? height : 0
+ sourceSize.width: width
+ sourceSize.height: height
+ color: button.hovered ? button.textHoverColor : button.textColor
+ visible: source != "" && !button.isIconOnRightSide
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Label
+ {
+ id: buttonText
+ text: button.text
+ color: button.enabled ? (button.hovered ? button.textHoverColor : button.textColor): button.textDisabledColor
+ font: UM.Theme.getFont("action_button")
+ visible: text != ""
+ renderType: Text.NativeRendering
+ anchors.verticalCenter: parent.verticalCenter
+ width: fixedWidthMode ? button.width - button.leftPadding - button.rightPadding : undefined
+ horizontalAlignment: Text.AlignHCenter
+ elide: Text.ElideRight
+ }
+
+ //Right side icon. Only displayed if isIconOnRightSide.
+ UM.RecolorImage
+ {
+ id: buttonIconRight
+ source: buttonIconLeft.source
+ height: buttonText.height
+ width: visible ? height : 0
+ sourceSize.width: width
+ sourceSize.height: height
+ color: buttonIconLeft.color
+ visible: source != "" && button.isIconOnRightSide
+ anchors.verticalCenter: buttonIconLeft.verticalCenter
+ }
+ }
+
+ background: Cura.RoundedRectangle
+ {
+ id: backgroundRect
+ cornerSide: Cura.RoundedRectangle.Direction.All
+ color: button.enabled ? (button.hovered ? button.hoverColor : button.color) : button.disabledColor
+ radius: UM.Theme.getSize("action_button_radius").width
+ border.width: UM.Theme.getSize("default_lining").width
+ border.color: button.enabled ? (button.hovered ? button.outlineHoverColor : button.outlineColor) : button.outlineDisabledColor
+ }
+
+ DropShadow
+ {
+ id: shadow
+ // Don't blur the shadow
+ radius: 0
+ anchors.fill: backgroundRect
+ source: backgroundRect
+ verticalOffset: 2
+ visible: false
+ // Should always be drawn behind the background.
+ z: backgroundRect.z - 1
+ }
+
+ ToolTip
+ {
+ id: tooltip
+ text: ""
+ delay: 500
+ visible: text != "" && button.hovered
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/ActionPanel/ActionPanelWidget.qml b/resources/qml/ActionPanel/ActionPanelWidget.qml
new file mode 100644
index 0000000000..a1cd81e9e9
--- /dev/null
+++ b/resources/qml/ActionPanel/ActionPanelWidget.qml
@@ -0,0 +1,55 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+import UM 1.2 as UM
+import Cura 1.0 as Cura
+
+
+// This element hold all the elements needed for the user to trigger the slicing process, and later
+// to get information about the printing times, material consumption and the output process (such as
+// saving to a file, printing over network, ...
+Rectangle
+{
+ id: actionPanelWidget
+
+ width: UM.Theme.getSize("action_panel_widget").width
+ height: childrenRect.height + 2 * UM.Theme.getSize("thick_margin").height
+
+ color: UM.Theme.getColor("main_background")
+ border.width: UM.Theme.getSize("default_lining").width
+ border.color: UM.Theme.getColor("lining")
+ radius: UM.Theme.getSize("default_radius").width
+
+ property bool outputAvailable: UM.Backend.state == UM.Backend.Done || UM.Backend.state == UM.Backend.Disabled
+
+ Loader
+ {
+ id: loader
+ anchors
+ {
+ top: parent.top
+ topMargin: UM.Theme.getSize("thick_margin").height
+ left: parent.left
+ leftMargin: UM.Theme.getSize("thick_margin").width
+ right: parent.right
+ rightMargin: UM.Theme.getSize("thick_margin").width
+ }
+ sourceComponent: outputAvailable ? outputProcessWidget : sliceProcessWidget
+ }
+
+ Component
+ {
+ id: sliceProcessWidget
+ SliceProcessWidget { }
+ }
+
+ Component
+ {
+ id: outputProcessWidget
+ OutputProcessWidget { }
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/ActionPanel/OutputDevicesActionButton.qml b/resources/qml/ActionPanel/OutputDevicesActionButton.qml
new file mode 100644
index 0000000000..9a6c97bcff
--- /dev/null
+++ b/resources/qml/ActionPanel/OutputDevicesActionButton.qml
@@ -0,0 +1,107 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+import UM 1.1 as UM
+import Cura 1.0 as Cura
+
+Item
+{
+ id: widget
+
+ Cura.PrimaryButton
+ {
+ id: saveToButton
+ height: parent.height
+ fixedWidthMode: true
+ cornerSide: deviceSelectionMenu.visible ? Cura.RoundedRectangle.Direction.Left : Cura.RoundedRectangle.Direction.All
+
+ anchors
+ {
+ top: parent.top
+ left: parent.left
+ right: deviceSelectionMenu.visible ? deviceSelectionMenu.left : parent.right
+ }
+
+ tooltip: UM.OutputDeviceManager.activeDeviceDescription
+
+ text: UM.OutputDeviceManager.activeDeviceShortDescription
+
+ onClicked:
+ {
+ forceActiveFocus();
+ UM.OutputDeviceManager.requestWriteToDevice(UM.OutputDeviceManager.activeDevice, PrintInformation.jobName,
+ { "filter_by_machine": true, "preferred_mimetypes": Cura.MachineManager.activeMachine.preferred_output_file_formats });
+ }
+ }
+
+ Cura.ActionButton
+ {
+ id: deviceSelectionMenu
+ height: parent.height
+
+ shadowEnabled: true
+ shadowColor: UM.Theme.getColor("primary_shadow")
+ cornerSide: Cura.RoundedRectangle.Direction.Right
+
+ anchors
+ {
+ top: parent.top
+ right: parent.right
+ }
+
+ leftPadding: UM.Theme.getSize("narrow_margin").width //Need more space than usual here for wide text.
+ rightPadding: UM.Theme.getSize("narrow_margin").width
+ tooltip: popup.opened ? "" : catalog.i18nc("@info:tooltip", "Select the active output device")
+ iconSource: popup.opened ? UM.Theme.getIcon("arrow_top") : UM.Theme.getIcon("arrow_bottom")
+ color: UM.Theme.getColor("action_panel_secondary")
+ visible: (devicesModel.deviceCount > 1)
+
+ onClicked: popup.opened ? popup.close() : popup.open()
+
+ Popup
+ {
+ id: popup
+ padding: 0
+
+ y: -height
+ x: parent.width - width
+
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+
+ contentItem: ColumnLayout
+ {
+ Repeater
+ {
+ model: devicesModel
+
+ delegate: Cura.ActionButton
+ {
+ text: model.description
+ color: "transparent"
+ cornerRadius: 0
+ hoverColor: UM.Theme.getColor("primary")
+ Layout.fillWidth: true
+ onClicked:
+ {
+ UM.OutputDeviceManager.setActiveDevice(model.id)
+ popup.close()
+ }
+ }
+ }
+ }
+
+ background: Rectangle
+ {
+ opacity: visible ? 1 : 0
+ Behavior on opacity { NumberAnimation { duration: 100 } }
+ color: UM.Theme.getColor("action_panel_secondary")
+ }
+ }
+ }
+
+ UM.OutputDevicesModel { id: devicesModel }
+}
\ No newline at end of file
diff --git a/resources/qml/ActionPanel/OutputProcessWidget.qml b/resources/qml/ActionPanel/OutputProcessWidget.qml
new file mode 100644
index 0000000000..3f53abf28f
--- /dev/null
+++ b/resources/qml/ActionPanel/OutputProcessWidget.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.7
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+import UM 1.1 as UM
+import Cura 1.0 as Cura
+
+
+// This element contains all the elements the user needs to visualize the data
+// that is gather after the slicing process, such as printint time, material usage, ...
+// There are also two buttons: one to previsualize the output layers, and the other to
+// select what to do with it (such as print over network, save to file, ...)
+Column
+{
+ id: widget
+
+ spacing: UM.Theme.getSize("thin_margin").height
+ property bool preSlicedData: PrintInformation.preSliced
+
+ UM.I18nCatalog
+ {
+ id: catalog
+ name: "cura"
+ }
+
+ Item
+ {
+ id: information
+ width: parent.width
+ height: childrenRect.height
+
+ Column
+ {
+ id: timeAndCostsInformation
+ spacing: UM.Theme.getSize("thin_margin").height
+
+ anchors
+ {
+ left: parent.left
+ right: printInformationPanel.left
+ rightMargin: UM.Theme.getSize("thin_margin").height
+ }
+
+ Cura.IconWithText
+ {
+ id: estimatedTime
+ width: parent.width
+
+ text: preSlicedData ? catalog.i18nc("@label", "No time estimation available") : PrintInformation.currentPrintTime.getDisplayString(UM.DurationFormat.Long)
+ source: UM.Theme.getIcon("clock")
+ font: UM.Theme.getFont("default_bold")
+ }
+
+ Cura.IconWithText
+ {
+ id: estimatedCosts
+ width: parent.width
+
+ property var printMaterialLengths: PrintInformation.materialLengths
+ property var printMaterialWeights: PrintInformation.materialWeights
+
+ text:
+ {
+ if (preSlicedData)
+ {
+ return catalog.i18nc("@label", "No cost estimation available")
+ }
+ var totalLengths = 0
+ var totalWeights = 0
+ if (printMaterialLengths)
+ {
+ for(var index = 0; index < printMaterialLengths.length; index++)
+ {
+ if(printMaterialLengths[index] > 0)
+ {
+ totalLengths += printMaterialLengths[index]
+ totalWeights += Math.round(printMaterialWeights[index])
+ }
+ }
+ }
+ return totalWeights + "g ยท " + totalLengths.toFixed(2) + "m"
+ }
+ source: UM.Theme.getIcon("spool")
+ }
+ }
+
+ PrintInformationWidget
+ {
+ id: printInformationPanel
+ visible: !preSlicedData
+
+ anchors
+ {
+ right: parent.right
+ verticalCenter: timeAndCostsInformation.verticalCenter
+ }
+ }
+ }
+
+ Item
+ {
+ id: buttonRow
+ anchors.right: parent.right
+ anchors.left: parent.left
+ height: UM.Theme.getSize("action_button").height
+
+ Cura.SecondaryButton
+ {
+ id: previewStageShortcut
+
+ anchors
+ {
+ left: parent.left
+ right: outputDevicesButton.left
+ rightMargin: UM.Theme.getSize("default_margin").width
+ }
+
+ height: UM.Theme.getSize("action_button").height
+ leftPadding: UM.Theme.getSize("default_margin").width
+ rightPadding: UM.Theme.getSize("default_margin").width
+ text: catalog.i18nc("@button", "Preview")
+
+ onClicked: UM.Controller.setActiveStage("PreviewStage")
+ visible: UM.Controller.activeStage != null && UM.Controller.activeStage.stageId != "PreviewStage"
+
+ shadowEnabled: true
+ shadowColor: UM.Theme.getColor("action_button_disabled_shadow")
+ }
+
+ Cura.OutputDevicesActionButton
+ {
+ id: outputDevicesButton
+
+ anchors.right: parent.right
+ width: previewStageShortcut.visible ? UM.Theme.getSize("action_button").width : parent.width
+ height: UM.Theme.getSize("action_button").height
+ }
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/ActionPanel/PrintInformationWidget.qml b/resources/qml/ActionPanel/PrintInformationWidget.qml
new file mode 100644
index 0000000000..554273a818
--- /dev/null
+++ b/resources/qml/ActionPanel/PrintInformationWidget.qml
@@ -0,0 +1,58 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+
+import UM 1.1 as UM
+import Cura 1.0 as Cura
+
+UM.RecolorImage
+{
+ id: widget
+
+ source: UM.Theme.getIcon("info")
+ width: UM.Theme.getSize("section_icon").width
+ height: UM.Theme.getSize("section_icon").height
+
+ color: popup.opened ? UM.Theme.getColor("primary") : UM.Theme.getColor("text_medium")
+
+ MouseArea
+ {
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: popup.open()
+ onExited: popup.close()
+ }
+
+ Popup
+ {
+ id: popup
+
+ y: -(height + UM.Theme.getSize("default_arrow").height + UM.Theme.getSize("thin_margin").height)
+ x: parent.width - width + UM.Theme.getSize("thin_margin").width
+
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+
+ opacity: opened ? 1 : 0
+ Behavior on opacity { NumberAnimation { duration: 100 } }
+
+ contentItem: PrintJobInformation
+ {
+ id: printJobInformation
+ width: UM.Theme.getSize("action_panel_information_widget").width
+ }
+
+ background: UM.PointingRectangle
+ {
+ color: UM.Theme.getColor("tool_panel_background")
+ borderColor: UM.Theme.getColor("lining")
+ borderWidth: UM.Theme.getSize("default_lining").width
+
+ target: Qt.point(width - (widget.width / 2) - UM.Theme.getSize("thin_margin").width,
+ height + UM.Theme.getSize("default_arrow").height - UM.Theme.getSize("thin_margin").height)
+
+ arrowSize: UM.Theme.getSize("default_arrow").width
+ }
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/ActionPanel/PrintJobInformation.qml b/resources/qml/ActionPanel/PrintJobInformation.qml
new file mode 100644
index 0000000000..8bd5d5a0d3
--- /dev/null
+++ b/resources/qml/ActionPanel/PrintJobInformation.qml
@@ -0,0 +1,159 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.1
+
+import UM 1.1 as UM
+import Cura 1.0 as Cura
+
+Column
+{
+ id: base
+ spacing: UM.Theme.getSize("default_margin").width
+
+ UM.I18nCatalog
+ {
+ id: catalog
+ name: "cura"
+ }
+
+ Column
+ {
+ id: timeSpecification
+ width: parent.width
+ topPadding: UM.Theme.getSize("default_margin").height
+ leftPadding: UM.Theme.getSize("default_margin").width
+ rightPadding: UM.Theme.getSize("default_margin").width
+
+ Label
+ {
+ text: catalog.i18nc("@label", "Time specification").toUpperCase()
+ color: UM.Theme.getColor("primary")
+ font: UM.Theme.getFont("default_bold")
+ renderType: Text.NativeRendering
+ }
+
+ Label
+ {
+ property var printDuration: PrintInformation.currentPrintTime
+
+ text:
+ {
+ // All the time information for the different features is achieved
+ var printTime = PrintInformation.getFeaturePrintTimes()
+ var totalSeconds = parseInt(printDuration.getDisplayString(UM.DurationFormat.Seconds))
+
+ // A message is created and displayed when the user hover the time label
+ var text = "
"
+ for(var feature in printTime)
+ {
+ if(!printTime[feature].isTotalDurationZero)
+ {
+ text += "
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..4ed8daa55c 100644
--- a/resources/qml/PrintMonitor.qml
+++ b/resources/qml/PrintMonitor.qml
@@ -11,136 +11,180 @@ import Cura 1.0 as Cura
import "PrinterOutput"
-Column
+
+Rectangle
{
- 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
+ Cura.ExtrudersModel
{
- id: extrudersGrid
- spacing: UM.Theme.getSize("sidebar_lining_thin").width
+ id: extrudersModel
+ simpleNames: true
+ }
+
+ OutputDeviceHeader
+ {
+ 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..b28c9ceb46
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml
@@ -0,0 +1,133 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.0
+
+import UM 1.3 as UM
+import Cura 1.0 as Cura
+
+
+Item
+{
+ id: customPrintSetup
+ height: childrenRect.height + padding
+
+ property real padding: UM.Theme.getSize("default_margin").width
+ property bool multipleExtruders: extrudersModel.count > 1
+
+ Cura.ExtrudersModel
+ {
+ id: extrudersModel
+ }
+
+ // 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
+ {
+ height: UM.Theme.getSize("print_setup_widget").height
+ anchors
+ {
+ top: tabBar.visible ? tabBar.bottom : globalProfileRow.bottom
+ left: parent.left
+ leftMargin: parent.padding
+ right: parent.right
+ rightMargin: parent.padding
+ topMargin: -UM.Theme.getSize("default_lining").width
+ }
+ 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
+
+ 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..8baaf9a7ae
--- /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("default")
+ 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..599eac957e
--- /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 {}
+
+ Cura.ExtrudersModel
+ {
+ id: extrudersModel
+ }
+
+ contentItem: PrintSetupSelectorContents {}
+}
\ 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..6c678f7ce5
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml
@@ -0,0 +1,129 @@
+// Copyright (c) 2018 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
+
+import QtQuick 2.7
+import QtQuick.Controls 2.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: childrenRect.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
+ }
+ 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
+ {
+ top: buttonsSeparator.bottom
+ left: parent.left
+ right: parent.right
+ }
+
+ Cura.SecondaryButton
+ {
+ 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
+ }
+ }
+}
\ 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..94da5bdd6f
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml
@@ -0,0 +1,83 @@
+// 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 ""
+ }
+
+ 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%"
+
+ 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
+
+ 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
+
+ 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..a5f35f333b
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedAdhesionSelector.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.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")
+ 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..2971415948
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.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.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") + " (%)"
+ 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
+ visible: (index % 20) == 0 // Only show steps of 20%
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: UM.Theme.getSize("thin_margin").height
+ renderType: Text.NativeRendering
+ }
+ }
+ }
+ }
+
+ 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..15d40f545a
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml
@@ -0,0 +1,453 @@
+// 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.SimpleModeSettingsManager.isProfileUserCreated)
+ {
+ qualityModel.qualitySliderActiveIndex = -1
+ }
+ else
+ {
+ qualityModel.qualitySliderActiveIndex = i
+ }
+
+ qualityModel.existingQualityProfile = 1
+ }
+
+ // Set min available
+ if (qualityItem.available && availableMin == -1)
+ {
+ availableMin = i
+ }
+
+ // Set max available
+ if (qualityItem.available)
+ {
+ availableMax = i
+ }
+ }
+
+ // Set total available ticks for active slider part
+ if (availableMin != -1)
+ {
+ qualityModel.availableTotalTicks = availableMax - availableMin + 1
+ }
+
+ // Calculate slider values
+ calculateSliderStepWidth(qualityModel.totalTicks)
+ calculateSliderMargins(availableMin, availableMax, qualityModel.totalTicks)
+
+ qualityModel.qualitySliderAvailableMin = availableMin
+ qualityModel.qualitySliderAvailableMax = availableMax
+ }
+
+ function calculateSliderStepWidth (totalTicks)
+ {
+ // 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")
+ anchors.left: parent.left
+ anchors.right: customisedSettings.left
+ }
+
+ UM.SimpleButton
+ {
+ id: customisedSettings
+
+ visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.SimpleModeSettingsManager.isProfileUserCreated
+ 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))
+ }
+ }
+ }
+ }
+ }
+
+ // 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.SimpleModeSettingsManager.isProfileUserCreated
+ 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.SimpleModeSettingsManager.isProfileUserCreated && qualityModel.existingQualityProfile
+ }
+ }
+
+ onValueChanged:
+ {
+ // only change if an active machine is set and the slider is visible at all.
+ if (Cura.MachineManager.activeMachine != null && visible)
+ {
+ // prevent updating during view initializing. Trigger only if the value changed by user
+ if (qualitySlider.value != qualityModel.qualitySliderActiveIndex && qualityModel.qualitySliderActiveIndex != -1)
+ {
+ // start updating with short delay
+ qualitySliderChangeTimer.start()
+ }
+ }
+ }
+
+ // 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.SimpleModeSettingsManager.isProfileUserCreated
+ }
+ }
+
+ // 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.SimpleModeSettingsManager.isProfileUserCreated
+
+ 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..57e0c8ce6b
--- /dev/null
+++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedSupportSelector.qml
@@ -0,0 +1,204 @@
+// 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")
+ 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
+ Cura.ExtrudersModel
+ {
+ id: 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 93%
rename from resources/qml/SidebarTooltip.qml
rename to resources/qml/PrintSetupTooltip.qml
index 29199481f6..4fa4ef9dd7 100644
--- a/resources/qml/SidebarTooltip.qml
+++ b/resources/qml/PrintSetupTooltip.qml
@@ -36,7 +36,7 @@ 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() {
diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml
index f0abd4cd6c..247bb3a27d 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
diff --git a/resources/qml/PrinterOutput/HeatedBedBox.qml b/resources/qml/PrinterOutput/HeatedBedBox.qml
index 9de66ad0be..33cf5cd1e2 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
@@ -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.
}
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..7ef89dabf7 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")
@@ -30,4 +31,4 @@ Item
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..16280eab5f 100644
--- a/resources/qml/PrinterOutput/OutputDeviceHeader.qml
+++ b/resources/qml/PrinterOutput/OutputDeviceHeader.qml
@@ -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..7cda4f1d2e
--- /dev/null
+++ b/resources/qml/PrinterSelector/MachineSelector.qml
@@ -0,0 +1,174 @@
+// 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.activeMachineNetworkKey != ""
+ 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: Item
+ {
+ implicitHeight: icon.height
+
+ UM.RecolorImage
+ {
+ id: icon
+
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+
+ source:
+ {
+ if (isNetworkPrinter)
+ {
+ if (machineSelector.outputDevice != null && machineSelector.outputDevice.clusterSize > 1)
+ {
+ return UM.Theme.getIcon("printer_group")
+ }
+ return UM.Theme.getIcon("printer_single")
+ }
+ return ""
+ }
+ width: UM.Theme.getSize("machine_selector_icon").width
+ height: width
+
+ color: UM.Theme.getColor("machine_selector_printer_icon")
+ visible: source != ""
+ }
+
+ Label
+ {
+ id: label
+ anchors.left: icon.visible ? icon.right : parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: UM.Theme.getSize("thin_margin").width
+ anchors.verticalCenter: icon.verticalCenter
+ text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName
+ elide: Text.ElideRight
+ color: UM.Theme.getColor("text")
+ font: UM.Theme.getFont("medium")
+ renderType: Text.NativeRendering
+ }
+
+ 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
+
+ onHeightChanged:
+ {
+ scroll.height = Math.min(height, 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..b88af35f82
--- /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("action_button")
+ 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..54d766a6e0
--- /dev/null
+++ b/resources/qml/PrinterSelector/MachineSelectorList.qml
@@ -0,0 +1,84 @@
+// 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
+
+Column
+{
+ id: machineSelectorList
+
+ Label
+ {
+ text: catalog.i18nc("@label", "Connected printers")
+ visible: networkedPrintersModel.items.length > 0
+ leftPadding: UM.Theme.getSize("default_margin").width
+ height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
+ renderType: Text.NativeRendering
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text_medium")
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Repeater
+ {
+ id: networkedPrinters
+
+ model: UM.ContainerStacksModel
+ {
+ id: networkedPrintersModel
+ filter:
+ {
+ "type": "machine", "um_network_key": "*", "hidden": "False"
+ }
+ }
+
+ delegate: MachineSelectorButton
+ {
+ text: model.metadata["connect_group_name"]
+ checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
+ outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
+
+ Connections
+ {
+ target: Cura.MachineManager
+ onActiveMachineNetworkGroupNameChanged: checked = Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
+ }
+ }
+ }
+
+ Label
+ {
+ text: catalog.i18nc("@label", "Preset printers")
+ visible: virtualPrintersModel.items.length > 0
+ leftPadding: UM.Theme.getSize("default_margin").width
+ height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
+ renderType: Text.NativeRendering
+ font: UM.Theme.getFont("medium")
+ color: UM.Theme.getColor("text_medium")
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Repeater
+ {
+ id: virtualPrinters
+
+ model: UM.ContainerStacksModel
+ {
+ id: virtualPrintersModel
+ filter:
+ {
+ "type": "machine", "um_network_key": null
+ }
+ }
+
+ delegate: MachineSelectorButton
+ {
+ text: model.name
+ checked: Cura.MachineManager.activeMachineId == model.id
+ }
+ }
+}
\ No newline at end of file
diff --git a/resources/qml/PrinterTypeLabel.qml b/resources/qml/PrinterTypeLabel.qml
new file mode 100644
index 0000000000..7feae32e16
--- /dev/null
+++ b/resources/qml/PrinterTypeLabel.qml
@@ -0,0 +1,34 @@
+// 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")
+ }
+
+ 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..5676bcedf9 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,18 +56,19 @@ 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
@@ -84,21 +76,27 @@ Button
font: UM.Theme.getFont("setting_category")
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,21 +105,26 @@ 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");
+ 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: base.checked ? UM.Theme.getIcon("arrow_bottom") : UM.Theme.getIcon("arrow_left")
}
@@ -132,24 +135,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 +168,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 +199,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 +211,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 +244,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..13d2a0eb8f 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:
{
diff --git a/resources/qml/Settings/SettingExtruder.qml b/resources/qml/Settings/SettingExtruder.qml
index a9427f863a..e1fedd9274 100644
--- a/resources/qml/Settings/SettingExtruder.qml
+++ b/resources/qml/Settings/SettingExtruder.qml
@@ -19,8 +19,9 @@ SettingItem
model: Cura.ExtrudersModel
{
- onModelChanged: {
- control.color = getItem(control.currentIndex).color;
+ onModelChanged:
+ {
+ control.color = getItem(control.currentIndex).color
}
}
@@ -113,14 +114,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 +155,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 +219,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 += "