Merge pull request #13938 from Ultimaker/CURA-9347_safe_to_profile_button

[CURA-9347] Easier 'compare-and-safe' for (new or custom) profiles
This commit is contained in:
Jelle Spijker 2022-12-05 15:34:57 +01:00 committed by GitHub
commit b8b433ed5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 209 additions and 87 deletions

View File

@ -709,6 +709,7 @@ class CuraApplication(QtApplication):
self.showMessageBox.emit(title, text, informativeText, detailedText, buttons, icon) self.showMessageBox.emit(title, text, informativeText, detailedText, buttons, icon)
showDiscardOrKeepProfileChanges = pyqtSignal() showDiscardOrKeepProfileChanges = pyqtSignal()
showCompareAndSaveProfileChanges = pyqtSignal(int)
def discardOrKeepProfileChanges(self) -> bool: def discardOrKeepProfileChanges(self) -> bool:
has_user_interaction = False has_user_interaction = False

View File

@ -184,7 +184,8 @@ class QualityManagementModel(ListModel):
container_registry.addContainer(container.duplicate(new_id, new_name)) container_registry.addContainer(container.duplicate(new_id, new_name))
@pyqtSlot(str) @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. """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 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) 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": 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. """Create a quality changes container with the given set-up.

View File

@ -496,10 +496,7 @@ UM.MainWindow
target: Cura.Actions.addProfile target: Cura.Actions.addProfile
function onTriggered() function onTriggered()
{ {
preferences.show(); createNewQualityDialog.visible = true;
preferences.setPage(4);
// Create a new profile after a very short delay so the preference page has time to initiate
createProfileTimer.start();
} }
} }
@ -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. // 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. // We need to do this in order to keep the bindings intact.
Connections Connections
@ -816,11 +804,16 @@ UM.MainWindow
Connections Connections
{ {
target: CuraApplication target: CuraApplication
function onShowDiscardOrKeepProfileChanges() function onShowCompareAndSaveProfileChanges(profileState)
{ {
discardOrKeepProfileChangesDialogLoader.sourceComponent = discardOrKeepProfileChangesDialogComponent discardOrKeepProfileChangesDialogLoader.sourceComponent = discardOrKeepProfileChangesDialogComponent
discardOrKeepProfileChangesDialogLoader.item.buttonState = profileState
discardOrKeepProfileChangesDialogLoader.item.show() discardOrKeepProfileChangesDialogLoader.item.show()
} }
function onShowDiscardOrKeepProfileChanges()
{
onShowCompareAndSaveProfileChanges(DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep)
}
} }
Cura.WizardDialog 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",
"<b>Only user changed settings will be saved in the custom profile.</b><br/>" +
"For materials that support it, the new custom profile will inherit properties from <b>%1</b>."
).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. * Function to check whether a QML object has a certain type.
* Taken from StackOverflow: https://stackoverflow.com/a/28384228 and * Taken from StackOverflow: https://stackoverflow.com/a/28384228 and

View File

@ -12,8 +12,13 @@ UM.Dialog
id: base id: base
title: catalog.i18nc("@title:window", "Discard or Keep changes") title: catalog.i18nc("@title:window", "Discard or Keep changes")
onAccepted: CuraApplication.discardOrKeepProfileChangesClosed("discard") enum ButtonsType { DiscardOrKeep, SaveFromBuiltIn, SaveFromCustom}
onRejected: CuraApplication.discardOrKeepProfileChangesClosed("keep") 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 minimumWidth: UM.Theme.getSize("popup_dialog").width
minimumHeight: UM.Theme.getSize("popup_dialog").height minimumHeight: UM.Theme.getSize("popup_dialog").height
@ -98,9 +103,12 @@ UM.Dialog
buttonSpacing: UM.Theme.getSize("thin_margin").width buttonSpacing: UM.Theme.getSize("thin_margin").width
leftButtons: [ leftButtons:
[
Cura.ComboBox Cura.ComboBox
{ {
visible: buttonState == DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep
implicitHeight: UM.Theme.getSize("combobox").height implicitHeight: UM.Theme.getSize("combobox").height
implicitWidth: UM.Theme.getSize("combobox").width implicitWidth: UM.Theme.getSize("combobox").width
@ -146,12 +154,28 @@ UM.Dialog
id: discardButton id: discardButton
text: catalog.i18nc("@action:button", "Discard changes") text: catalog.i18nc("@action:button", "Discard changes")
onClicked: base.accept() onClicked: base.accept()
visible: buttonState == DiscardOrKeepProfileChangesDialog.ButtonsType.DiscardOrKeep
}, },
Cura.SecondaryButton Cura.SecondaryButton
{ {
id: keepButton id: keepButton
text: catalog.i18nc("@action:button", "Keep changes") text: catalog.i18nc("@action:button", "Keep changes")
onClicked: base.reject() 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()
} }
] ]
} }

View File

