diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 74811e724f..7f9f0ef68d 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -709,6 +709,7 @@ class CuraApplication(QtApplication): self.showMessageBox.emit(title, text, informativeText, detailedText, buttons, icon) showDiscardOrKeepProfileChanges = pyqtSignal() + showCompareAndSaveProfileChanges = pyqtSignal(int) def discardOrKeepProfileChanges(self) -> bool: has_user_interaction = False diff --git a/cura/Machines/Models/QualityManagementModel.py b/cura/Machines/Models/QualityManagementModel.py index b4fb8b38b5..3c3bc9a6e9 100644 --- a/cura/Machines/Models/QualityManagementModel.py +++ b/cura/Machines/Models/QualityManagementModel.py @@ -184,7 +184,8 @@ class QualityManagementModel(ListModel): container_registry.addContainer(container.duplicate(new_id, new_name)) @pyqtSlot(str) - def createQualityChanges(self, base_name: str) -> None: + @pyqtSlot(str, bool) + def createQualityChanges(self, base_name: str, activate_after_success: bool = False) -> None: """Create quality changes containers from the user containers in the active stacks. This will go through the global and extruder stacks and create quality_changes containers from the user @@ -233,6 +234,14 @@ class QualityManagementModel(ListModel): container_registry.addContainer(new_changes) + if activate_after_success: + # At this point, the QualityChangesGroup object for the new changes may not exist yet. + # This can be forced by asking for all of them. At that point it's just as well to loop. + for quality_changes in ContainerTree.getInstance().getCurrentQualityChangesGroups(): + if quality_changes.name == unique_name: + machine_manager.setQualityChangesGroup(quality_changes) + break + def _createQualityChanges(self, quality_type: str, intent_category: Optional[str], new_name: str, machine: "GlobalStack", extruder_stack: Optional["ExtruderStack"]) -> "InstanceContainer": """Create a quality changes container with the given set-up. diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 2ec342f502..6e36587b23 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -496,10 +496,7 @@ UM.MainWindow target: Cura.Actions.addProfile function onTriggered() { - preferences.show(); - preferences.setPage(4); - // Create a new profile after a very short delay so the preference page has time to initiate - createProfileTimer.start(); + createNewQualityDialog.visible = true; } } @@ -547,15 +544,6 @@ UM.MainWindow } } - Timer - { - id: createProfileTimer - repeat: false - interval: 1 - - onTriggered: preferences.getCurrentItem().createProfile() - } - // BlurSettings is a way to force the focus away from any of the setting items. // We need to do this in order to keep the bindings intact. Connections @@ -816,11 +804,16 @@ UM.MainWindow Connections { target: CuraApplication - function onShowDiscardOrKeepProfileChanges() + function onShowCompareAndSaveProfileChanges(profileState) { discardOrKeepProfileChangesDialogLoader.sourceComponent = discardOrKeepProfileChangesDialogComponent + discardOrKeepProfileChangesDialogLoader.item.buttonState = profileState discardOrKeepProfileChangesDialogLoader.item.show() } + function onShowDiscardOrKeepProfileChanges() + { + onShowCompareAndSaveProfileChanges(DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep) + } } Cura.WizardDialog @@ -885,6 +878,49 @@ UM.MainWindow } } + Cura.RenameDialog + { + id: createNewQualityDialog + title: catalog.i18nc("@title:window", "Save Custom Profile") + objectPlaceholder: catalog.i18nc("@textfield:placeholder", "New Custom Profile") + explanation: catalog.i18nc("@info", "Custom profile name:") + extraInfo: + [ + UM.ColorImage + { + width: UM.Theme.getSize("message_type_icon").width + height: UM.Theme.getSize("message_type_icon").height + source: UM.Theme.getIcon("Information") + color: UM.Theme.getColor("text") + }, + Column + { + UM.Label + { + text: catalog.i18nc + ( + "@label %i will be replaced with a profile name", + "Only user changed settings will be saved in the custom profile.
" + + "For materials that support it, the new custom profile will inherit properties from %1." + ).arg(Cura.MachineManager.activeQualityOrQualityChangesName) + wrapMode: Text.WordWrap + width: parent.parent.width - 2 * UM.Theme.getSize("message_type_icon").width + } + Cura.TertiaryButton + { + text: catalog.i18nc("@action:button", "Learn more about Cura print profiles") + iconSource: UM.Theme.getIcon("LinkExternal") + isIconOnRightSide: true + leftPadding: 0 + rightPadding: 0 + onClicked: Qt.openUrlExternally("https://support.ultimaker.com/s/article/1667337576882") + } + } + ] + okButtonText: catalog.i18nc("@button", "Save new profile") + onAccepted: CuraApplication.getQualityManagementModel().createQualityChanges(newName, true); + } + /** * Function to check whether a QML object has a certain type. * Taken from StackOverflow: https://stackoverflow.com/a/28384228 and diff --git a/resources/qml/Dialogs/DiscardOrKeepProfileChangesDialog.qml b/resources/qml/Dialogs/DiscardOrKeepProfileChangesDialog.qml index 0fecb6b662..8dbe18ccff 100644 --- a/resources/qml/Dialogs/DiscardOrKeepProfileChangesDialog.qml +++ b/resources/qml/Dialogs/DiscardOrKeepProfileChangesDialog.qml @@ -12,8 +12,13 @@ UM.Dialog id: base title: catalog.i18nc("@title:window", "Discard or Keep changes") - onAccepted: CuraApplication.discardOrKeepProfileChangesClosed("discard") - onRejected: CuraApplication.discardOrKeepProfileChangesClosed("keep") + enum ButtonsType { DiscardOrKeep, SaveFromBuiltIn, SaveFromCustom} + property int buttonState: DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep + + onAccepted: buttonState == DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep ? + CuraApplication.discardOrKeepProfileChangesClosed("discard") : Cura.Actions.addProfile.trigger() + onRejected: buttonState == DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep ? + CuraApplication.discardOrKeepProfileChangesClosed("keep") : Cura.Actions.updateProfile.trigger() minimumWidth: UM.Theme.getSize("popup_dialog").width minimumHeight: UM.Theme.getSize("popup_dialog").height @@ -98,9 +103,12 @@ UM.Dialog buttonSpacing: UM.Theme.getSize("thin_margin").width - leftButtons: [ + leftButtons: + [ Cura.ComboBox { + visible: buttonState == DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep + implicitHeight: UM.Theme.getSize("combobox").height implicitWidth: UM.Theme.getSize("combobox").width @@ -146,12 +154,28 @@ UM.Dialog id: discardButton text: catalog.i18nc("@action:button", "Discard changes") onClicked: base.accept() + visible: buttonState == DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep }, Cura.SecondaryButton { id: keepButton text: catalog.i18nc("@action:button", "Keep changes") onClicked: base.reject() + visible: buttonState == DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep + }, + Cura.SecondaryButton + { + id: overwriteButton + text: catalog.i18nc("@action:button", "Save as new custom profile") + visible: buttonState != DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep + onClicked: base.accept() + }, + Cura.PrimaryButton + { + id: saveButton + text: catalog.i18nc("@action:button", "Save changes") + visible: buttonState == DiscardOrKeepProfileChangesDialog.ButtonsType.SaveFromCustom + onClicked: base.reject() } ] } diff --git a/resources/qml/Preferences/RenameDialog.qml b/resources/qml/Dialogs/RenameDialog.qml similarity index 64% rename from resources/qml/Preferences/RenameDialog.qml rename to resources/qml/Dialogs/RenameDialog.qml index 7bcd65ed5d..52cfe3a26e 100644 --- a/resources/qml/Preferences/RenameDialog.qml +++ b/resources/qml/Dialogs/RenameDialog.qml @@ -15,17 +15,23 @@ UM.Dialog buttonSpacing: UM.Theme.getSize("default_margin").width property string object: "" + property string objectPlaceholder: "" property alias newName: nameField.text property bool validName: true property string validationError property string dialogTitle: catalog.i18nc("@title:window", "Rename") property string explanation: catalog.i18nc("@info", "Please provide a new name.") + property string okButtonText: catalog.i18nc("@action:button", "OK") + + // Extra Information for the user about the current rename can go here, can be left alone if not needed. + // For example; An icon and a text-field and a tertiary button providing a link. + property list extraInfo title: dialogTitle backgroundColor: UM.Theme.getColor("main_background") minimumWidth: UM.Theme.getSize("small_popup_dialog").width - minimumHeight: UM.Theme.getSize("small_popup_dialog").height + minimumHeight: UM.Theme.getSize("small_popup_dialog").height + extraInfoHolder.height width: minimumWidth height: minimumHeight @@ -55,11 +61,33 @@ UM.Dialog id: nameField width: parent.width text: base.object + placeholderText: base.objectPlaceholder + placeholderTextColor: UM.Theme.getColor("text_field_text_disabled") maximumLength: 40 selectByMouse: true onTextChanged: base.textChanged(text) } + // spacer + Item + { + height: UM.Theme.getSize("wide_margin").height + width: height + } + + Row + { + id: extraInfoHolder + anchors + { + left: parent.left + right: parent.right + margins: UM.Theme.getSize("default_margin").height + } + spacing: UM.Theme.getSize("default_margin").height + children: extraInfo + } + UM.Label { visible: !base.validName @@ -67,20 +95,23 @@ UM.Dialog } } - rightButtons: [ - Cura.SecondaryButton + leftButtons: + [ + Cura.TertiaryButton { id: cancelButton text: catalog.i18nc("@action:button","Cancel") onClicked: base.reject() - }, + } + ] + rightButtons: + [ Cura.PrimaryButton { id: okButton - text: catalog.i18nc("@action:button", "OK") + text: base.okButtonText onClicked: base.accept() enabled: base.validName } ] } - diff --git a/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml index e64f211cd1..5742e12a3c 100644 --- a/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml +++ b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml @@ -52,8 +52,8 @@ Item id: intentSelection onClicked: menu.opened ? menu.close() : menu.open() - anchors.right: parent.right - width: UM.Theme.getSize("print_setup_big_item").width + anchors.right: profileWarningReset.left + width: UM.Theme.getSize("print_setup_big_item").width - profileWarningReset.width height: textLabel.contentHeight + 2 * UM.Theme.getSize("narrow_margin").height hoverEnabled: true @@ -152,6 +152,14 @@ Item } } + ProfileWarningReset + { + id: profileWarningReset + width: childrenRect.width + anchors.right: parent.right + fullWarning: false + } + QualitiesWithIntentMenu { id: menu diff --git a/resources/qml/PrintSetupSelector/Custom/QualitiesWithIntentMenu.qml b/resources/qml/PrintSetupSelector/Custom/QualitiesWithIntentMenu.qml index a2624dbf14..1aa10a9b42 100644 --- a/resources/qml/PrintSetupSelector/Custom/QualitiesWithIntentMenu.qml +++ b/resources/qml/PrintSetupSelector/Custom/QualitiesWithIntentMenu.qml @@ -223,58 +223,6 @@ Popup color: borderColor } - MenuButton - { - labelText: Cura.Actions.addProfile.text - - anchors.left: parent.left - anchors.right: parent.right - - enabled: Cura.Actions.addProfile.enabled - onClicked: - { - Cura.Actions.addProfile.trigger() - popup.visible = false - } - } - MenuButton - { - labelText: Cura.Actions.updateProfile.text - anchors.left: parent.left - anchors.right: parent.right - - enabled: Cura.Actions.updateProfile.enabled - - onClicked: - { - popup.visible = false - Cura.Actions.updateProfile.trigger() - } - } - MenuButton - { - text: catalog.i18nc("@action:button", "Discard current changes") - - anchors.left: parent.left - anchors.right: parent.right - - enabled: Cura.MachineManager.hasUserSettings - - onClicked: - { - popup.visible = false - Cura.ContainerManager.clearUserContainers() - } - } - - Rectangle - { - height: UM.Theme.getSize("default_lining").width - anchors.left: parent.left - anchors.right: parent.right - color: borderColor - } - MenuButton { id: manageProfilesButton diff --git a/resources/qml/PrintSetupSelector/Recommended/ProfileWarningReset.qml b/resources/qml/PrintSetupSelector/ProfileWarningReset.qml similarity index 51% rename from resources/qml/PrintSetupSelector/Recommended/ProfileWarningReset.qml rename to resources/qml/PrintSetupSelector/ProfileWarningReset.qml index 10f006538b..5e6a3d8157 100644 --- a/resources/qml/PrintSetupSelector/Recommended/ProfileWarningReset.qml +++ b/resources/qml/PrintSetupSelector/ProfileWarningReset.qml @@ -1,19 +1,27 @@ +// Copyright (C) 2022 UltiMaker +// Cura is released under the terms of the LGPLv3 or higher. + import QtQuick 2.10 import UM 1.6 as UM import Cura 1.6 as Cura +import "../Dialogs" + Item { + property bool fullWarning: true // <- Can you see the warning icon and the text, or is it just the buttons? + height: visible ? UM.Theme.getSize("action_button_icon").height : 0 visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.MachineManager.hasCustomQuality Rectangle { id: warningIcon + visible: fullWarning color: UM.Theme.getColor("um_yellow_5") height: UM.Theme.getSize("action_button_icon").height - width: height + width: visible ? height : 0 radius: width anchors { @@ -31,7 +39,8 @@ Item UM.Label { id: warning - width: parent.width - warningIcon.width - resetToDefaultQualityButton.width + visible: fullWarning + width: visible ? parent.width - warningIcon.width - (compareAndSaveButton.width + resetToDefaultQualityButton.width) : 0 anchors { left: warningIcon.right @@ -76,11 +85,14 @@ Item PropertyChanges { target: warning - text: catalog.i18nc("@info", "Some settings were changed.") + text: + { + var profile_name = Cura.MachineManager.activeQualityOrQualityChangesName; + return catalog.i18nc("@info %1 is the name of a profile", "Some setting-values defined in %1 were overridden.").arg(profile_name); + } } } ] - } UM.SimpleButton @@ -90,17 +102,63 @@ Item width: height iconSource: UM.Theme.getIcon("ArrowReset") anchors + { + right: buttonsSpacer.left + verticalCenter: parent.verticalCenter + } + + color: enabled ? UM.Theme.getColor("accent_1") : UM.Theme.getColor("disabled") + hoverColor: UM.Theme.getColor("primary_hover") + + enabled: Cura.MachineManager.hasCustomQuality || Cura.SimpleModeSettingsManager.isProfileCustomized + onClicked: Cura.MachineManager.resetToUseDefaultQuality() + + UM.ToolTip + { + visible: parent.hovered + y: parent.y + parent.height + UM.Theme.getSize("default_margin").height + targetPoint: Qt.point(parent.x, Math.round(parent.y + parent.height / 2)) + tooltipText: catalog.i18nc("@info", "Reset to defaults.") + } + } + + // Spacer + Item + { + id: buttonsSpacer + width: UM.Theme.getSize("action_button_icon").height + anchors.right: compareAndSaveButton.left + } + + UM.SimpleButton + { + id: compareAndSaveButton + height: UM.Theme.getSize("action_button_icon").height + width: height + iconSource: UM.Theme.getIcon("Save") + anchors { right: parent.right verticalCenter: parent.verticalCenter } - color: UM.Theme.getColor("accent_1") + color: enabled ? UM.Theme.getColor("accent_1") : UM.Theme.getColor("disabled") + hoverColor: UM.Theme.getColor("primary_hover") - onClicked: + enabled: Cura.SimpleModeSettingsManager.isProfileCustomized + onClicked: CuraApplication.showCompareAndSaveProfileChanges + ( + Cura.MachineManager.hasCustomQuality ? + DiscardOrKeepProfileChangesDialog.ButtonsType.SaveFromCustom : + DiscardOrKeepProfileChangesDialog.ButtonsType.SaveFromBuiltIn + ) + + UM.ToolTip { - Cura.MachineManager.resetToUseDefaultQuality() + visible: parent.hovered + y: parent.y + parent.height + UM.Theme.getSize("default_margin").height + targetPoint: Qt.point(parent.x, Math.round(parent.y + parent.height / 2)) + tooltipText: catalog.i18nc("@info", "Compare and save.") } } - -} \ No newline at end of file +} diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedPrintSetup.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedPrintSetup.qml index 94de16141f..37517709a9 100644 --- a/resources/qml/PrintSetupSelector/Recommended/RecommendedPrintSetup.qml +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedPrintSetup.qml @@ -6,6 +6,7 @@ import QtQuick.Layouts 1.1 import UM 1.6 as UM import Cura 1.6 as Cura +import ".." Item { diff --git a/resources/themes/cura-light/icons/default/Save.svg b/resources/themes/cura-light/icons/default/Save.svg new file mode 100644 index 0000000000..61887b084c --- /dev/null +++ b/resources/themes/cura-light/icons/default/Save.svg @@ -0,0 +1,6 @@ + + + + + +