diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 49f7e740a9..91e0966fed 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -36,12 +36,12 @@ class CuraActions(QObject): # Starting a web browser from a signal handler connected to a menu will crash on windows. # So instead, defer the call to the next run of the event loop, since that does work. # Note that weirdly enough, only signal handlers that open a web browser fail like that. - event = CallFunctionEvent(self._openUrl, [QUrl("http://ultimaker.com/en/support/software")], {}) + event = CallFunctionEvent(self._openUrl, [QUrl("https://ultimaker.com/en/resources/manuals/software")], {}) cura.CuraApplication.CuraApplication.getInstance().functionEvent(event) @pyqtSlot() def openBugReportPage(self) -> None: - event = CallFunctionEvent(self._openUrl, [QUrl("http://github.com/Ultimaker/Cura/issues")], {}) + event = CallFunctionEvent(self._openUrl, [QUrl("https://github.com/Ultimaker/Cura/issues")], {}) cura.CuraApplication.CuraApplication.getInstance().functionEvent(event) ## Reset camera position and direction to default diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 9ec2435f0b..f927e64044 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -51,7 +51,7 @@ from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob from cura.Arranging.ShapeArray import ShapeArray from cura.MultiplyObjectsJob import MultiplyObjectsJob -from cura.PrintersModel import PrintersModel +from cura.GlobalStacksModel import GlobalStacksModel from cura.Scene.ConvexHullDecorator import ConvexHullDecorator from cura.Operations.SetParentOperation import SetParentOperation from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator @@ -499,7 +499,8 @@ class CuraApplication(QtApplication): preferences.addPreference("cura/choice_on_profile_override", "always_ask") preferences.addPreference("cura/choice_on_open_project", "always_ask") preferences.addPreference("cura/use_multi_build_plate", False) - + preferences.addPreference("view/settings_list_height", 400) + preferences.addPreference("view/settings_visible", False) preferences.addPreference("cura/currency", "€") preferences.addPreference("cura/material_settings", "{}") @@ -971,7 +972,7 @@ class CuraApplication(QtApplication): qmlRegisterType(MultiBuildPlateModel, "Cura", 1, 0, "MultiBuildPlateModel") qmlRegisterType(InstanceContainer, "Cura", 1, 0, "InstanceContainer") qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel") - qmlRegisterType(PrintersModel, "Cura", 1, 0, "PrintersModel") + qmlRegisterType(GlobalStacksModel, "Cura", 1, 0, "GlobalStacksModel") qmlRegisterType(FavoriteMaterialsModel, "Cura", 1, 0, "FavoriteMaterialsModel") qmlRegisterType(GenericMaterialsModel, "Cura", 1, 0, "GenericMaterialsModel") diff --git a/cura/PrintersModel.py b/cura/GlobalStacksModel.py similarity index 88% rename from cura/PrintersModel.py rename to cura/GlobalStacksModel.py index 8b5d2f6cc9..939809151d 100644 --- a/cura/PrintersModel.py +++ b/cura/GlobalStacksModel.py @@ -12,7 +12,8 @@ from cura.PrinterOutputDevice import ConnectionType from cura.Settings.GlobalStack import GlobalStack -class PrintersModel(ListModel): + +class GlobalStacksModel(ListModel): NameRole = Qt.UserRole + 1 IdRole = Qt.UserRole + 2 HasRemoteConnectionRole = Qt.UserRole + 3 @@ -41,21 +42,14 @@ class PrintersModel(ListModel): if isinstance(container, GlobalStack): self._update() - ## Handler for container name change events. - def _onContainerNameChanged(self): - self._update() - def _update(self) -> None: items = [] - for container in self._container_stacks: - container.nameChanged.disconnect(self._onContainerNameChanged) container_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine") for container_stack in container_stacks: - connection_type = container_stack.getMetaDataEntry("connection_type") + connection_type = int(container_stack.getMetaDataEntry("connection_type", ConnectionType.NotConnected.value)) has_remote_connection = connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value] - if container_stack.getMetaDataEntry("hidden", False) in ["True", True]: continue diff --git a/cura/Machines/MaterialManager.py b/cura/Machines/MaterialManager.py index aee96f3153..4d9574bf38 100644 --- a/cura/Machines/MaterialManager.py +++ b/cura/Machines/MaterialManager.py @@ -302,6 +302,10 @@ class MaterialManager(QObject): def getMaterialGroupListByGUID(self, guid: str) -> Optional[List[MaterialGroup]]: return self._guid_material_groups_map.get(guid) + # Returns a dict of all material groups organized by root_material_id. + def getAllMaterialGroups(self) -> Dict[str, "MaterialGroup"]: + return self._material_group_map + # # Return a dict with all root material IDs (k) and ContainerNodes (v) that's suitable for the given setup. # diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py index 747882b041..7ccc886bfe 100644 --- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QTimer from UM.Application import Application from UM.Logger import Logger @@ -39,15 +39,23 @@ class QualityProfilesDropDownMenuModel(ListModel): self._machine_manager = self._application.getMachineManager() self._quality_manager = Application.getInstance().getQualityManager() - self._application.globalContainerStackChanged.connect(self._update) - self._machine_manager.activeQualityGroupChanged.connect(self._update) - self._machine_manager.extruderChanged.connect(self._update) - self._quality_manager.qualitiesUpdated.connect(self._update) + self._application.globalContainerStackChanged.connect(self._onChange) + self._machine_manager.activeQualityGroupChanged.connect(self._onChange) + self._machine_manager.extruderChanged.connect(self._onChange) + self._quality_manager.qualitiesUpdated.connect(self._onChange) self._layer_height_unit = "" # This is cached + self._update_timer = QTimer() # type: QTimer + self._update_timer.setInterval(100) + self._update_timer.setSingleShot(True) + self._update_timer.timeout.connect(self._update) + self._update() + def _onChange(self) -> None: + self._update_timer.start() + def _update(self): Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) diff --git a/cura/Machines/Models/SettingVisibilityPresetsModel.py b/cura/Machines/Models/SettingVisibilityPresetsModel.py index 79131521f2..baa8e3ed29 100644 --- a/cura/Machines/Models/SettingVisibilityPresetsModel.py +++ b/cura/Machines/Models/SettingVisibilityPresetsModel.py @@ -6,6 +6,7 @@ from typing import Optional, List from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from UM.Logger import Logger +from UM.Preferences import Preferences from UM.Resources import Resources from UM.i18n import i18nCatalog @@ -18,14 +19,20 @@ class SettingVisibilityPresetsModel(QObject): onItemsChanged = pyqtSignal() activePresetChanged = pyqtSignal() - def __init__(self, preferences, parent = None): + def __init__(self, preferences: Preferences, parent = None) -> None: super().__init__(parent) self._items = [] # type: List[SettingVisibilityPreset] + self._custom_preset = SettingVisibilityPreset(preset_id = "custom", name = "Custom selection", weight = -100) + self._populate() basic_item = self.getVisibilityPresetById("basic") - basic_visibile_settings = ";".join(basic_item.settings) + if basic_item is not None: + basic_visibile_settings = ";".join(basic_item.settings) + else: + Logger.log("w", "Unable to find the basic visiblity preset.") + basic_visibile_settings = "" self._preferences = preferences @@ -42,7 +49,8 @@ class SettingVisibilityPresetsModel(QObject): visible_settings = self._preferences.getValue("general/visible_settings") if not visible_settings: - self._preferences.setValue("general/visible_settings", ";".join(self._active_preset_item.settings)) + new_visible_settings = self._active_preset_item.settings if self._active_preset_item is not None else [] + self._preferences.setValue("general/visible_settings", ";".join(new_visible_settings)) else: self._onPreferencesChanged("general/visible_settings") @@ -59,9 +67,7 @@ class SettingVisibilityPresetsModel(QObject): def _populate(self) -> None: from cura.CuraApplication import CuraApplication items = [] # type: List[SettingVisibilityPreset] - - custom_preset = SettingVisibilityPreset(preset_id="custom", name ="Custom selection", weight = -100) - items.append(custom_preset) + items.append(self._custom_preset) for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.SettingVisibilityPreset): setting_visibility_preset = SettingVisibilityPreset() try: @@ -77,7 +83,7 @@ class SettingVisibilityPresetsModel(QObject): self.setItems(items) @pyqtProperty("QVariantList", notify = onItemsChanged) - def items(self): + def items(self) -> List[SettingVisibilityPreset]: return self._items def setItems(self, items: List[SettingVisibilityPreset]) -> None: @@ -87,7 +93,7 @@ class SettingVisibilityPresetsModel(QObject): @pyqtSlot(str) def setActivePreset(self, preset_id: str) -> None: - if preset_id == self._active_preset_item.presetId: + if self._active_preset_item is not None and preset_id == self._active_preset_item.presetId: Logger.log("d", "Same setting visibility preset [%s] selected, do nothing.", preset_id) return @@ -96,7 +102,7 @@ class SettingVisibilityPresetsModel(QObject): Logger.log("w", "Tried to set active preset to unknown id [%s]", preset_id) return - need_to_save_to_custom = self._active_preset_item.presetId == "custom" and preset_id != "custom" + need_to_save_to_custom = self._active_preset_item is None or (self._active_preset_item.presetId == "custom" and preset_id != "custom") if need_to_save_to_custom: # Save the current visibility settings to custom current_visibility_string = self._preferences.getValue("general/visible_settings") @@ -117,7 +123,9 @@ class SettingVisibilityPresetsModel(QObject): @pyqtProperty(str, notify = activePresetChanged) def activePreset(self) -> str: - return self._active_preset_item.presetId + if self._active_preset_item is not None: + return self._active_preset_item.presetId + return "" def _onPreferencesChanged(self, name: str) -> None: if name != "general/visible_settings": @@ -149,7 +157,12 @@ class SettingVisibilityPresetsModel(QObject): else: item_to_set = matching_preset_item + # If we didn't find a matching preset, fallback to custom. + if item_to_set is None: + item_to_set = self._custom_preset + if self._active_preset_item is None or self._active_preset_item.presetId != item_to_set.presetId: self._active_preset_item = item_to_set - self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item.presetId) + if self._active_preset_item is not None: + self._preferences.setValue("cura/active_setting_visibility_preset", self._active_preset_item.presetId) self.activePresetChanged.emit() diff --git a/cura/OAuth2/AuthorizationService.py b/cura/OAuth2/AuthorizationService.py index 4355891139..a055254891 100644 --- a/cura/OAuth2/AuthorizationService.py +++ b/cura/OAuth2/AuthorizationService.py @@ -83,9 +83,11 @@ class AuthorizationService: if not self.getUserProfile(): # We check if we can get the user profile. # If we can't get it, that means the access token (JWT) was invalid or expired. + Logger.log("w", "Unable to get the user profile.") return None if self._auth_data is None: + Logger.log("d", "No auth data to retrieve the access_token from") return None return self._auth_data.access_token diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 3102d73bb0..99e8835c2f 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -36,7 +36,7 @@ class ConnectionState(IntEnum): class ConnectionType(IntEnum): - Unknown = 0 + NotConnected = 0 UsbConnection = 1 NetworkConnection = 2 CloudConnection = 3 @@ -74,7 +74,7 @@ class PrinterOutputDevice(QObject, OutputDevice): # Signal to indicate that the configuration of one of the printers has changed. uniqueConfigurationsChanged = pyqtSignal() - def __init__(self, device_id: str, connection_type: "ConnectionType" = ConnectionType.Unknown, parent: QObject = None) -> None: + def __init__(self, device_id: str, connection_type: "ConnectionType" = ConnectionType.NotConnected, parent: QObject = None) -> None: super().__init__(device_id = device_id, parent = parent) # type: ignore # MyPy complains with the multiple inheritance self._printers = [] # type: List[PrinterOutputModel] @@ -230,7 +230,7 @@ class PrinterOutputDevice(QObject, OutputDevice): # 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])) + return list(sorted(set([configuration.printerType for configuration in self._unique_configurations]))) def _onPrintersChanged(self) -> None: for printer in self._printers: diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index cd8ca09447..32b83ead28 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -299,6 +299,7 @@ class MachineManager(QObject): self.activeMaterialChanged.emit() self.rootMaterialChanged.emit() + self.numberExtrudersEnabledChanged.emit() def _onContainersChanged(self, container: ContainerInterface) -> None: self._instance_container_timer.start() @@ -526,7 +527,7 @@ class MachineManager(QObject): @pyqtProperty(bool, notify = printerConnectedStatusChanged) def activeMachineHasRemoteConnection(self) -> bool: if self._global_container_stack: - connection_type = self._global_container_stack.getMetaDataEntry("connection_type") + connection_type = int(self._global_container_stack.getMetaDataEntry("connection_type", ConnectionType.NotConnected.value)) return connection_type in [ConnectionType.NetworkConnection.value, ConnectionType.CloudConnection.value] return False diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 7ede6b6736..f12a5b1222 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -86,8 +86,8 @@ class CuraEngineBackend(QObject, Backend): self._layer_view_active = False #type: bool self._onActiveViewChanged() - self._stored_layer_data = [] #type: List[Arcus.PythonMessage] - self._stored_optimized_layer_data = {} #type: Dict[int, List[Arcus.PythonMessage]] # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob + self._stored_layer_data = [] # type: List[Arcus.PythonMessage] + self._stored_optimized_layer_data = {} # type: Dict[int, List[Arcus.PythonMessage]] # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob self._scene = self._application.getController().getScene() #type: Scene self._scene.sceneChanged.connect(self._onSceneChanged) @@ -229,6 +229,7 @@ class CuraEngineBackend(QObject, Backend): if not self._build_plates_to_be_sliced: self.processingProgress.emit(1.0) Logger.log("w", "Slice unnecessary, nothing has changed that needs reslicing.") + self.setState(BackendState.Done) return if self._process_layers_job: @@ -245,7 +246,7 @@ class CuraEngineBackend(QObject, Backend): num_objects = self._numObjectsPerBuildPlate() self._stored_layer_data = [] - self._stored_optimized_layer_data[build_plate_to_be_sliced] = [] + if build_plate_to_be_sliced not in num_objects or num_objects[build_plate_to_be_sliced] == 0: self._scene.gcode_dict[build_plate_to_be_sliced] = [] #type: ignore #Because we created this attribute above. @@ -253,7 +254,7 @@ class CuraEngineBackend(QObject, Backend): if self._build_plates_to_be_sliced: self.slice() return - + self._stored_optimized_layer_data[build_plate_to_be_sliced] = [] if self._application.getPrintInformation() and build_plate_to_be_sliced == active_build_plate: self._application.getPrintInformation().setToZeroPrintInformation(build_plate_to_be_sliced) @@ -410,7 +411,7 @@ class CuraEngineBackend(QObject, Backend): if job.getResult() == StartJobResult.NothingToSlice: if self._application.platformActivity: - self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit."), + self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume or are assigned to a disabled extruder. Please scale or rotate models to fit, or enable an extruder."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.setState(BackendState.Error) diff --git a/plugins/MonitorStage/MonitorMain.qml b/plugins/MonitorStage/MonitorMain.qml index 8f113735ee..5fda32db9e 100644 --- a/plugins/MonitorStage/MonitorMain.qml +++ b/plugins/MonitorStage/MonitorMain.qml @@ -1,4 +1,5 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.10 import QtQuick.Controls 1.4 @@ -7,23 +8,27 @@ 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 { - // We show a nice overlay on the 3D viewer when the current output device has no monitor view - Rectangle - { - id: viewportOverlay + id: viewportOverlay - color: UM.Theme.getColor("viewport_overlay") + color: UM.Theme.getColor("viewport_overlay") + anchors.fill: parent + + // This mouse area is to prevent mouse clicks to be passed onto the scene. + MouseArea + { anchors.fill: parent - MouseArea - { - anchors.fill: parent - acceptedButtons: Qt.AllButtons - onWheel: wheel.accepted = true - } + acceptedButtons: Qt.AllButtons + onWheel: wheel.accepted = true } + // Disable dropping files into Cura when the monitor page is active + DropArea + { + anchors.fill: parent + } Loader { id: monitorViewComponent @@ -37,4 +42,4 @@ Item sourceComponent: Cura.MachineManager.printerOutputDevices.length > 0 ? Cura.MachineManager.printerOutputDevices[0].monitorItem : null } -} +} \ No newline at end of file diff --git a/plugins/PostProcessingPlugin/PostProcessingPlugin.qml b/plugins/PostProcessingPlugin/PostProcessingPlugin.qml index b962f4d53b..d5fe618b2d 100644 --- a/plugins/PostProcessingPlugin/PostProcessingPlugin.qml +++ b/plugins/PostProcessingPlugin/PostProcessingPlugin.qml @@ -25,7 +25,7 @@ UM.Dialog { if(!visible) //Whenever the window is closed (either via the "Close" button or the X on the window frame), we want to update it in the stack. { - manager.writeScriptsToStack(); + manager.writeScriptsToStack() } } @@ -61,18 +61,23 @@ UM.Dialog anchors.leftMargin: base.textMargin anchors.right: parent.right anchors.rightMargin: base.textMargin - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") elide: Text.ElideRight } ListView { id: activeScriptsList - anchors.top: activeScriptsHeader.bottom - anchors.topMargin: base.textMargin - anchors.left: parent.left - anchors.leftMargin: UM.Theme.getSize("default_margin").width - anchors.right: parent.right - anchors.rightMargin: base.textMargin + + anchors + { + top: activeScriptsHeader.bottom + left: parent.left + right: parent.right + rightMargin: base.textMargin + topMargin: base.textMargin + leftMargin: UM.Theme.getSize("default_margin").width + } + height: childrenRect.height model: manager.scriptList delegate: Item @@ -84,8 +89,12 @@ UM.Dialog id: activeScriptButton text: manager.getScriptLabelByKey(modelData.toString()) exclusiveGroup: selectedScriptGroup + width: parent.width + height: UM.Theme.getSize("setting").height checkable: true - checked: { + + checked: + { if (manager.selectedScriptIndex == index) { base.activeScriptName = manager.getScriptLabelByKey(modelData.toString()) @@ -102,8 +111,7 @@ UM.Dialog manager.setSelectedScriptIndex(index) base.activeScriptName = manager.getScriptLabelByKey(modelData.toString()) } - width: parent.width - height: UM.Theme.getSize("setting").height + style: ButtonStyle { background: Rectangle @@ -121,6 +129,7 @@ UM.Dialog } } } + Button { id: removeButton @@ -249,8 +258,8 @@ UM.Dialog onTriggered: manager.addScriptToList(modelData.toString()) } - onObjectAdded: scriptsMenu.insertItem(index, object); - onObjectRemoved: scriptsMenu.removeItem(object); + onObjectAdded: scriptsMenu.insertItem(index, object) + onObjectRemoved: scriptsMenu.removeItem(object) } } } @@ -268,26 +277,35 @@ UM.Dialog { id: scriptSpecsHeader text: manager.selectedScriptIndex == -1 ? catalog.i18nc("@label", "Settings") : base.activeScriptName - anchors.top: parent.top - anchors.topMargin: base.textMargin - anchors.left: parent.left - anchors.leftMargin: base.textMargin - anchors.right: parent.right - anchors.rightMargin: base.textMargin + anchors + { + top: parent.top + topMargin: base.textMargin + left: parent.left + leftMargin: base.textMargin + right: parent.right + rightMargin: base.textMargin + } + elide: Text.ElideRight height: 20 * screenScaleFactor - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") } ScrollView { id: scrollView - anchors.top: scriptSpecsHeader.bottom - anchors.topMargin: settingsPanel.textMargin - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: parent.bottom + anchors + { + top: scriptSpecsHeader.bottom + topMargin: settingsPanel.textMargin + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + right: parent.right + bottom: parent.bottom + } + visible: manager.selectedScriptDefinitionId != "" style: UM.Theme.styles.scrollview; @@ -297,11 +315,12 @@ UM.Dialog spacing: UM.Theme.getSize("default_lining").height model: UM.SettingDefinitionsModel { - id: definitionsModel; + id: definitionsModel containerId: manager.selectedScriptDefinitionId showAll: true } - delegate:Loader + + delegate: Loader { id: settingLoader @@ -312,23 +331,24 @@ UM.Dialog { if(model.type != undefined) { - return UM.Theme.getSize("section").height; + return UM.Theme.getSize("section").height } else { - return 0; + return 0 } } else { - return 0; + return 0 } - } Behavior on height { NumberAnimation { duration: 100 } } opacity: provider.properties.enabled == "True" ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 100 } } enabled: opacity > 0 + property var definition: model property var settingDefinitionsModel: definitionsModel property var propertyProvider: provider @@ -339,11 +359,12 @@ UM.Dialog //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. asynchronous: model.type != "enum" && model.type != "extruder" - onLoaded: { + onLoaded: + { settingLoader.item.showRevertButton = false settingLoader.item.showInheritButton = false settingLoader.item.showLinkedSettingIcon = false - settingLoader.item.doDepthIndentation = true + settingLoader.item.doDepthIndentation = false settingLoader.item.doQualityUserSettingEmphasis = false } @@ -395,18 +416,14 @@ UM.Dialog onShowTooltip: { - tooltip.text = text; - var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0); - tooltip.show(position); + tooltip.text = text + var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0) + tooltip.show(position) tooltip.target.x = position.x + 1 } - onHideTooltip: - { - tooltip.hide(); - } + onHideTooltip: tooltip.hide() } - } } } @@ -459,6 +476,7 @@ UM.Dialog Cura.SettingUnknown { } } } + rightButtons: Button { text: catalog.i18nc("@action:button", "Close") @@ -466,43 +484,15 @@ UM.Dialog onClicked: dialog.accept() } - Button { + Cura.SecondaryButton + { objectName: "postProcessingSaveAreaButton" visible: activeScriptsList.count > 0 height: UM.Theme.getSize("save_button_save_to_button").height width: height tooltip: catalog.i18nc("@info:tooltip", "Change active post-processing scripts") onClicked: dialog.show() - - style: ButtonStyle { - background: Rectangle { - id: deviceSelectionIcon - border.width: UM.Theme.getSize("default_lining").width - border.color: !control.enabled ? UM.Theme.getColor("action_button_disabled_border") : - control.pressed ? UM.Theme.getColor("action_button_active_border") : - control.hovered ? UM.Theme.getColor("action_button_hovered_border") : UM.Theme.getColor("action_button_border") - color: !control.enabled ? UM.Theme.getColor("action_button_disabled") : - control.pressed ? UM.Theme.getColor("action_button_active") : - control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") - Behavior on color { ColorAnimation { duration: 50; } } - anchors.left: parent.left - anchors.leftMargin: Math.round(UM.Theme.getSize("save_button_text_margin").width / 2); - width: parent.height - height: parent.height - - UM.RecolorImage { - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - width: Math.round(parent.width / 2) - height: Math.round(parent.height / 2) - sourceSize.height: height - color: !control.enabled ? UM.Theme.getColor("action_button_disabled_text") : - control.pressed ? UM.Theme.getColor("action_button_active_text") : - control.hovered ? UM.Theme.getColor("action_button_hovered_text") : UM.Theme.getColor("action_button_text"); - source: "postprocessing.svg" - } - } - label: Label{ } - } + iconSource: "postprocessing.svg" + fixedWidthMode: true } } \ No newline at end of file diff --git a/plugins/SimulationView/LayerSlider.qml b/plugins/SimulationView/LayerSlider.qml index 42b8cf0ba0..88f298d1f5 100644 --- a/plugins/SimulationView/LayerSlider.qml +++ b/plugins/SimulationView/LayerSlider.qml @@ -163,9 +163,9 @@ Item id: rangleHandleLabel height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height - x: parent.x + parent.width + UM.Theme.getSize("default_margin").width + x: parent.x - width - UM.Theme.getSize("default_margin").width anchors.verticalCenter: parent.verticalCenter - target: Qt.point(sliderRoot.width + width, y + height / 2) + target: Qt.point(sliderRoot.width, y + height / 2) visible: sliderRoot.activeHandle == parent // custom properties diff --git a/plugins/SimulationView/SimulationViewMenuComponent.qml b/plugins/SimulationView/SimulationViewMenuComponent.qml index fe32fe9eb1..4c952d4c43 100644 --- a/plugins/SimulationView/SimulationViewMenuComponent.qml +++ b/plugins/SimulationView/SimulationViewMenuComponent.qml @@ -43,7 +43,7 @@ Cura.ExpandableComponent verticalAlignment: Text.AlignVCenter height: parent.height elide: Text.ElideRight - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("text_medium") renderType: Text.NativeRendering } @@ -60,7 +60,7 @@ Cura.ExpandableComponent } height: parent.height elide: Text.ElideRight - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("text") renderType: Text.NativeRendering } diff --git a/plugins/Toolbox/resources/qml/SmallRatingWidget.qml b/plugins/Toolbox/resources/qml/SmallRatingWidget.qml index 4950ea9242..965b81dc0f 100644 --- a/plugins/Toolbox/resources/qml/SmallRatingWidget.qml +++ b/plugins/Toolbox/resources/qml/SmallRatingWidget.qml @@ -30,7 +30,7 @@ Row width: contentWidth anchors.verticalCenter: starIcon.verticalCenter color: starIcon.color - font: UM.Theme.getFont("small") + font: UM.Theme.getFont("default") renderType: Text.NativeRendering } } \ No newline at end of file diff --git a/plugins/Toolbox/resources/qml/Toolbox.qml b/plugins/Toolbox/resources/qml/Toolbox.qml index 9ede2a6bda..d15d98eed7 100644 --- a/plugins/Toolbox/resources/qml/Toolbox.qml +++ b/plugins/Toolbox/resources/qml/Toolbox.qml @@ -38,7 +38,7 @@ Window { id: mainView width: parent.width - z: -1 + z: parent.z - 1 anchors { top: header.bottom diff --git a/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml b/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml index 7b026566c3..b653f1a73b 100644 --- a/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml +++ b/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml @@ -55,7 +55,7 @@ Item bottomMargin: UM.Theme.getSize("default_margin").height } text: details.name || "" - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") wrapMode: Text.WordWrap width: parent.width height: UM.Theme.getSize("toolbox_property_label").height diff --git a/plugins/Toolbox/resources/qml/ToolboxBackColumn.qml b/plugins/Toolbox/resources/qml/ToolboxBackColumn.qml index edb1967fee..dba9f19ccd 100644 --- a/plugins/Toolbox/resources/qml/ToolboxBackColumn.qml +++ b/plugins/Toolbox/resources/qml/ToolboxBackColumn.qml @@ -61,8 +61,13 @@ Item id: labelStyle text: control.text color: control.enabled ? (control.hovered ? UM.Theme.getColor("primary") : UM.Theme.getColor("text")) : UM.Theme.getColor("text_inactive") - font: UM.Theme.getFont("default_bold") - horizontalAlignment: Text.AlignRight + font: UM.Theme.getFont("medium_bold") + horizontalAlignment: Text.AlignLeft + anchors + { + left: parent.left + leftMargin: UM.Theme.getSize("default_margin").width + } width: control.width renderType: Text.NativeRendering } diff --git a/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml b/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml index b9b36cd878..fef2732af9 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDetailPage.qml @@ -59,7 +59,7 @@ Item leftMargin: UM.Theme.getSize("default_margin").width } text: details === null ? "" : (details.name || "") - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") width: contentWidth height: contentHeight diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml index 85f0ff8be4..a9fcb39b28 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsGrid.qml @@ -22,7 +22,7 @@ Column text: gridArea.heading width: parent.width color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("medium") + font: UM.Theme.getFont("large") renderType: Text.NativeRendering } Grid diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml index 58e4f070e0..a11c6ee963 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml @@ -112,7 +112,7 @@ Item elide: Text.ElideRight width: parent.width wrapMode: Text.WordWrap - color: UM.Theme.getColor("text_medium") + color: UM.Theme.getColor("text") font: UM.Theme.getFont("default") anchors.top: name.bottom anchors.bottom: rating.top diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml index 820b74554a..795622cf82 100644 --- a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml +++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcase.qml @@ -23,7 +23,7 @@ Rectangle text: catalog.i18nc("@label", "Featured") width: parent.width color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("medium") + font: UM.Theme.getFont("large") renderType: Text.NativeRendering } Grid diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml index e1d01db59a..a85a69cbac 100644 --- a/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml +++ b/plugins/Toolbox/resources/qml/ToolboxInstalledPage.qml @@ -37,7 +37,7 @@ ScrollView width: page.width text: catalog.i18nc("@title:tab", "Plugins") color: UM.Theme.getColor("text_medium") - font: UM.Theme.getFont("medium") + font: UM.Theme.getFont("large") renderType: Text.NativeRendering } Rectangle diff --git a/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml b/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml index 593e024309..333d4dd50a 100644 --- a/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml +++ b/plugins/Toolbox/resources/qml/ToolboxInstalledTile.qml @@ -49,13 +49,14 @@ Item width: parent.width height: Math.floor(UM.Theme.getSize("toolbox_property_label").height) wrapMode: Text.WordWrap - font: UM.Theme.getFont("default_bold") + font: UM.Theme.getFont("large_bold") color: pluginInfo.color renderType: Text.NativeRendering } Label { text: model.description + font: UM.Theme.getFont("default") maximumLineCount: 3 elide: Text.ElideRight width: parent.width @@ -82,6 +83,7 @@ Item return model.author_name } } + font: UM.Theme.getFont("medium") width: parent.width height: Math.floor(UM.Theme.getSize("toolbox_property_label").height) wrapMode: Text.WordWrap @@ -96,6 +98,7 @@ Item Label { text: model.version + font: UM.Theme.getFont("default") width: parent.width height: UM.Theme.getSize("toolbox_property_label").height color: UM.Theme.getColor("text") diff --git a/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml index 80b5c2f99e..3883a7e285 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/DiscoverUM3Action.qml @@ -223,7 +223,7 @@ Cura.MachineAction width: parent.width wrapMode: Text.WordWrap text: base.selectedDevice ? base.selectedDevice.name : "" - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") elide: Text.ElideRight renderType: Text.NativeRendering } diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml index 2ca37a7e13..b8c4353811 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorPrinterCard.qml @@ -81,7 +81,7 @@ Item text: printer && printer.name ? printer.name : "" color: "#414054" // TODO: Theme! elide: Text.ElideRight - font: UM.Theme.getFont("large") // 16pt, bold + font: UM.Theme.getFont("large_bold") // 16pt, bold width: parent.width // FIXED-LINE-HEIGHT: @@ -185,7 +185,7 @@ Item verticalCenter: parent.verticalCenter } color: "#414054" // TODO: Theme! - font: UM.Theme.getFont("large") // 16pt, bold + font: UM.Theme.getFont("large_bold") // 16pt, bold text: { if (printer && printer.state == "disabled") { @@ -236,7 +236,7 @@ Item id: printerJobNameLabel color: printer.activePrintJob && printer.activePrintJob.isActive ? "#414054" : "#babac1" // TODO: Theme! elide: Text.ElideRight - font: UM.Theme.getFont("large") // 16pt, bold + font: UM.Theme.getFont("large_bold") // 16pt, bold text: base.printer.activePrintJob ? base.printer.activePrintJob.name : "Untitled" // TODO: I18N width: parent.width diff --git a/plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml b/plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml index 884dbabc2f..f2a0e785b8 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/MonitorQueue.qml @@ -23,7 +23,7 @@ Item top: parent.top } color: UM.Theme.getColor("text") - font: UM.Theme.getFont("large_nonbold") + font: UM.Theme.getFont("large") text: catalog.i18nc("@label", "Queued") } diff --git a/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml b/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml index 320201e165..c99ed1688e 100644 --- a/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml +++ b/plugins/UM3NetworkPrinting/resources/qml/UM3InfoComponents.qml @@ -90,67 +90,4 @@ Item { source: "DiscoverUM3Action.qml"; } } - - Column { - anchors.fill: parent; - objectName: "networkPrinterConnectionInfo"; - spacing: UM.Theme.getSize("default_margin").width; - visible: isUM3; - - Button { - onClicked: Cura.MachineManager.printerOutputDevices[0].requestAuthentication(); - text: catalog.i18nc("@action:button", "Request Access"); - tooltip: catalog.i18nc("@info:tooltip", "Send access request to the printer"); - visible: printerConnected && !printerAcceptsCommands && !authenticationRequested; - } - - Row { - anchors { - left: parent.left; - right: parent.right; - } - height: childrenRect.height; - spacing: UM.Theme.getSize("default_margin").width; - visible: printerConnected; - - Column { - Repeater { - model: CuraApplication.getExtrudersModel() - - Label { - text: model.name; - } - } - } - - Column { - Repeater { - id: nozzleColumn; - model: hotendIds - - Label { - text: nozzleColumn.model[index]; - } - } - } - - Column { - Repeater { - id: materialColumn; - model: materialNames - - Label { - text: materialColumn.model[index]; - } - } - } - } - - Button { - onClicked: manager.loadConfigurationFromPrinter(); - text: catalog.i18nc("@action:button", "Activate Configuration"); - tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura"); - visible: false; // printerConnected && !isClusterPrinter() - } - } } diff --git a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py index bebccc54e3..5e8aaa9fa9 100644 --- a/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/ClusterUM3OutputDevice.py @@ -620,8 +620,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): if material_group_list is None: material_name = i18n_catalog.i18nc("@label:material", "Empty") if len(material_data.get("guid", "")) == 0 \ else i18n_catalog.i18nc("@label:material", "Unknown") + return MaterialOutputModel(guid = material_data.get("guid", ""), - type = material_data.get("type", ""), + type = material_data.get("material", ""), color = material_data.get("color", ""), brand = material_data.get("brand", ""), name = material_data.get("name", material_name) diff --git a/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py b/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py index 6ce99e4891..68af2bd575 100644 --- a/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py +++ b/plugins/UM3NetworkPrinting/src/DiscoverUM3Action.py @@ -193,4 +193,3 @@ class DiscoverUM3Action(MachineAction): # Create extra components CuraApplication.getInstance().addAdditionalComponent("monitorButtons", self.__additional_components_view.findChild(QObject, "networkPrinterConnectButton")) - CuraApplication.getInstance().addAdditionalComponent("machinesDetailPane", self.__additional_components_view.findChild(QObject, "networkPrinterConnectionInfo")) diff --git a/plugins/UM3NetworkPrinting/src/SendMaterialJob.py b/plugins/UM3NetworkPrinting/src/SendMaterialJob.py index f536fad49a..9d0d3dbbad 100644 --- a/plugins/UM3NetworkPrinting/src/SendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/src/SendMaterialJob.py @@ -2,7 +2,6 @@ # Cura is released under the terms of the LGPLv3 or higher. import json import os -import urllib.parse from typing import Dict, TYPE_CHECKING, Set from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest @@ -10,9 +9,7 @@ from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest from UM.Application import Application from UM.Job import Job from UM.Logger import Logger -from UM.MimeTypeDatabase import MimeTypeDatabase -from UM.Resources import Resources -from cura.CuraApplication import CuraApplication + # Absolute imports don't work in plugins from .Models import ClusterMaterial, LocalMaterial @@ -37,7 +34,6 @@ class SendMaterialJob(Job): # # \param reply The reply from the printer, a json file. def _onGetRemoteMaterials(self, reply: QNetworkReply) -> None: - # Got an error from the HTTP request. If we did not receive a 200 something happened. if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: Logger.log("e", "Error fetching materials from printer: %s", reply.errorString()) @@ -52,7 +48,6 @@ class SendMaterialJob(Job): # # \param remote_materials_by_guid The remote materials by GUID. def _sendMissingMaterials(self, remote_materials_by_guid: Dict[str, ClusterMaterial]) -> None: - # Collect local materials local_materials_by_guid = self._getLocalMaterials() if len(local_materials_by_guid) == 0: @@ -91,22 +86,22 @@ class SendMaterialJob(Job): # # \param materials_to_send A set with id's of materials that must be sent. def _sendMaterials(self, materials_to_send: Set[str]) -> None: - file_paths = Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.MaterialInstanceContainer) + container_registry = Application.getInstance().getContainerRegistry() + material_manager = Application.getInstance().getMaterialManager() + material_group_dict = material_manager.getAllMaterialGroups() - # Find all local material files and send them if needed. - for file_path in file_paths: - try: - mime_type = MimeTypeDatabase.getMimeTypeForFile(file_path) - except MimeTypeDatabase.MimeTypeNotFoundError: - continue - - file_name = os.path.basename(file_path) - material_id = urllib.parse.unquote_plus(mime_type.stripExtension(file_name)) - if material_id not in materials_to_send: + for root_material_id in material_group_dict: + if root_material_id not in materials_to_send: # If the material does not have to be sent we skip it. continue - self._sendMaterialFile(file_path, file_name, material_id) + file_path = container_registry.getContainerFilePathById(root_material_id) + if not file_path: + Logger.log("w", "Cannot get file path for material container [%s]", root_material_id) + continue + + file_name = os.path.basename(file_path) + self._sendMaterialFile(file_path, file_name, root_material_id) ## Send a single material file to the printer. # @@ -116,7 +111,6 @@ class SendMaterialJob(Job): # \param file_name The name of the material file. # \param material_id The ID of the material in the file. def _sendMaterialFile(self, file_path: str, file_name: str, material_id: str) -> None: - parts = [] # Add the material file. @@ -171,27 +165,31 @@ class SendMaterialJob(Job): # \return a dictionary of LocalMaterial objects by GUID def _getLocalMaterials(self) -> Dict[str, LocalMaterial]: result = {} # type: Dict[str, LocalMaterial] - container_registry = Application.getInstance().getContainerRegistry() - material_containers = container_registry.findContainersMetadata(type = "material") + material_manager = Application.getInstance().getMaterialManager() + + material_group_dict = material_manager.getAllMaterialGroups() # Find the latest version of all material containers in the registry. - for material in material_containers: + for root_material_id, material_group in material_group_dict.items(): + material_metadata = material_group.root_material_node.getMetadata() + try: # material version must be an int - material["version"] = int(material["version"]) + material_metadata["version"] = int(material_metadata["version"]) # Create a new local material - local_material = LocalMaterial(**material) + local_material = LocalMaterial(**material_metadata) + local_material.id = root_material_id if local_material.GUID not in result or \ local_material.version > result.get(local_material.GUID).version: result[local_material.GUID] = local_material except KeyError: - Logger.logException("w", "Local material {} has missing values.".format(material["id"])) + Logger.logException("w", "Local material {} has missing values.".format(material_metadata["id"])) except ValueError: - Logger.logException("w", "Local material {} has invalid values.".format(material["id"])) + Logger.logException("w", "Local material {} has invalid values.".format(material_metadata["id"])) except TypeError: - Logger.logException("w", "Local material {} has invalid values.".format(material["id"])) + Logger.logException("w", "Local material {} has invalid values.".format(material_metadata["id"])) return result diff --git a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py index 80212fcf00..57bc96b0e0 100644 --- a/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py +++ b/plugins/UM3NetworkPrinting/src/UM3OutputDevicePlugin.py @@ -114,6 +114,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin): if key == um_network_key: if not self._discovered_devices[key].isConnected(): Logger.log("d", "Attempting to connect with [%s]" % key) + active_machine.setMetaDataEntry("connection_type", self._discovered_devices[key].getConnectionType().value) self._discovered_devices[key].connect() self._discovered_devices[key].connectionStateChanged.connect(self._onDeviceConnectionStateChanged) else: diff --git a/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py index b669eb192a..6eac892af6 100644 --- a/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/tests/TestSendMaterialJob.py @@ -1,26 +1,29 @@ # Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +import copy import io import json from unittest import TestCase, mock -from unittest.mock import patch, call +from unittest.mock import patch, call, MagicMock from PyQt5.QtCore import QByteArray -from UM.MimeTypeDatabase import MimeType from UM.Application import Application + +from cura.Machines.MaterialGroup import MaterialGroup +from cura.Machines.MaterialNode import MaterialNode + from plugins.UM3NetworkPrinting.src.SendMaterialJob import SendMaterialJob +_FILES_MAP = {"generic_pla_white": "/materials/generic_pla_white.xml.fdm_material", + "generic_pla_black": "/materials/generic_pla_black.xml.fdm_material", + } + @patch("builtins.open", lambda _, __: io.StringIO("")) -@patch("UM.MimeTypeDatabase.MimeTypeDatabase.getMimeTypeForFile", - lambda _: MimeType(name = "application/x-ultimaker-material-profile", comment = "Ultimaker Material Profile", - suffixes = ["xml.fdm_material"])) -@patch("UM.Resources.Resources.getAllResourcesOfType", lambda _: ["/materials/generic_pla_white.xml.fdm_material"]) -@patch("plugins.UM3NetworkPrinting.src.ClusterUM3OutputDevice") -@patch("PyQt5.QtNetwork.QNetworkReply") class TestSendMaterialJob(TestCase): + # version 1 _LOCAL_MATERIAL_WHITE = {"type": "material", "status": "unknown", "id": "generic_pla_white", "base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA", "brand": "Generic", "material": "PLA", "color_name": "White", @@ -29,6 +32,37 @@ class TestSendMaterialJob(TestCase): "properties": {"density": "1.00", "diameter": "2.85", "weight": "750"}, "definition": "fdmprinter", "compatible": True} + # version 2 + _LOCAL_MATERIAL_WHITE_NEWER = {"type": "material", "status": "unknown", "id": "generic_pla_white", + "base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA", + "brand": "Generic", "material": "PLA", "color_name": "White", + "GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "2", + "color_code": "#ffffff", + "description": "Test PLA White", "adhesion_info": "Use glue.", + "approximate_diameter": "3", + "properties": {"density": "1.00", "diameter": "2.85", "weight": "750"}, + "definition": "fdmprinter", "compatible": True} + + # invalid version: "one" + _LOCAL_MATERIAL_WHITE_INVALID_VERSION = {"type": "material", "status": "unknown", "id": "generic_pla_white", + "base_file": "generic_pla_white", "setting_version": "5", "name": "White PLA", + "brand": "Generic", "material": "PLA", "color_name": "White", + "GUID": "badb0ee7-87c8-4f3f-9398-938587b67dce", "version": "one", + "color_code": "#ffffff", + "description": "Test PLA White", "adhesion_info": "Use glue.", + "approximate_diameter": "3", + "properties": {"density": "1.00", "diameter": "2.85", "weight": "750"}, + "definition": "fdmprinter", "compatible": True} + + _LOCAL_MATERIAL_WHITE_ALL_RESULT = {"generic_pla_white": MaterialGroup("generic_pla_white", + MaterialNode(_LOCAL_MATERIAL_WHITE))} + + _LOCAL_MATERIAL_WHITE_NEWER_ALL_RESULT = {"generic_pla_white": MaterialGroup("generic_pla_white", + MaterialNode(_LOCAL_MATERIAL_WHITE_NEWER))} + + _LOCAL_MATERIAL_WHITE_INVALID_VERSION_ALL_RESULT = {"generic_pla_white": MaterialGroup("generic_pla_white", + MaterialNode(_LOCAL_MATERIAL_WHITE_INVALID_VERSION))} + _LOCAL_MATERIAL_BLACK = {"type": "material", "status": "unknown", "id": "generic_pla_black", "base_file": "generic_pla_black", "setting_version": "5", "name": "Yellow CPE", "brand": "Ultimaker", "material": "CPE", "color_name": "Black", @@ -37,6 +71,9 @@ class TestSendMaterialJob(TestCase): "properties": {"density": "1.01", "diameter": "2.85", "weight": "750"}, "definition": "fdmprinter", "compatible": True} + _LOCAL_MATERIAL_BLACK_ALL_RESULT = {"generic_pla_black": MaterialGroup("generic_pla_black", + MaterialNode(_LOCAL_MATERIAL_BLACK))} + _REMOTE_MATERIAL_WHITE = { "guid": "badb0ee7-87c8-4f3f-9398-938587b67dce", "material": "PLA", @@ -55,14 +92,17 @@ class TestSendMaterialJob(TestCase): "density": 1.00 } - def test_run(self, device_mock, reply_mock): + def test_run(self): + device_mock = MagicMock() job = SendMaterialJob(device_mock) job.run() # We expect the materials endpoint to be called when the job runs. device_mock.get.assert_called_with("materials/", on_finished = job._onGetRemoteMaterials) - def test__onGetRemoteMaterials_withFailedRequest(self, reply_mock, device_mock): + def test__onGetRemoteMaterials_withFailedRequest(self): + reply_mock = MagicMock() + device_mock = MagicMock() reply_mock.attribute.return_value = 404 job = SendMaterialJob(device_mock) job._onGetRemoteMaterials(reply_mock) @@ -70,7 +110,9 @@ class TestSendMaterialJob(TestCase): # We expect the device not to be called for any follow up. self.assertEqual(0, device_mock.createFormPart.call_count) - def test__onGetRemoteMaterials_withWrongEncoding(self, reply_mock, device_mock): + def test__onGetRemoteMaterials_withWrongEncoding(self): + reply_mock = MagicMock() + device_mock = MagicMock() reply_mock.attribute.return_value = 200 reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("cp500")) job = SendMaterialJob(device_mock) @@ -79,7 +121,9 @@ class TestSendMaterialJob(TestCase): # Given that the parsing fails we do no expect the device to be called for any follow up. self.assertEqual(0, device_mock.createFormPart.call_count) - def test__onGetRemoteMaterials_withBadJsonAnswer(self, reply_mock, device_mock): + def test__onGetRemoteMaterials_withBadJsonAnswer(self): + reply_mock = MagicMock() + device_mock = MagicMock() reply_mock.attribute.return_value = 200 reply_mock.readAll.return_value = QByteArray(b"Six sick hicks nick six slick bricks with picks and sticks.") job = SendMaterialJob(device_mock) @@ -88,7 +132,9 @@ class TestSendMaterialJob(TestCase): # Given that the parsing fails we do no expect the device to be called for any follow up. self.assertEqual(0, device_mock.createFormPart.call_count) - def test__onGetRemoteMaterials_withMissingGuidInRemoteMaterial(self, reply_mock, device_mock): + def test__onGetRemoteMaterials_withMissingGuidInRemoteMaterial(self): + reply_mock = MagicMock() + device_mock = MagicMock() reply_mock.attribute.return_value = 200 remote_material_without_guid = self._REMOTE_MATERIAL_WHITE.copy() del remote_material_without_guid["guid"] @@ -99,18 +145,20 @@ class TestSendMaterialJob(TestCase): # Given that parsing fails we do not expect the device to be called for any follow up. self.assertEqual(0, device_mock.createFormPart.call_count) + @patch("cura.Machines.MaterialManager.MaterialManager") @patch("cura.Settings.CuraContainerRegistry") @patch("UM.Application") def test__onGetRemoteMaterials_withInvalidVersionInLocalMaterial(self, application_mock, container_registry_mock, - reply_mock, device_mock): + material_manager_mock): + reply_mock = MagicMock() + device_mock = MagicMock() + application_mock.getContainerRegistry.return_value = container_registry_mock + application_mock.getMaterialManager.return_value = material_manager_mock + reply_mock.attribute.return_value = 200 reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii")) - localMaterialWhiteWithInvalidVersion = self._LOCAL_MATERIAL_WHITE.copy() - localMaterialWhiteWithInvalidVersion["version"] = "one" - container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithInvalidVersion] - - application_mock.getContainerRegistry.return_value = container_registry_mock + material_manager_mock.getAllMaterialGroups.return_value = self._LOCAL_MATERIAL_WHITE_INVALID_VERSION_ALL_RESULT.copy() with mock.patch.object(Application, "getInstance", new = lambda: application_mock): job = SendMaterialJob(device_mock) @@ -118,15 +166,16 @@ class TestSendMaterialJob(TestCase): self.assertEqual(0, device_mock.createFormPart.call_count) - @patch("cura.Settings.CuraContainerRegistry") - @patch("UM.Application") - def test__onGetRemoteMaterials_withNoUpdate(self, application_mock, container_registry_mock, reply_mock, - device_mock): - application_mock.getContainerRegistry.return_value = container_registry_mock + @patch("UM.Application.Application.getInstance") + def test__onGetRemoteMaterials_withNoUpdate(self, application_mock): + reply_mock = MagicMock() + device_mock = MagicMock() + container_registry_mock = application_mock.getContainerRegistry.return_value + material_manager_mock = application_mock.getMaterialManager.return_value device_mock.createFormPart.return_value = "_xXx_" - container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE] + material_manager_mock.getAllMaterialGroups.return_value = self._LOCAL_MATERIAL_WHITE_ALL_RESULT.copy() reply_mock.attribute.return_value = 200 reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii")) @@ -138,24 +187,25 @@ class TestSendMaterialJob(TestCase): self.assertEqual(0, device_mock.createFormPart.call_count) self.assertEqual(0, device_mock.postFormWithParts.call_count) - @patch("cura.Settings.CuraContainerRegistry") - @patch("UM.Application") - def test__onGetRemoteMaterials_withUpdatedMaterial(self, application_mock, container_registry_mock, reply_mock, - device_mock): - application_mock.getContainerRegistry.return_value = container_registry_mock + @patch("UM.Application.Application.getInstance") + def test__onGetRemoteMaterials_withUpdatedMaterial(self, get_instance_mock): + reply_mock = MagicMock() + device_mock = MagicMock() + application_mock = get_instance_mock.return_value + container_registry_mock = application_mock.getContainerRegistry.return_value + material_manager_mock = application_mock.getMaterialManager.return_value + + container_registry_mock.getContainerFilePathById = lambda x: _FILES_MAP.get(x) device_mock.createFormPart.return_value = "_xXx_" - localMaterialWhiteWithHigherVersion = self._LOCAL_MATERIAL_WHITE.copy() - localMaterialWhiteWithHigherVersion["version"] = "2" - container_registry_mock.findContainersMetadata.return_value = [localMaterialWhiteWithHigherVersion] + material_manager_mock.getAllMaterialGroups.return_value = self._LOCAL_MATERIAL_WHITE_NEWER_ALL_RESULT.copy() reply_mock.attribute.return_value = 200 reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_WHITE]).encode("ascii")) - with mock.patch.object(Application, "getInstance", new = lambda: application_mock): - job = SendMaterialJob(device_mock) - job._onGetRemoteMaterials(reply_mock) + job = SendMaterialJob(device_mock) + job._onGetRemoteMaterials(reply_mock) self.assertEqual(1, device_mock.createFormPart.call_count) self.assertEqual(1, device_mock.postFormWithParts.call_count) @@ -164,16 +214,21 @@ class TestSendMaterialJob(TestCase): call.postFormWithParts(target = "materials/", parts = ["_xXx_"], on_finished = job.sendingFinished)], device_mock.method_calls) - @patch("cura.Settings.CuraContainerRegistry") - @patch("UM.Application") - def test__onGetRemoteMaterials_withNewMaterial(self, application_mock, container_registry_mock, reply_mock, - device_mock): - application_mock.getContainerRegistry.return_value = container_registry_mock + @patch("UM.Application.Application.getInstance") + def test__onGetRemoteMaterials_withNewMaterial(self, application_mock): + reply_mock = MagicMock() + device_mock = MagicMock() + container_registry_mock = application_mock.getContainerRegistry.return_value + material_manager_mock = application_mock.getMaterialManager.return_value + + container_registry_mock.getContainerFilePathById = lambda x: _FILES_MAP.get(x) device_mock.createFormPart.return_value = "_xXx_" - container_registry_mock.findContainersMetadata.return_value = [self._LOCAL_MATERIAL_WHITE, - self._LOCAL_MATERIAL_BLACK] + all_results = self._LOCAL_MATERIAL_WHITE_ALL_RESULT.copy() + for key, value in self._LOCAL_MATERIAL_BLACK_ALL_RESULT.items(): + all_results[key] = value + material_manager_mock.getAllMaterialGroups.return_value = all_results reply_mock.attribute.return_value = 200 reply_mock.readAll.return_value = QByteArray(json.dumps([self._REMOTE_MATERIAL_BLACK]).encode("ascii")) diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py index 006b21bc48..b55ea5ebaf 100644 --- a/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py +++ b/plugins/VersionUpgrade/VersionUpgrade32to33/__init__.py @@ -47,7 +47,7 @@ def getMetaData() -> Dict[str, Any]: }, "user": { "get_version": upgrade.getCfgVersion, - "location": {"./user"} + "location": {"./user", "./materials/*"} }, "variant": { "get_version": upgrade.getCfgVersion, diff --git a/resources/bundled_packages/cura.json b/resources/bundled_packages/cura.json index c32b94af3f..f912958f74 100644 --- a/resources/bundled_packages/cura.json +++ b/resources/bundled_packages/cura.json @@ -356,7 +356,7 @@ } } }, - "PreviewStage": { + "PreviewStage": { "package_info": { "package_id": "PreviewStage", "package_type": "plugin", @@ -1585,4 +1585,4 @@ } } } -} +} \ No newline at end of file diff --git a/resources/qml/Account/AccountDetails.qml b/resources/qml/Account/AccountDetails.qml index bfb23930c6..45f822e41f 100644 --- a/resources/qml/Account/AccountDetails.qml +++ b/resources/qml/Account/AccountDetails.qml @@ -44,7 +44,7 @@ Column 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") + font: loggedIn ? UM.Theme.getFont("large_bold") : UM.Theme.getFont("default") color: UM.Theme.getColor("text") } diff --git a/resources/qml/ActionButton.qml b/resources/qml/ActionButton.qml index 3a9552cd9c..6cab04e5ec 100644 --- a/resources/qml/ActionButton.qml +++ b/resources/qml/ActionButton.qml @@ -16,7 +16,7 @@ Button property alias iconSource: buttonIconLeft.source property alias textFont: buttonText.font property alias cornerRadius: backgroundRect.radius - property alias tooltip: tooltip.text + property alias tooltip: tooltip.tooltipText property alias cornerSide: backgroundRect.cornerSide property color color: UM.Theme.getColor("primary") @@ -31,6 +31,8 @@ Button property alias shadowColor: shadow.color property alias shadowEnabled: shadow.visible + property alias toolTipContentAlignment: tooltip.contentAlignment + // This property is used to indicate whether the button has a fixed width or the width would depend on the contents // Be careful when using fixedWidthMode, the translated texts can be too long that they won't fit. In any case, // we elide the text to the right so the text will be cut off with the three dots at the end. @@ -110,11 +112,9 @@ Button z: backgroundRect.z - 1 } - ToolTip + Cura.ToolTip { id: tooltip - text: "" - delay: 500 - visible: text != "" && button.hovered + visible: button.hovered } } \ No newline at end of file diff --git a/resources/qml/ActionPanel/ActionPanelWidget.qml b/resources/qml/ActionPanel/ActionPanelWidget.qml index a1cd81e9e9..1d9ee95548 100644 --- a/resources/qml/ActionPanel/ActionPanelWidget.qml +++ b/resources/qml/ActionPanel/ActionPanelWidget.qml @@ -23,6 +23,7 @@ Rectangle border.width: UM.Theme.getSize("default_lining").width border.color: UM.Theme.getColor("lining") radius: UM.Theme.getSize("default_radius").width + z: 10 property bool outputAvailable: UM.Backend.state == UM.Backend.Done || UM.Backend.state == UM.Backend.Disabled diff --git a/resources/qml/ActionPanel/OutputDevicesActionButton.qml b/resources/qml/ActionPanel/OutputDevicesActionButton.qml index b56f50b9a9..3bfaab0fc1 100644 --- a/resources/qml/ActionPanel/OutputDevicesActionButton.qml +++ b/resources/qml/ActionPanel/OutputDevicesActionButton.qml @@ -60,7 +60,6 @@ Item 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) @@ -94,7 +93,6 @@ Item onClicked: { UM.OutputDeviceManager.setActiveDevice(model.id) - widget.requestWriteToDevice() popup.close() } } diff --git a/resources/qml/ActionPanel/OutputProcessWidget.qml b/resources/qml/ActionPanel/OutputProcessWidget.qml index eb6dc5b417..15214f212c 100644 --- a/resources/qml/ActionPanel/OutputProcessWidget.qml +++ b/resources/qml/ActionPanel/OutputProcessWidget.qml @@ -40,8 +40,7 @@ Column anchors { left: parent.left - right: printInformationPanel.left - rightMargin: printInformationPanel.visible ? UM.Theme.getSize("thin_margin").width : 0 + right: parent.right } Cura.IconWithText @@ -51,7 +50,15 @@ Column 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") + font: UM.Theme.getFont("large_bold") + + PrintInformationWidget + { + id: printInformationPanel + visible: !preSlicedData + anchors.left: parent.left + anchors.leftMargin: parent.contentWidth + UM.Theme.getSize("default_margin").width + } } Cura.IconWithText @@ -84,20 +91,43 @@ Column return totalWeights + "g · " + totalLengths.toFixed(2) + "m" } source: UM.Theme.getIcon("spool") + + Item + { + id: additionalComponents + width: childrenRect.width + anchors.right: parent.right + height: parent.height + Row + { + id: additionalComponentsRow + anchors.right: parent.right + anchors.bottom: parent.bottom + spacing: UM.Theme.getSize("default_margin").width + } + } + Component.onCompleted: addAdditionalComponents("saveButton") + + Connections + { + target: CuraApplication + onAdditionalComponentsChanged: addAdditionalComponents("saveButton") + } + + function addAdditionalComponents (areaId) + { + if(areaId == "saveButton") + { + for (var component in CuraApplication.additionalComponents["saveButton"]) + { + CuraApplication.additionalComponents["saveButton"][component].parent = additionalComponentsRow + } + } + } } } - PrintInformationWidget - { - id: printInformationPanel - visible: !preSlicedData - anchors - { - right: parent.right - verticalCenter: timeAndCostsInformation.verticalCenter - } - } } Item @@ -123,11 +153,10 @@ Column tooltip: text fixedWidthMode: true + toolTipContentAlignment: Cura.ToolTip.ContentAlignment.AlignLeft + 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 diff --git a/resources/qml/ActionPanel/SliceProcessWidget.qml b/resources/qml/ActionPanel/SliceProcessWidget.qml index 3756d0d452..1695be8748 100644 --- a/resources/qml/ActionPanel/SliceProcessWidget.qml +++ b/resources/qml/ActionPanel/SliceProcessWidget.qml @@ -44,9 +44,9 @@ Column { id: autoSlicingLabel width: parent.width - visible: prepareButtons.autoSlice && (widget.backendState == UM.Backend.Processing || widget.backendState == UM.Backend.NotStarted) + visible: progressBar.visible - text: catalog.i18nc("@label:PrintjobStatus", "Auto slicing...") + text: catalog.i18nc("@label:PrintjobStatus", "Slicing...") color: UM.Theme.getColor("text") font: UM.Theme.getFont("default") renderType: Text.NativeRendering @@ -107,8 +107,15 @@ Column { id: sliceButton fixedWidthMode: true - anchors.fill: parent + + height: parent.height + + anchors.right: additionalComponents.left + anchors.rightMargin: additionalComponents.width != 0 ? UM.Theme.getSize("default_margin").width : 0 + anchors.left: parent.left + text: catalog.i18nc("@button", "Slice") + tooltip: catalog.i18nc("@label", "Start the slicing process") enabled: widget.backendState != UM.Backend.Error visible: widget.backendState == UM.Backend.NotStarted || widget.backendState == UM.Backend.Error onClicked: sliceOrStopSlicing() @@ -118,12 +125,48 @@ Column { id: cancelButton fixedWidthMode: true - anchors.fill: parent + height: parent.height + anchors.left: parent.left + + anchors.right: additionalComponents.left + anchors.rightMargin: additionalComponents.width != 0 ? UM.Theme.getSize("default_margin").width : 0 text: catalog.i18nc("@button", "Cancel") enabled: sliceButton.enabled visible: !sliceButton.visible onClicked: sliceOrStopSlicing() } + + Item + { + id: additionalComponents + width: childrenRect.width + anchors.right: parent.right + height: parent.height + Row + { + id: additionalComponentsRow + anchors.verticalCenter: parent.verticalCenter + spacing: UM.Theme.getSize("default_margin").width + } + } + Component.onCompleted: prepareButtons.addAdditionalComponents("saveButton") + + Connections + { + target: CuraApplication + onAdditionalComponentsChanged: prepareButtons.addAdditionalComponents("saveButton") + } + + function addAdditionalComponents (areaId) + { + if(areaId == "saveButton") + { + for (var component in CuraApplication.additionalComponents["saveButton"]) + { + CuraApplication.additionalComponents["saveButton"][component].parent = additionalComponentsRow + } + } + } } @@ -134,10 +177,13 @@ Column onPreferenceChanged: { var autoSlice = UM.Preferences.getValue("general/auto_slice") - prepareButtons.autoSlice = autoSlice - if(autoSlice) + if(prepareButtons.autoSlice != autoSlice) { - CuraApplication.backend.forceSlice() + prepareButtons.autoSlice = autoSlice + if(autoSlice) + { + CuraApplication.backend.forceSlice() + } } } } diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 8a34c7e219..a78295e7fa 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -252,7 +252,21 @@ UM.MainWindow anchors.bottom: parent.bottom anchors.rightMargin: UM.Theme.getSize("thick_margin").width anchors.bottomMargin: UM.Theme.getSize("thick_margin").height - visible: CuraApplication.platformActivity + + /* + Show this panel only if there is something on the build plate, and there is NOT an opaque item in front of the build plate. + This cannot be solved by Z indexing! If you want to try solving this, please increase this counter when you're done: + Number of people having tried to fix this by z-indexing: 2 + The problem arises from the following render order requirements: + - The stage menu must be rendered above the stage main. + - The stage main must be rendered above the action panel (because the monitor page must be rendered above the action panel). + - The action panel must be rendered above the expandable components drop-down. + However since the expandable components drop-downs are child elements of the stage menu, + they can't be rendered lower than elements that are lower than the stage menu. + Therefore we opted to forego the second requirement and hide the action panel instead when something obscures it (except the expandable components). + We assume that QQuickRectangles are always opaque and any other item is not. + */ + visible: CuraApplication.platformActivity && (main.item == null || !qmlTypeOf(main.item, "QQuickRectangle")) } Loader @@ -818,4 +832,21 @@ UM.MainWindow } } } + + /** + * Function to check whether a QML object has a certain type. + * Taken from StackOverflow: https://stackoverflow.com/a/28384228 and + * adapted to our code style. + * Licensed under CC BY-SA 3.0. + * \param obj The QtObject to get the name of. + * \param class_name (str) The name of the class to check against. Has to be + * the QtObject class name, not the QML entity name. + */ + function qmlTypeOf(obj, class_name) + { + //className plus "(" is the class instance without modification. + //className plus "_QML" is the class instance with user-defined properties. + var str = obj.toString(); + return str.indexOf(class_name + "(") == 0 || str.indexOf(class_name + "_QML") == 0; + } } diff --git a/resources/qml/Dialogs/AboutDialog.qml b/resources/qml/Dialogs/AboutDialog.qml index add84614e0..ac115a0e5f 100644 --- a/resources/qml/Dialogs/AboutDialog.qml +++ b/resources/qml/Dialogs/AboutDialog.qml @@ -51,7 +51,7 @@ UM.Dialog id: version text: catalog.i18nc("@label","version: %1").arg(UM.Application.version) - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") anchors.right : logo.right anchors.top: logo.bottom diff --git a/resources/qml/ExpandableComponent.qml b/resources/qml/ExpandableComponent.qml index afe15bcb1d..025c63d754 100644 --- a/resources/qml/ExpandableComponent.qml +++ b/resources/qml/ExpandableComponent.qml @@ -64,7 +64,7 @@ Item property alias iconSize: collapseButton.height // Is the "drawer" open? - readonly property alias expanded: contentContainer.visible + property alias expanded: contentContainer.visible // What should the radius of the header be. This is also influenced by the headerCornerSide property alias headerRadius: background.radius diff --git a/resources/qml/ExpandableComponentHeader.qml b/resources/qml/ExpandableComponentHeader.qml index 09ea262c82..94066340e3 100644 --- a/resources/qml/ExpandableComponentHeader.qml +++ b/resources/qml/ExpandableComponentHeader.qml @@ -25,7 +25,7 @@ Cura.RoundedRectangle { id: headerLabel text: "" - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") renderType: Text.NativeRendering verticalAlignment: Text.AlignVCenter color: UM.Theme.getColor("small_button_text") diff --git a/resources/qml/ExtruderIcon.qml b/resources/qml/ExtruderIcon.qml index fcc49c9040..015ebea52e 100644 --- a/resources/qml/ExtruderIcon.qml +++ b/resources/qml/ExtruderIcon.qml @@ -48,7 +48,7 @@ Item id: extruderNumberText anchors.centerIn: parent text: index + 1 - font: UM.Theme.getFont("very_small") + font: UM.Theme.getFont("small") color: UM.Theme.getColor("text") width: contentWidth height: contentHeight @@ -66,7 +66,7 @@ Item sourceSize.height: width source: UM.Theme.getIcon("cross1") visible: !extruderEnabled - color: "black" + color: UM.Theme.getColor("text") } } } \ No newline at end of file diff --git a/resources/qml/JobSpecs.qml b/resources/qml/JobSpecs.qml index c7f82b8876..144616c22d 100644 --- a/resources/qml/JobSpecs.qml +++ b/resources/qml/JobSpecs.qml @@ -97,7 +97,7 @@ Item style: TextFieldStyle { textColor: UM.Theme.getColor("text_scene") - font: UM.Theme.getFont("default_bold") + font: UM.Theme.getFont("default") background: Rectangle { opacity: 0 @@ -115,7 +115,7 @@ Item height: UM.Theme.getSize("jobspecs_line").height verticalAlignment: Text.AlignVCenter - font: UM.Theme.getFont("default_bold") + font: UM.Theme.getFont("default") color: UM.Theme.getColor("text_scene") text: CuraApplication.getSceneBoundingBoxString } diff --git a/resources/qml/MainWindow/ApplicationMenu.qml b/resources/qml/MainWindow/ApplicationMenu.qml index 04c068cb54..a694b8e403 100644 --- a/resources/qml/MainWindow/ApplicationMenu.qml +++ b/resources/qml/MainWindow/ApplicationMenu.qml @@ -83,14 +83,6 @@ Item } } - Menu - { - id: plugin_menu - title: catalog.i18nc("@title:menu menubar:toplevel", "&Marketplace") - - MenuItem { action: Cura.Actions.browsePackages } - } - Menu { id: preferencesMenu diff --git a/resources/qml/MainWindow/MainWindowHeader.qml b/resources/qml/MainWindow/MainWindowHeader.qml index eecf2a1e73..3e296ead40 100644 --- a/resources/qml/MainWindow/MainWindowHeader.qml +++ b/resources/qml/MainWindow/MainWindowHeader.qml @@ -29,6 +29,9 @@ Item source: UM.Theme.getImage("logo") width: UM.Theme.getSize("logo").width height: UM.Theme.getSize("logo").height + + sourceSize.width: width + sourceSize.height: height } Row @@ -99,6 +102,7 @@ Item { id: label text: marketplaceButton.text + font: UM.Theme.getFont("default") color: marketplaceButton.hovered ? UM.Theme.getColor("main_window_header_background") : UM.Theme.getColor("primary_text") width: contentWidth verticalAlignment: Text.AlignVCenter diff --git a/resources/qml/Menus/ConfigurationMenu/AutoConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/AutoConfiguration.qml index a3ed5040b7..18409dd43a 100644 --- a/resources/qml/Menus/ConfigurationMenu/AutoConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/AutoConfiguration.qml @@ -16,7 +16,7 @@ Item { id: header text: catalog.i18nc("@header", "Configurations") - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("small_button_text") height: contentHeight renderType: Text.NativeRendering diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml index 862e1475a9..058c1ff4c2 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationItem.qml @@ -12,7 +12,23 @@ Button id: configurationItem property var configuration: null - hoverEnabled: true + hoverEnabled: isValidMaterial + + property bool isValidMaterial: + { + var extruderConfigurations = configuration.extruderConfigurations + + for (var index in extruderConfigurations) + { + var name = extruderConfigurations[index].material ? extruderConfigurations[index].material.name : "" + + if (name == "" || name == "Unknown") + { + return false + } + } + return true + } background: Rectangle { @@ -40,17 +56,104 @@ Button right: parent.right rightMargin: UM.Theme.getSize("wide_margin").width } - + height: childrenRect.height spacing: UM.Theme.getSize("default_margin").width Repeater { id: repeater model: configuration.extruderConfigurations + delegate: PrintCoreConfiguration { width: Math.round(parent.width / 2) printCoreConfiguration: modelData + visible: configurationItem.isValidMaterial + } + } + + // Unknown material + Item + { + id: unknownMaterial + height: unknownMaterialMessage.height + UM.Theme.getSize("thin_margin").width / 2 + width: parent.width + + anchors.top: parent.top + anchors.topMargin: UM.Theme.getSize("thin_margin").width / 2 + + visible: !configurationItem.isValidMaterial + + UM.RecolorImage + { + id: icon + anchors.verticalCenter: unknownMaterialMessage.verticalCenter + + source: UM.Theme.getIcon("warning") + color: UM.Theme.getColor("warning") + width: UM.Theme.getSize("section_icon").width + height: width + } + + Label + { + id: unknownMaterialMessage + text: + { + var extruderConfigurations = configuration.extruderConfigurations + var unknownMaterials = [] + for (var index in extruderConfigurations) + { + var name = extruderConfigurations[index].material ? extruderConfigurations[index].material.name : "" + if (name == "" || name == "Unknown") + { + var materialType = extruderConfigurations[index].material.type + if (extruderConfigurations[index].material.type == "") + { + materialType = "Unknown" + } + + var brand = extruderConfigurations[index].material.brand + if (brand == "") + { + brand = "Unknown" + } + + name = materialType + " (" + brand + ")" + unknownMaterials.push(name) + } + } + + unknownMaterials = "" + unknownMaterials + "" + var draftResult = catalog.i18nc("@label", "This configuration is not available because %1 is not recognized. Please visit %2 to download the correct material profile."); + var result = draftResult.arg(unknownMaterials).arg("" + catalog.i18nc("@label","Marketplace") + " ") + + return result + } + width: extruderRow.width + + anchors.left: icon.right + anchors.right: unknownMaterial.right + anchors.leftMargin: UM.Theme.getSize("wide_margin").height + anchors.top: unknownMaterial.top + + wrapMode: Text.WordWrap + font: UM.Theme.getFont("default") + color: UM.Theme.getColor("text") + verticalAlignment: Text.AlignVCenter + linkColor: UM.Theme.getColor("text_link") + + onLinkActivated: + { + Cura.Actions.browsePackages.trigger() + } + } + + MouseArea + { + anchors.fill: parent + cursorShape: unknownMaterialMessage.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + acceptedButtons: Qt.NoButton } } } @@ -84,27 +187,15 @@ Button rightMargin: UM.Theme.getSize("wide_margin").width } height: childrenRect.height - visible: configuration.buildplateConfiguration != "" + visible: configuration.buildplateConfiguration != "" && false //Buildplate is disabled as long as we have no printers that properly support buildplate swapping (so we can't test). - UM.RecolorImage - { - id: buildplateIcon - anchors.left: parent.left - width: UM.Theme.getSize("main_window_header_button_icon").width - height: UM.Theme.getSize("main_window_header_button_icon").height - source: UM.Theme.getIcon("buildplate") - color: UM.Theme.getColor("text") - } - - Label + // Show the type of buildplate. The first letter is capitalized + Cura.IconWithText { id: buildplateLabel - anchors.left: buildplateIcon.right - anchors.verticalCenter: buildplateIcon.verticalCenter - anchors.leftMargin: UM.Theme.getSize("narrow_margin").height - text: configuration.buildplateConfiguration - renderType: Text.NativeRendering - color: UM.Theme.getColor("text") + source: UM.Theme.getIcon("buildplate") + text: configuration.buildplateConfiguration.charAt(0).toUpperCase() + configuration.buildplateConfiguration.substr(1) + anchors.left: parent.left } } } @@ -125,6 +216,9 @@ Button onClicked: { - Cura.MachineManager.applyRemoteConfiguration(configuration) + if(isValidMaterial) + { + Cura.MachineManager.applyRemoteConfiguration(configuration); + } } } diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 684e575bfd..e57b21cb78 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -51,7 +51,7 @@ Item anchors.left: icon.right anchors.right: parent.right anchors.leftMargin: UM.Theme.getSize("default_margin").width - text: catalog.i18nc("@label", "The configurations are not available because the printer is disconnected.") + text: catalog.i18nc("@label", "Downloading the configurations from the remote printer") color: UM.Theme.getColor("text") font: UM.Theme.getFont("default") renderType: Text.NativeRendering diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationMenu.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationMenu.qml index 207b65afc7..3001efac54 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationMenu.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationMenu.qml @@ -86,7 +86,7 @@ Cura.ExpandablePopup { text: model.material elide: Text.ElideRight - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("text") renderType: Text.NativeRendering @@ -107,7 +107,7 @@ Cura.ExpandablePopup { text: catalog.i18nc("@label", "Select configuration") elide: Text.ElideRight - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("text") renderType: Text.NativeRendering diff --git a/resources/qml/Menus/ConfigurationMenu/CustomConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/CustomConfiguration.qml index 4d6d80c1b4..5cecda4e5c 100644 --- a/resources/qml/Menus/ConfigurationMenu/CustomConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/CustomConfiguration.qml @@ -23,7 +23,7 @@ Item { id: header text: catalog.i18nc("@header", "Custom") - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("small_button_text") height: contentHeight renderType: Text.NativeRendering diff --git a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml index a344e31d4f..db6a97aa65 100644 --- a/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml +++ b/resources/qml/Menus/ConfigurationMenu/PrintCoreConfiguration.qml @@ -39,7 +39,7 @@ Row text: printCoreConfiguration.material.brand ? printCoreConfiguration.material.name : " " //Use space so that the height is still correct. renderType: Text.NativeRendering elide: Text.ElideRight - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("text") } Label diff --git a/resources/qml/Menus/LocalPrinterMenu.qml b/resources/qml/Menus/LocalPrinterMenu.qml index 0bdd4f33b9..4da1de2abf 100644 --- a/resources/qml/Menus/LocalPrinterMenu.qml +++ b/resources/qml/Menus/LocalPrinterMenu.qml @@ -7,16 +7,18 @@ import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura -Instantiator { - model: UM.ContainerStacksModel { - filter: {"type": "machine", "um_network_key": null} - } - MenuItem { - text: model.name; - checkable: true; +Instantiator +{ + model: Cura.GlobalStacksModel {} + + MenuItem + { + text: model.name + checkable: true checked: Cura.MachineManager.activeMachineId == model.id - exclusiveGroup: group; - onTriggered: Cura.MachineManager.setActiveMachine(model.id); + exclusiveGroup: group + visible: !model.hasRemoteConnection + onTriggered: Cura.MachineManager.setActiveMachine(model.id) } onObjectAdded: menu.insertItem(index, object) onObjectRemoved: menu.removeItem(object) diff --git a/resources/qml/Menus/NetworkPrinterMenu.qml b/resources/qml/Menus/NetworkPrinterMenu.qml index 07a22202e4..3cb0aae016 100644 --- a/resources/qml/Menus/NetworkPrinterMenu.qml +++ b/resources/qml/Menus/NetworkPrinterMenu.qml @@ -7,18 +7,17 @@ import QtQuick.Controls 1.4 import UM 1.2 as UM import Cura 1.0 as Cura -Instantiator { - model: UM.ContainerStacksModel { - filter: {"type": "machine", "um_network_key": "*", "hidden": "False"} - } - MenuItem { - // TODO: Use printer_group icon when it's a cluster. Not use it for now since it doesn't look as expected -// iconSource: UM.Theme.getIcon("printer_single") +Instantiator +{ + model: Cura.GlobalStacksModel {} + MenuItem + { text: model.metadata["connect_group_name"] - checkable: true; + checkable: true + visible: model.hasRemoteConnection checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"] - exclusiveGroup: group; - onTriggered: Cura.MachineManager.setActiveMachine(model.id); + exclusiveGroup: group + onTriggered: Cura.MachineManager.setActiveMachine(model.id) } onObjectAdded: menu.insertItem(index, object) onObjectRemoved: menu.removeItem(object) diff --git a/resources/qml/MonitorButton.qml b/resources/qml/MonitorButton.qml index fd7d2287c4..99640b1059 100644 --- a/resources/qml/MonitorButton.qml +++ b/resources/qml/MonitorButton.qml @@ -168,7 +168,7 @@ Item anchors.leftMargin: UM.Theme.getSize("thick_margin").width color: base.statusColor - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") text: statusText } @@ -179,7 +179,7 @@ Item anchors.right: progressBar.right color: base.statusColor - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") text: Math.round(progress) + "%" visible: showProgress } diff --git a/resources/qml/Preferences/MachinesPage.qml b/resources/qml/Preferences/MachinesPage.qml index 4acefdb493..f9c1a9b0a0 100644 --- a/resources/qml/Preferences/MachinesPage.qml +++ b/resources/qml/Preferences/MachinesPage.qml @@ -70,7 +70,7 @@ UM.ManagementPage { id: machineName text: base.currentItem && base.currentItem.name ? base.currentItem.name : "" - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") width: parent.width elide: Text.ElideRight } @@ -126,132 +126,15 @@ UM.ManagementPage } } - Grid - { - id: machineInfo - - anchors.top: machineActions.visible ? machineActions.bottom : machineActions.anchors.top - anchors.topMargin: UM.Theme.getSize("default_margin").height - anchors.left: parent.left - anchors.right: parent.right - spacing: UM.Theme.getSize("default_margin").height - rowSpacing: UM.Theme.getSize("default_lining").height - columns: 2 - - visible: base.currentItem - - property bool printerConnected: Cura.MachineManager.printerConnected - property var connectedPrinter: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null - property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands - property var printJob: connectedPrinter != null ? connectedPrinter.activePrintJob: null - Label - { - text: catalog.i18nc("@label", "Printer type:") - visible: base.currentItem && "definition_name" in base.currentItem.metadata - } - Label - { - text: (base.currentItem && "definition_name" in base.currentItem.metadata) ? base.currentItem.metadata.definition_name : "" - } - Label - { - text: catalog.i18nc("@label", "Connection:") - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId - } - Label - { - width: (parent.width * 0.7) | 0 - text: machineInfo.printerConnected ? machineInfo.connectedPrinter.connectionText : catalog.i18nc("@info:status", "The printer is not connected.") - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId - wrapMode: Text.WordWrap - } - Label - { - text: catalog.i18nc("@label", "State:") - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId && machineInfo.printerAcceptsCommands - } - Label { - width: (parent.width * 0.7) | 0 - text: - { - if(!machineInfo.printerConnected || !machineInfo.printerAcceptsCommands) { - return ""; - } - - if (machineInfo.printJob == null) - { - return catalog.i18nc("@label:MonitorStatus", "Waiting for a printjob"); - } - - switch(machineInfo.printJob.state) - { - case "printing": - return catalog.i18nc("@label:MonitorStatus", "Printing..."); - case "paused": - return catalog.i18nc("@label:MonitorStatus", "Paused"); - case "pre_print": - return catalog.i18nc("@label:MonitorStatus", "Preparing..."); - case "wait_cleanup": - return catalog.i18nc("@label:MonitorStatus", "Waiting for someone to clear the build plate"); - case "error": - return printerOutputDevice.errorText; - case "maintenance": - return catalog.i18nc("@label:MonitorStatus", "In maintenance. Please check the printer"); - case "abort": // note sure if this jobState actually occurs in the wild - return catalog.i18nc("@label:MonitorStatus", "Aborting print..."); - - } - return "" - } - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId && machineInfo.printerAcceptsCommands - wrapMode: Text.WordWrap - } - } - - Column { - id: additionalComponentsColumn - anchors.left: parent.left - anchors.right: parent.right - anchors.top: machineInfo.visible ? machineInfo.bottom : machineInfo.anchors.top - anchors.topMargin: UM.Theme.getSize("default_margin").width - - spacing: UM.Theme.getSize("default_margin").width - visible: base.currentItem && base.currentItem.id == Cura.MachineManager.activeMachineId - - Component.onCompleted: - { - for (var component in CuraApplication.additionalComponents["machinesDetailPane"]) { - CuraApplication.additionalComponents["machinesDetailPane"][component].parent = additionalComponentsColumn - } - } - } - - Component.onCompleted: { - addAdditionalComponents("machinesDetailPane") - } - - Connections { - target: CuraApplication - onAdditionalComponentsChanged: addAdditionalComponents - } - - function addAdditionalComponents (areaId) { - if(areaId == "machinesDetailPane") { - for (var component in CuraApplication.additionalComponents["machinesDetailPane"]) { - CuraApplication.additionalComponents["machinesDetailPane"][component].parent = additionalComponentsColumn - } - } - } - UM.I18nCatalog { id: catalog; name: "cura"; } UM.ConfirmRemoveDialog { - id: confirmDialog; - object: base.currentItem && base.currentItem.name ? base.currentItem.name : ""; + id: confirmDialog + object: base.currentItem && base.currentItem.name ? base.currentItem.name : "" onYes: { - Cura.MachineManager.removeMachine(base.currentItem.id); + Cura.MachineManager.removeMachine(base.currentItem.id) if(!base.currentItem) { objectList.currentIndex = activeMachineIndex() diff --git a/resources/qml/Preferences/Materials/MaterialsBrandSection.qml b/resources/qml/Preferences/Materials/MaterialsBrandSection.qml index c40693e343..c976233805 100644 --- a/resources/qml/Preferences/Materials/MaterialsBrandSection.qml +++ b/resources/qml/Preferences/Materials/MaterialsBrandSection.qml @@ -10,7 +10,7 @@ import QtQuick.Dialogs 1.2 import UM 1.2 as UM import Cura 1.0 as Cura -Rectangle +Item { id: brand_section diff --git a/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml b/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml index 92970f40e2..eb4a63250f 100644 --- a/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml +++ b/resources/qml/Preferences/Materials/MaterialsDetailsPanel.qml @@ -65,7 +65,7 @@ Item Label { text: materialProperties.name - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") } } diff --git a/resources/qml/Preferences/Materials/MaterialsSlot.qml b/resources/qml/Preferences/Materials/MaterialsSlot.qml index fb3cb9607d..2f4847103b 100644 --- a/resources/qml/Preferences/Materials/MaterialsSlot.qml +++ b/resources/qml/Preferences/Materials/MaterialsSlot.qml @@ -15,7 +15,7 @@ Rectangle id: materialSlot property var material: null property var hovered: false - property var is_favorite: material != null ? material.is_favorite : false + property var is_favorite: material != null && material.is_favorite height: UM.Theme.getSize("favorites_row").height width: parent.width @@ -73,11 +73,9 @@ Rectangle if (materialSlot.is_favorite) { base.materialManager.removeFavorite(material.root_material_id) - materialSlot.is_favorite = false return } base.materialManager.addFavorite(material.root_material_id) - materialSlot.is_favorite = true return } style: ButtonStyle diff --git a/resources/qml/Preferences/Materials/MaterialsTypeSection.qml b/resources/qml/Preferences/Materials/MaterialsTypeSection.qml index f98c19e0b3..8f34217cce 100644 --- a/resources/qml/Preferences/Materials/MaterialsTypeSection.qml +++ b/resources/qml/Preferences/Materials/MaterialsTypeSection.qml @@ -10,7 +10,7 @@ import QtQuick.Dialogs 1.2 import UM 1.2 as UM import Cura 1.0 as Cura -Rectangle +Item { id: material_type_section property var materialType diff --git a/resources/qml/Preferences/ProfilesPage.qml b/resources/qml/Preferences/ProfilesPage.qml index 7fb17b7aa1..d9b679e344 100644 --- a/resources/qml/Preferences/ProfilesPage.qml +++ b/resources/qml/Preferences/ProfilesPage.qml @@ -408,7 +408,7 @@ Item { anchors.left: parent.left anchors.leftMargin: UM.Theme.getSize("default_lining").width - text: section == "true" ? catalog.i18nc("@label", "Protected profiles") : catalog.i18nc("@label", "Custom profiles") + text: section == "true" ? catalog.i18nc("@label", "Default profiles") : catalog.i18nc("@label", "Custom profiles") font.bold: true } } @@ -471,7 +471,7 @@ Item Label { text: base.currentItemName - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") } } diff --git a/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml index 51eb14a441..98bb5c0405 100644 --- a/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml +++ b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml @@ -11,7 +11,6 @@ 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 @@ -98,15 +97,15 @@ Item Rectangle { - height: UM.Theme.getSize("print_setup_widget").height anchors { top: tabBar.visible ? tabBar.bottom : globalProfileRow.bottom + topMargin: -UM.Theme.getSize("default_lining").width left: parent.left leftMargin: parent.padding right: parent.right rightMargin: parent.padding - topMargin: -UM.Theme.getSize("default_lining").width + bottom: parent.bottom } z: tabBar.z - 1 // Don't show the border when only one extruder diff --git a/resources/qml/PrintSetupSelector/Custom/GlobalProfileSelector.qml b/resources/qml/PrintSetupSelector/Custom/GlobalProfileSelector.qml index 8baaf9a7ae..32c07a52a6 100644 --- a/resources/qml/PrintSetupSelector/Custom/GlobalProfileSelector.qml +++ b/resources/qml/PrintSetupSelector/Custom/GlobalProfileSelector.qml @@ -25,7 +25,7 @@ Item right: globalProfileSelection.left } text: catalog.i18nc("@label", "Profile") - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("text") verticalAlignment: Text.AlignVCenter } diff --git a/resources/qml/PrintSetupSelector/PrintSetupSelector.qml b/resources/qml/PrintSetupSelector/PrintSetupSelector.qml index 2d4d7f6cf1..48ac07679d 100644 --- a/resources/qml/PrintSetupSelector/PrintSetupSelector.qml +++ b/resources/qml/PrintSetupSelector/PrintSetupSelector.qml @@ -29,4 +29,7 @@ Cura.ExpandableComponent property var extrudersModel: CuraApplication.getExtrudersModel() contentItem: PrintSetupSelectorContents {} + + onExpandedChanged: UM.Preferences.setValue("view/settings_visible", expanded) + Component.onCompleted: expanded = UM.Preferences.getValue("view/settings_visible") } \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml b/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml index 6c678f7ce5..0b8fb89311 100644 --- a/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml +++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorContents.qml @@ -15,7 +15,7 @@ Item id: content width: UM.Theme.getSize("print_setup_widget").width - 2 * UM.Theme.getSize("default_margin").width - height: childrenRect.height + height: contents.height + buttonRow.height enum Mode { @@ -71,6 +71,15 @@ Item right: parent.right top: parent.top } + height: UM.Preferences.getValue("view/settings_list_height") - UM.Theme.getSize("default_margin").height + Connections + { + target: UM.Preferences + onPreferenceChanged: + { + customPrintSetup.height = UM.Preferences.getValue("view/settings_list_height"); + } + } visible: currentModeIndex == PrintSetupSelectorContents.Mode.Custom } } @@ -94,13 +103,14 @@ Item anchors { - top: buttonsSeparator.bottom + bottom: parent.bottom left: parent.left right: parent.right } Cura.SecondaryButton { + id: recommendedButton anchors.top: parent.top anchors.left: parent.left anchors.margins: parent.padding @@ -125,5 +135,58 @@ Item visible: currentModeIndex == PrintSetupSelectorContents.Mode.Recommended onClicked: currentModeIndex = PrintSetupSelectorContents.Mode.Custom } + + //Invisible area at the bottom with which you can resize the panel. + MouseArea + { + anchors + { + left: parent.left + right: parent.right + bottom: parent.bottom + top: recommendedButton.bottom + topMargin: UM.Theme.getSize("default_lining").height + } + cursorShape: Qt.SplitVCursor + visible: currentModeIndex == PrintSetupSelectorContents.Mode.Custom + drag + { + target: parent + axis: Drag.YAxis + } + onMouseYChanged: + { + if(drag.active) + { + // position of mouse relative to dropdown align vertical centre of mouse area to cursor + // v------------------------------v v------------v + var h = mouseY + buttonRow.y + content.y - height / 2 | 0; + if(h < 200 * screenScaleFactor) //Enforce a minimum size. + { + h = 200 * screenScaleFactor; + } + + //Absolute mouse Y position in the window, to prevent it from going outside the window. + var mouse_absolute_y = mapToGlobal(mouseX, mouseY).y - UM.Preferences.getValue("general/window_top"); + if(mouse_absolute_y > base.height) + { + h -= mouse_absolute_y - base.height; + } + + UM.Preferences.setValue("view/settings_list_height", h); + } + } + + UM.RecolorImage + { + width: parent.width * 0.05 + height: parent.height * 0.3 + + anchors.centerIn: parent + + source: UM.Theme.getIcon("grip_lines") + color: UM.Theme.getColor("lining") + } + } } } \ No newline at end of file diff --git a/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml b/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml index 94da5bdd6f..5ae9488cd3 100644 --- a/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml +++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml @@ -29,6 +29,7 @@ RowLayout } return "" } + font: UM.Theme.getFont("medium") UM.SettingPropertyProvider { @@ -43,6 +44,7 @@ RowLayout { source: UM.Theme.getIcon("category_infill") text: Cura.MachineManager.activeStack ? parseInt(infillDensity.properties.value) + "%" : "0%" + font: UM.Theme.getFont("medium") UM.SettingPropertyProvider { @@ -57,6 +59,7 @@ RowLayout { source: UM.Theme.getIcon("category_support") text: supportEnabled.properties.value == "True" ? enabledText : disabledText + font: UM.Theme.getFont("medium") UM.SettingPropertyProvider { @@ -71,6 +74,7 @@ RowLayout { source: UM.Theme.getIcon("category_adhesion") text: platformAdhesionType.properties.value != "skirt" && platformAdhesionType.properties.value != "none" ? enabledText : disabledText + font: UM.Theme.getFont("medium") UM.SettingPropertyProvider { diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedAdhesionSelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedAdhesionSelector.qml index a5f35f333b..941199707c 100644 --- a/resources/qml/PrintSetupSelector/Recommended/RecommendedAdhesionSelector.qml +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedAdhesionSelector.qml @@ -26,6 +26,7 @@ Item anchors.left: parent.left source: UM.Theme.getIcon("category_adhesion") text: catalog.i18nc("@label", "Adhesion") + font: UM.Theme.getFont("medium") width: labelColumnWidth } diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml index 0da53cc1c1..19f199fea6 100644 --- a/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedInfillDensitySelector.qml @@ -63,6 +63,7 @@ Item anchors.left: parent.left source: UM.Theme.getIcon("category_infill") text: catalog.i18nc("@label", "Infill") + " (%)" + font: UM.Theme.getFont("medium") width: labelColumnWidth } @@ -140,6 +141,7 @@ Item Label { text: index + font: UM.Theme.getFont("default") visible: (index % 20) == 0 // Only show steps of 20% anchors.horizontalCenter: parent.horizontalCenter y: UM.Theme.getSize("thin_margin").height diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml index 1e71134404..801e76382b 100644 --- a/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml @@ -173,6 +173,7 @@ Item id: qualityRowTitle source: UM.Theme.getIcon("category_layer_height") text: catalog.i18nc("@label", "Layer Height") + font: UM.Theme.getFont("medium") anchors.left: parent.left anchors.right: customisedSettings.left } @@ -271,6 +272,7 @@ Item return Math.round((settingsColumnWidth / qualityModel.totalTicks) * index - (width / 2)) } } + font: UM.Theme.getFont("default") } } } diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedSupportSelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedSupportSelector.qml index 87fb664713..0e834ac4df 100644 --- a/resources/qml/PrintSetupSelector/Recommended/RecommendedSupportSelector.qml +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedSupportSelector.qml @@ -27,6 +27,7 @@ Item visible: enableSupportCheckBox.visible source: UM.Theme.getIcon("category_support") text: catalog.i18nc("@label", "Support") + font: UM.Theme.getFont("medium") width: labelColumnWidth } diff --git a/resources/qml/PrintSetupTooltip.qml b/resources/qml/PrintSetupTooltip.qml index 4fa4ef9dd7..6b1538d849 100644 --- a/resources/qml/PrintSetupTooltip.qml +++ b/resources/qml/PrintSetupTooltip.qml @@ -2,9 +2,7 @@ // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.7 -import QtQuick.Controls 1.1 -import QtQuick.Controls.Styles 1.1 -import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 import UM 1.0 as UM @@ -43,7 +41,8 @@ UM.PointingRectangle { base.opacity = 0; } - Label { + Label + { id: label; anchors { top: parent.top; @@ -57,5 +56,6 @@ UM.PointingRectangle { textFormat: Text.RichText font: UM.Theme.getFont("default"); color: UM.Theme.getColor("tooltip_text"); + renderType: Text.NativeRendering } } diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 9ba78f778f..a19c02b0dd 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -80,7 +80,7 @@ Item id: extruderCurrentTemperature text: Math.round(extruderModel.hotendTemperature) + "°C" color: UM.Theme.getColor("text") - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") anchors.right: extruderTargetTemperature.left anchors.top: parent.top anchors.margins: UM.Theme.getSize("default_margin").width diff --git a/resources/qml/PrinterOutput/HeatedBedBox.qml b/resources/qml/PrinterOutput/HeatedBedBox.qml index ac541f707c..77421c8aad 100644 --- a/resources/qml/PrinterOutput/HeatedBedBox.qml +++ b/resources/qml/PrinterOutput/HeatedBedBox.qml @@ -67,7 +67,7 @@ Item { id: bedCurrentTemperature text: printerModel != null ? printerModel.bedTemperature + "°C" : "" - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") anchors.right: bedTargetTemperature.left anchors.top: parent.top diff --git a/resources/qml/PrinterOutput/OutputDeviceHeader.qml b/resources/qml/PrinterOutput/OutputDeviceHeader.qml index 16280eab5f..47f855266b 100644 --- a/resources/qml/PrinterOutput/OutputDeviceHeader.qml +++ b/resources/qml/PrinterOutput/OutputDeviceHeader.qml @@ -31,7 +31,7 @@ Item Label { id: outputDeviceNameLabel - font: UM.Theme.getFont("large") + font: UM.Theme.getFont("large_bold") color: UM.Theme.getColor("text") anchors.left: parent.left anchors.top: parent.top diff --git a/resources/qml/PrinterSelector/MachineSelector.qml b/resources/qml/PrinterSelector/MachineSelector.qml index 28e01c7ae9..9f0d3b4ac6 100644 --- a/resources/qml/PrinterSelector/MachineSelector.qml +++ b/resources/qml/PrinterSelector/MachineSelector.qml @@ -93,14 +93,16 @@ Cura.ExpandablePopup width: scroll.width - scroll.leftPadding - scroll.rightPadding property real maximumHeight: UM.Theme.getSize("machine_selector_widget_content").height - buttonRow.height - onHeightChanged: + // We use an extra property here, since we only want to to be informed about the content size changes. + onContentHeightChanged: { - scroll.height = Math.min(height, maximumHeight) + scroll.height = Math.min(contentHeight, maximumHeight) popup.height = scroll.height + buttonRow.height } + Component.onCompleted: { - scroll.height = Math.min(height, maximumHeight) + scroll.height = Math.min(contentHeight, maximumHeight) popup.height = scroll.height + buttonRow.height } diff --git a/resources/qml/PrinterSelector/MachineSelectorList.qml b/resources/qml/PrinterSelector/MachineSelectorList.qml index ea8068fa95..b9c20d0de1 100644 --- a/resources/qml/PrinterSelector/MachineSelectorList.qml +++ b/resources/qml/PrinterSelector/MachineSelectorList.qml @@ -10,15 +10,15 @@ import Cura 1.0 as Cura ListView { id: listView - height: childrenRect.height - model: Cura.PrintersModel {} + model: Cura.GlobalStacksModel {} section.property: "hasRemoteConnection" + property real contentHeight: childrenRect.height section.delegate: Label { text: section == "true" ? catalog.i18nc("@label", "Connected printers") : catalog.i18nc("@label", "Preset printers") width: parent.width - height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0 + height: UM.Theme.getSize("action_button").height leftPadding: UM.Theme.getSize("default_margin").width renderType: Text.NativeRendering font: UM.Theme.getFont("medium") diff --git a/resources/qml/Settings/SettingCategory.qml b/resources/qml/Settings/SettingCategory.qml index da731bcd55..1e88867889 100644 --- a/resources/qml/Settings/SettingCategory.qml +++ b/resources/qml/Settings/SettingCategory.qml @@ -73,7 +73,7 @@ Button text: definition.label textFormat: Text.PlainText renderType: Text.NativeRendering - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium_bold") color: { if (!base.enabled) diff --git a/resources/qml/ToolTip.qml b/resources/qml/ToolTip.qml new file mode 100644 index 0000000000..e82caf01b2 --- /dev/null +++ b/resources/qml/ToolTip.qml @@ -0,0 +1,63 @@ +// Copyright (c) 2018 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.7 +import QtQuick.Controls 2.3 + +import UM 1.0 as UM +import Cura 1.0 as Cura + +ToolTip +{ + enum ContentAlignment + { + AlignLeft, + AlignRight + } + + // Defines the alignment of the content, by default to the left + property int contentAlignment: Cura.ToolTip.ContentAlignment.AlignRight + + property alias tooltipText: tooltip.text + property var targetPoint: Qt.point(parent.x, y + Math.round(height/2)) + + id: tooltip + text: "" + delay: 500 + font: UM.Theme.getFont("default") + + // If the text is not set, just set the height to 0 to prevent it from showing + height: text != "" ? label.contentHeight + 2 * UM.Theme.getSize("thin_margin").width: 0 + + x: + { + if (contentAlignment == Cura.ToolTip.ContentAlignment.AlignLeft) + { + return (label.width + Math.round(UM.Theme.getSize("default_arrow").width * 1.2) + padding * 2) * -1 + } + return parent.width + Math.round(UM.Theme.getSize("default_arrow").width * 1.2 + padding) + } + + y: Math.round(parent.height / 2 - label.height / 2 ) - padding + + padding: UM.Theme.getSize("thin_margin").width + + background: UM.PointingRectangle + { + id: backgroundRect + color: UM.Theme.getColor("tooltip") + target: Qt.point(targetPoint.x - tooltip.x, targetPoint.y - tooltip.y) + arrowSize: UM.Theme.getSize("default_arrow").width + } + + contentItem: Label + { + id: label + text: tooltip.text + font: tooltip.font + wrapMode: Text.Wrap + textFormat: Text.RichText + color: UM.Theme.getColor("tooltip_text") + renderType: Text.NativeRendering + } +} \ No newline at end of file diff --git a/resources/qml/ToolbarButton.qml b/resources/qml/ToolbarButton.qml index adff73fb7c..b3f84bba1d 100644 --- a/resources/qml/ToolbarButton.qml +++ b/resources/qml/ToolbarButton.qml @@ -96,4 +96,11 @@ Button height: UM.Theme.getSize("button_icon").height } } + + Cura.ToolTip + { + id: tooltip + tooltipText: base.text + visible: base.hovered + } } diff --git a/resources/qml/ViewsSelector.qml b/resources/qml/ViewsSelector.qml index 1f5a0bbc85..0e9be649db 100644 --- a/resources/qml/ViewsSelector.qml +++ b/resources/qml/ViewsSelector.qml @@ -51,7 +51,7 @@ Cura.ExpandablePopup verticalAlignment: Text.AlignVCenter height: parent.height elide: Text.ElideRight - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("text_medium") renderType: Text.NativeRendering } @@ -68,7 +68,7 @@ Cura.ExpandablePopup } height: parent.height elide: Text.ElideRight - font: UM.Theme.getFont("default") + font: UM.Theme.getFont("medium") color: UM.Theme.getColor("text") renderType: Text.NativeRendering } diff --git a/resources/qml/qmldir b/resources/qml/qmldir index 1dc21150ce..80e0f8be46 100644 --- a/resources/qml/qmldir +++ b/resources/qml/qmldir @@ -14,4 +14,5 @@ PrinterTypeLabel 1.0 PrinterTypeLabel.qml ViewsSelector 1.0 ViewsSelector.qml ToolbarButton 1.0 ToolbarButton.qml SettingView 1.0 SettingView.qml -ProfileMenu 1.0 ProfileMenu.qml \ No newline at end of file +ProfileMenu 1.0 ProfileMenu.qml +ToolTip 1.0 ToolTip.qml \ No newline at end of file diff --git a/resources/themes/cura-dark/theme.json b/resources/themes/cura-dark/theme.json index 537fccbc5c..6b29073475 100644 --- a/resources/themes/cura-dark/theme.json +++ b/resources/themes/cura-dark/theme.json @@ -28,6 +28,7 @@ "machine_selector_bar": [39, 44, 48, 255], "machine_selector_active": [39, 44, 48, 255], + "machine_selector_printer_icon": [204, 204, 204, 255], "text": [255, 255, 255, 204], "text_detail": [255, 255, 255, 172], diff --git a/resources/themes/cura-light/icons/grip_lines.svg b/resources/themes/cura-light/icons/grip_lines.svg new file mode 100644 index 0000000000..253d1fb486 --- /dev/null +++ b/resources/themes/cura-light/icons/grip_lines.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/themes/cura-light/styles.qml b/resources/themes/cura-light/styles.qml index 89729fc08c..b314190e24 100755 --- a/resources/themes/cura-light/styles.qml +++ b/resources/themes/cura-light/styles.qml @@ -207,8 +207,8 @@ QtObject anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter - text: control.text; - font: Theme.getFont("button_tooltip") + text: control.text + font: Theme.getFont("default") color: Theme.getColor("tooltip_text") } } @@ -256,7 +256,7 @@ QtObject source: control.iconSource width: Theme.getSize("button_icon").width height: Theme.getSize("button_icon").height - color: Theme.getColor("toolbar_button_text") + color: Theme.getColor("icon") sourceSize: Theme.getSize("button_icon") } @@ -585,6 +585,7 @@ QtObject text: control.unit ? control.unit : "" color: Theme.getColor("setting_unit"); font: Theme.getFont("default"); + renderType: Text.NativeRendering } } } diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 2b9ce3d218..42ef632673 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -6,17 +6,17 @@ "fonts": { "large": { "size": 1.35, - "weight": 63, + "weight": 40, "family": "Noto Sans" }, - "large_nonbold": { + "large_bold": { "size": 1.35, - "weight": 50, + "weight": 63, "family": "Noto Sans" }, "medium": { "size": 1.16, - "weight": 50, + "weight": 40, "family": "Noto Sans" }, "medium_bold": { @@ -25,29 +25,24 @@ "family": "Noto Sans" }, "default": { - "size": 1.0, - "weight": 50, + "size": 0.95, + "weight": 40, "family": "Noto Sans" }, "default_bold": { - "size": 1.0, + "size": 0.95, "weight": 63, "family": "Noto Sans" }, "default_italic": { - "size": 1.0, - "weight": 50, + "size": 0.95, + "weight": 40, "italic": true, "family": "Noto Sans" }, "small": { - "size": 0.85, - "weight": 50, - "family": "Noto Sans" - }, - "very_small": { "size": 0.7, - "weight": 50, + "weight": 40, "family": "Noto Sans" } }, @@ -118,7 +113,6 @@ "warning": [245, 166, 35, 255], "disabled": [229, 229, 229, 255], - "toolbar_button_text": [8, 7, 63, 255], "toolbar_button_hover": [232, 242, 252, 255], "toolbar_button_active": [232, 242, 252, 255], "toolbar_button_active_hover": [232, 242, 252, 255], @@ -303,7 +297,7 @@ "printer_config_mismatch": [127, 127, 127, 255], "toolbox_header_button_text_active": [0, 0, 0, 255], - "toolbox_header_button_text_inactive": [128, 128, 128, 255], + "toolbox_header_button_text_inactive": [0, 0, 0, 255], "toolbox_header_button_text_hovered": [0, 0, 0, 255], "favorites_header_bar": [245, 245, 245, 255], @@ -492,7 +486,7 @@ "toolbox_detail_header": [1.0, 14.0], "toolbox_detail_tile": [1.0, 8.0], "toolbox_back_column": [6.0, 1.0], - "toolbox_back_button": [4.0, 2.0], + "toolbox_back_button": [6.0, 2.0], "toolbox_installed_tile": [1.0, 8.0], "toolbox_property_label": [1.0, 2.0], "toolbox_heading_label": [1.0, 3.8],