@ -15,17 +15,23 @@ UM.Dialog
buttonSpacing: UM.Theme.getSize("default_margin").width buttonSpacing: UM.Theme.getSize("default_margin").width
property string object: "" property string object: ""
property string objectPlaceholder: ""
property alias newName: nameField.text property alias newName: nameField.text
property bool validName: true property bool validName: true
property string validationError property string validationError
property string dialogTitle: catalog.i18nc("@title:window", "Rename") property string dialogTitle: catalog.i18nc("@title:window", "Rename")
property string explanation: catalog.i18nc("@info", "Please provide a new name.") 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<Item> extraInfo
title: dialogTitle title: dialogTitle
backgroundColor: UM.Theme.getColor("main_background") backgroundColor: UM.Theme.getColor("main_background")
minimumWidth: UM.Theme.getSize("small_popup_dialog").width 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 width: minimumWidth
height: minimumHeight height: minimumHeight
@ -55,11 +61,33 @@ UM.Dialog
id: nameField id: nameField
width: parent.width width: parent.width
text: base.object text: base.object
placeholderText: base.objectPlaceholder
placeholderTextColor: UM.Theme.getColor("text_field_text_disabled")
maximumLength: 40 maximumLength: 40
selectByMouse: true selectByMouse: true
onTextChanged: base.textChanged(text) 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 UM.Label
{ {
visible: !base.validName visible: !base.validName
@ -67,20 +95,23 @@ UM.Dialog
} }
} }
rightButtons: [ leftButtons:
Cura.SecondaryButton [
Cura.TertiaryButton
{ {
id: cancelButton id: cancelButton
text: catalog.i18nc("@action:button","Cancel") text: catalog.i18nc("@action:button","Cancel")
onClicked: base.reject() onClicked: base.reject()
}, }
]
rightButtons:
[
Cura.PrimaryButton Cura.PrimaryButton
{ {
id: okButton id: okButton
text: catalog.i18nc("@action:button", "OK") text: base.okButtonText
onClicked: base.accept() onClicked: base.accept()
enabled: base.validName enabled: base.validName
} }
] ]
} }

View File

@ -52,8 +52,8 @@ Item
id: intentSelection id: intentSelection
onClicked: menu.opened ? menu.close() : menu.open() onClicked: menu.opened ? menu.close() : menu.open()
anchors.right: parent.right anchors.right: profileWarningReset.left
width: UM.Theme.getSize("print_setup_big_item").width width: UM.Theme.getSize("print_setup_big_item").width - profileWarningReset.width
height: textLabel.contentHeight + 2 * UM.Theme.getSize("narrow_margin").height height: textLabel.contentHeight + 2 * UM.Theme.getSize("narrow_margin").height
hoverEnabled: true hoverEnabled: true
@ -152,6 +152,14 @@ Item
} }
} }
ProfileWarningReset
{
id: profileWarningReset
width: childrenRect.width
anchors.right: parent.right
fullWarning: false
}
QualitiesWithIntentMenu QualitiesWithIntentMenu
{ {
id: menu id: menu

View File

@ -223,58 +223,6 @@ Popup
color: borderColor 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 MenuButton
{ {
id: manageProfilesButton id: manageProfilesButton

View File

@ -1,19 +1,27 @@
// Copyright (C) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10 import QtQuick 2.10
import UM 1.6 as UM import UM 1.6 as UM
import Cura 1.6 as Cura import Cura 1.6 as Cura
import "../Dialogs"
Item 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 height: visible ? UM.Theme.getSize("action_button_icon").height : 0
visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.MachineManager.hasCustomQuality visible: Cura.SimpleModeSettingsManager.isProfileCustomized || Cura.MachineManager.hasCustomQuality
Rectangle Rectangle
{ {
id: warningIcon id: warningIcon
visible: fullWarning
color: UM.Theme.getColor("um_yellow_5") color: UM.Theme.getColor("um_yellow_5")
height: UM.Theme.getSize("action_button_icon").height height: UM.Theme.getSize("action_button_icon").height
width: height width: visible ? height : 0
radius: width radius: width
anchors anchors
{ {
@ -31,7 +39,8 @@ Item
UM.Label UM.Label
{ {
id: warning id: warning
width: parent.width - warningIcon.width - resetToDefaultQualityButton.width visible: fullWarning
width: visible ? parent.width - warningIcon.width - (compareAndSaveButton.width + resetToDefaultQualityButton.width) : 0
anchors anchors
{ {
left: warningIcon.right left: warningIcon.right
@ -76,11 +85,14 @@ Item
PropertyChanges PropertyChanges
{ {
target: warning 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 <b>%1</b> were overridden.").arg(profile_name);
}
} }
} }
] ]
} }
UM.SimpleButton UM.SimpleButton
@ -90,17 +102,63 @@ Item
width: height width: height
iconSource: UM.Theme.getIcon("ArrowReset") iconSource: UM.Theme.getIcon("ArrowReset")
anchors 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 right: parent.right
verticalCenter: parent.verticalCenter 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.")
} }
} }
}
}

View File

@ -6,6 +6,7 @@ import QtQuick.Layouts 1.1
import UM 1.6 as UM import UM 1.6 as UM
import Cura 1.6 as Cura import Cura 1.6 as Cura
import ".."
Item Item
{ {

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path fill-rule="evenodd" d="M3 18C3 19.6569 4.34315 21 6 21H18C19.6569 21 21 19.6569 21 18V8L16 3H6C4.34315 3 3 4.34315 3 6V18ZM5 5H15.1716L19 8.82843V19H5V5Z"/>
<path fill-rule="evenodd" d="M7 5H15V9H7V5ZM9 5V7H13V5H9Z"/>
<path fill-rule="evenodd" d="M15 15H9V19H15V15ZM7 13V20H17V13H7Z"/>
</svg>

After

Width:  |  Height:  |  Size: 413 B