Merge pull request #13972 from Ultimaker/CURA-9793_extend_recommended_print_settings

[CURA-9793] Extend recommended print settings
This commit is contained in:
Casper Lamboo 2022-12-12 14:38:46 +01:00 committed by GitHub
commit e558752ed0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1081 additions and 839 deletions

View File

@ -2,13 +2,15 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from PyQt6.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant # For communicating data and events to Qt. from PyQt6.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant # For communicating data and events to Qt.
from UM.Application import Application
from UM.FlameProfiler import pyqtSlot from UM.FlameProfiler import pyqtSlot
import cura.CuraApplication # To get the global container stack to find the current machine. import cura.CuraApplication # To get the global container stack to find the current machine.
from UM.Util import parseBool
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
from UM.Logger import Logger from UM.Logger import Logger
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
from UM.Settings.ContainerRegistry import ContainerRegistry # Finding containers by ID. from UM.Settings.ContainerRegistry import ContainerRegistry # Finding containers by ID.
@ -45,6 +47,7 @@ class ExtruderManager(QObject):
self._selected_object_extruders = [] # type: List[Union[str, "ExtruderStack"]] self._selected_object_extruders = [] # type: List[Union[str, "ExtruderStack"]]
Selection.selectionChanged.connect(self.resetSelectedObjectExtruders) Selection.selectionChanged.connect(self.resetSelectedObjectExtruders)
Application.getInstance().globalContainerStackChanged.connect(self.emitGlobalStackExtrudersChanged) # When the machine is swapped we must update the active machine extruders
extrudersChanged = pyqtSignal(QVariant) extrudersChanged = pyqtSignal(QVariant)
"""Signal to notify other components when the list of extruders for a machine definition changes.""" """Signal to notify other components when the list of extruders for a machine definition changes."""
@ -52,6 +55,21 @@ class ExtruderManager(QObject):
activeExtruderChanged = pyqtSignal() activeExtruderChanged = pyqtSignal()
"""Notify when the user switches the currently active extruder.""" """Notify when the user switches the currently active extruder."""
def emitGlobalStackExtrudersChanged(self):
# HACK
# The emit function can't be directly connected to another signal. This wrapper function is required.
# The extrudersChanged signal is emitted early when changing machines. This triggers it a second time
# after the extruder have changed properly. This is important for any QML using ExtruderManager.extruderIds
# This is a hack, but other behaviour relys on the updating in this order.
self.extrudersChanged.emit(self._application.getGlobalContainerStack().getId())
@pyqtProperty(int, notify = extrudersChanged)
def enabledExtruderCount(self) -> int:
global_container_stack = self._application.getGlobalContainerStack()
if global_container_stack:
return len([extruder for extruder in global_container_stack.extruderList if parseBool(extruder.getMetaDataEntry("enabled", "True"))])
return 0
@pyqtProperty(str, notify = activeExtruderChanged) @pyqtProperty(str, notify = activeExtruderChanged)
def activeExtruderStackId(self) -> Optional[str]: def activeExtruderStackId(self) -> Optional[str]:
"""Gets the unique identifier of the currently active extruder stack. """Gets the unique identifier of the currently active extruder stack.

View File

@ -42,21 +42,8 @@ class SimpleModeSettingsManager(QObject):
for extruder_stack in global_stack.extruderList: for extruder_stack in global_stack.extruderList:
user_setting_keys.update(extruder_stack.userChanges.getAllKeys()) user_setting_keys.update(extruder_stack.userChanges.getAllKeys())
# remove settings that are visible in recommended (we don't show the reset button for those)
for skip_key in self.__ignored_custom_setting_keys:
if skip_key in user_setting_keys:
user_setting_keys.remove(skip_key)
has_customized_user_settings = len(user_setting_keys) > 0 has_customized_user_settings = len(user_setting_keys) > 0
if has_customized_user_settings != self._is_profile_customized: if has_customized_user_settings != self._is_profile_customized:
self._is_profile_customized = has_customized_user_settings self._is_profile_customized = has_customized_user_settings
self.isProfileCustomizedChanged.emit() self.isProfileCustomizedChanged.emit()
# These are the settings included in the Simple ("Recommended") Mode, so only when the other settings have been
# changed, we consider it as a user customized profile in the Simple ("Recommended") Mode.
__ignored_custom_setting_keys = ["support_enable",
"infill_sparse_density",
"gradual_infill_steps",
"adhesion_type",
"support_extruder_nr"]

View File

@ -27,7 +27,7 @@ Item
Row Row
{ {
height: parent.height height: parent.height
spacing: UM.Theme.getSize("print_setup_slider_handle").width // TODO: Theme! (Should be same as extruder spacing) spacing: UM.Theme.getSize("slider_handle").width // TODO: Theme! (Should be same as extruder spacing)
// This wrapper ensures that the buildplate icon is located centered // This wrapper ensures that the buildplate icon is located centered
// below an extruder icon. // below an extruder icon.

View File

@ -1,4 +1,4 @@
// Copyright (c) 2022 Ultimaker B.V. // Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.15 import QtQuick 2.15
@ -6,8 +6,8 @@ import QtQuick.Controls 2.2
import QtQuick.Window 2.1 import QtQuick.Window 2.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import UM 1.5 as UM import UM 1.7 as UM
import Cura 1.1 as Cura import Cura 1.7 as Cura
/* /*
@ -122,7 +122,7 @@ UM.Dialog
text = `#${text}`; text = `#${text}`;
} }
} }
validator: RegularExpressionValidator { regularExpression: /^#([a-fA-F0-9]{0,6})$/ } validator: UM.HexColorValidator {}
} }
Rectangle Rectangle

View File

@ -12,17 +12,14 @@ UM.ToolbarButton
id: base id: base
property var extruder property var extruder
property var extruderNumberFont: UM.Theme.getFont("small_emphasis")
text: catalog.i18ncp("@label %1 is filled in with the name of an extruder", "Print Selected Model with %1", "Print Selected Models with %1", UM.Selection.selectionCount).arg(extruder.name)
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) != -1
enabled: UM.Selection.hasSelection && extruder.stack.isEnabled
toolItem: ExtruderIcon toolItem: ExtruderIcon
{ {
materialColor: extruder.color materialColor: extruder.color
extruderEnabled: extruder.stack.isEnabled extruderEnabled: extruder.stack.isEnabled
iconVariant: "default" iconVariant: "default"
font: extruderNumberFont
property int index: extruder.index property int index: extruder.index
} }

View File

@ -14,6 +14,7 @@ Item
property bool extruderEnabled: true property bool extruderEnabled: true
property var iconSize: UM.Theme.getSize("extruder_icon").width property var iconSize: UM.Theme.getSize("extruder_icon").width
property string iconVariant: "medium" property string iconVariant: "medium"
property alias font: extruderNumberText.font
implicitWidth: iconSize implicitWidth: iconSize
implicitHeight: iconSize implicitHeight: iconSize

View File

@ -68,18 +68,27 @@ UM.TooltipArea
function updateModel() function updateModel()
{ {
clear() clear()
// Options come in as a string-representation of an OrderedDict
if(propertyProvider.properties.options) if(!propertyProvider.properties.options)
{ {
var options = propertyProvider.properties.options.match(/^OrderedDict\(\[\((.*)\)\]\)$/); return
if(options)
{
options = options[1].split("), (");
for(var i = 0; i < options.length; i++)
{
var option = options[i].substring(1, options[i].length - 1).split("', '");
append({ text: option[1], value: option[0] });
} }
if (typeof propertyProvider.properties["options"] === "string")
{
return
}
for (var i = 0; i < propertyProvider.properties["options"].keys().length; i++)
{
var key = propertyProvider.properties["options"].keys()[i]
var value = propertyProvider.properties["options"][key]
append({ text: value, code: key })
if (propertyProvider.properties.value === key)
{
comboBox.currentIndex = i
} }
} }
} }
@ -123,7 +132,7 @@ UM.TooltipArea
onActivated: onActivated:
{ {
var newValue = model.get(index).value var newValue = model.get(index).value
if (propertyProvider.properties.value != newValue) if (propertyProvider.properties.value !== newValue && newValue !== undefined)
{ {
if (setValueFunction !== null) if (setValueFunction !== null)
{ {

View File

@ -59,7 +59,7 @@ UM.TooltipArea
UM.SettingPropertyProvider UM.SettingPropertyProvider
{ {
id: propertyProvider id: propertyProvider
watchedProperties: [ "value", "description" ] watchedProperties: [ "value", "description", "validationState" ]
} }
UM.Label UM.Label

View File

@ -67,6 +67,11 @@ Item
top: parent.top top: parent.top
} }
visible: currentModeIndex == PrintSetupSelectorContents.Mode.Recommended visible: currentModeIndex == PrintSetupSelectorContents.Mode.Recommended
function onModeChanged()
{
currentModeIndex = PrintSetupSelectorContents.Mode.Custom;
}
} }
CustomPrintSetup CustomPrintSetup
@ -116,13 +121,21 @@ Item
width: parent.width width: parent.width
height: UM.Theme.getSize("default_lining").height height: UM.Theme.getSize("default_lining").height
color: UM.Theme.getColor("lining") color: UM.Theme.getColor("lining")
visible: currentModeIndex == PrintSetupSelectorContents.Mode.Custom
} }
Item Item
{ {
id: buttonRow id: buttonRow
property real padding: UM.Theme.getSize("default_margin").width property real padding: UM.Theme.getSize("default_margin").width
height: recommendedButton.height + 2 * padding + (draggableArea.visible ? draggableArea.height : 0) height:
{
if (currentModeIndex == PrintSetupSelectorContents.Mode.Custom)
{
return recommendedButton.height + 2 * padding + (draggableArea.visible ? draggableArea.height : 0)
}
return 0
}
anchors anchors
{ {
@ -145,25 +158,6 @@ Item
onClicked: currentModeIndex = PrintSetupSelectorContents.Mode.Recommended onClicked: currentModeIndex = PrintSetupSelectorContents.Mode.Recommended
} }
Cura.SecondaryButton
{
id: customSettingsButton
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: UM.Theme.getSize("default_margin").width
leftPadding: UM.Theme.getSize("default_margin").width
rightPadding: UM.Theme.getSize("default_margin").width
text: catalog.i18nc("@button", "Custom")
iconSource: UM.Theme.getIcon("ChevronSingleRight")
isIconOnRightSide: true
visible: currentModeIndex == PrintSetupSelectorContents.Mode.Recommended
onClicked:
{
currentModeIndex = PrintSetupSelectorContents.Mode.Custom
updateDragPosition();
}
}
//Invisible area at the bottom with which you can resize the panel. //Invisible area at the bottom with which you can resize the panel.
MouseArea MouseArea
{ {

View File

@ -1,89 +1,37 @@
// Copyright (c) 2018 Ultimaker B.V. // Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.7
import QtQuick.Layouts 1.3
import UM 1.5 as UM import UM 1.5 as UM
import Cura 1.0 as Cura import Cura 1.7 as Cura
// RecommendedSettingSection
// Adhesion
//
Item
{ {
id: enableAdhesionRow id: enableAdhesionRow
height: enableAdhesionContainer.height
property real labelColumnWidth: Math.round(width / 3) title: catalog.i18nc("@label", "Adhesion")
icon: UM.Theme.getIcon("Adhesion")
enableSectionSwitchVisible: platformAdhesionType.properties.enabled === "True"
enableSectionSwitchChecked: platformAdhesionType.properties.value !== "skirt" && platformAdhesionType.properties.value !== "none"
enableSectionSwitchEnabled: recommendedPrintSetup.settingsEnabled
tooltipText: catalog.i18nc("@label", "Enable printing a brim or raft. This will add a flat area around or under your object which is easy to cut off afterwards.")
property var curaRecommendedMode: Cura.RecommendedMode {} property var curaRecommendedMode: Cura.RecommendedMode {}
Cura.IconWithText property UM.SettingPropertyProvider platformAdhesionType: UM.SettingPropertyProvider
{ {
id: enableAdhesionRowTitle
anchors.top: parent.top
anchors.left: parent.left
source: UM.Theme.getIcon("Adhesion")
text: catalog.i18nc("@label", "Adhesion")
font: UM.Theme.getFont("medium")
width: labelColumnWidth
iconSize: UM.Theme.getSize("medium_button_icon").width
}
Item
{
id: enableAdhesionContainer
height: enableAdhesionCheckBox.height
anchors
{
left: enableAdhesionRowTitle.right
right: parent.right
verticalCenter: enableAdhesionRowTitle.verticalCenter
}
UM.CheckBox
{
id: enableAdhesionCheckBox
anchors.verticalCenter: parent.verticalCenter
//: Setting enable printing build-plate adhesion helper checkbox
enabled: recommendedPrintSetup.settingsEnabled
visible: platformAdhesionType.properties.enabled == "True"
checked: platformAdhesionType.properties.value != "skirt" && platformAdhesionType.properties.value != "none"
MouseArea
{
id: adhesionMouseArea
anchors.fill: parent
hoverEnabled: true
// propagateComposedEvents used on adhesionTooltipMouseArea does not work with Controls Components.
// It only works with other MouseAreas, so this is required
onClicked: curaRecommendedMode.setAdhesion(!parent.checked)
}
}
}
MouseArea
{
id: adhesionTooltipMouseArea
anchors.fill: parent
propagateComposedEvents: true
hoverEnabled: true
onEntered:base.showTooltip(enableAdhesionCheckBox, Qt.point(-enableAdhesionContainer.x - UM.Theme.getSize("thick_margin").width, 0),
catalog.i18nc("@label", "Enable printing a brim or raft. This will add a flat area around or under your object which is easy to cut off afterwards."));
onExited: base.hideTooltip()
}
UM.SettingPropertyProvider
{
id: platformAdhesionType
containerStack: Cura.MachineManager.activeMachine containerStack: Cura.MachineManager.activeMachine
removeUnusedValue: false //Doesn't work with settings that are resolved. removeUnusedValue: false //Doesn't work with settings that are resolved.
key: "adhesion_type" key: "adhesion_type"
watchedProperties: [ "value", "resolve", "enabled" ] watchedProperties: [ "value", "resolve", "enabled" ]
storeIndex: 0 storeIndex: 0
} }
function onEnableSectionChanged(state)
{
curaRecommendedMode.setAdhesion(state)
}
} }

View File

@ -1,277 +0,0 @@
// Copyright (c) 2022 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.15
import UM 1.5 as UM
import Cura 1.0 as Cura
//
// Infill
//
Item
{
id: infillRow
height: childrenRect.height
property real labelColumnWidth: Math.round(width / 3)
// Create a binding to update the icon when the infill density changes
Binding
{
target: infillRowTitle
property: "source"
value:
{
var density = parseInt(infillDensity.properties.value)
if (parseInt(infillSteps.properties.value) != 0)
{
return UM.Theme.getIcon("InfillGradual")
}
if (density <= 0)
{
return UM.Theme.getIcon("Infill0")
}
if (density < 40)
{
return UM.Theme.getIcon("Infill3")
}
if (density < 90)
{
return UM.Theme.getIcon("Infill2")
}
return UM.Theme.getIcon("Infill100")
}
}
// We use a binding to make sure that after manually setting infillSlider.value it is still bound to the property provider
Binding
{
target: infillSlider
property: "value"
value: {
// The infill slider has a max value of 100. When it is given a value > 100 onValueChanged updates the setting to be 100.
// When changing to an intent with infillDensity > 100, it would always be clamped to 100.
// This will force the slider to ignore the first onValueChanged for values > 100 so higher values can be set.
var density = parseInt(infillDensity.properties.value)
if (density > 100) {
infillSlider.ignoreValueChange = true
}
return density
}
}
// Here are the elements that are shown in the left column
Cura.IconWithText
{
id: infillRowTitle
anchors.top: parent.top
anchors.left: parent.left
source: UM.Theme.getIcon("Infill1")
text: catalog.i18nc("@label", "Infill") + " (%)"
font: UM.Theme.getFont("medium")
width: labelColumnWidth
iconSize: UM.Theme.getSize("medium_button_icon").width
tooltipText: catalog.i18nc("@label", "Gradual infill will gradually increase the amount of infill towards the top.")
}
Item
{
id: infillSliderContainer
height: childrenRect.height
anchors
{
left: infillRowTitle.right
right: parent.right
verticalCenter: infillRowTitle.verticalCenter
}
Slider
{
id: infillSlider
property var ignoreValueChange: false
width: parent.width
height: UM.Theme.getSize("print_setup_slider_handle").height // The handle is the widest element of the slider
from: 0
to: 100
stepSize: 1
// disable slider when gradual support is enabled
enabled: parseInt(infillSteps.properties.value) == 0
// set initial value from stack
value: parseInt(infillDensity.properties.value)
//Draw line
background: Rectangle
{
id: backgroundLine
height: UM.Theme.getSize("print_setup_slider_groove").height
width: parent.width - UM.Theme.getSize("print_setup_slider_handle").width
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: infillSlider.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
Repeater
{
id: repeater
anchors.fill: parent
model: infillSlider.to / infillSlider.stepSize + 1
Rectangle
{
color: infillSlider.enabled ? UM.Theme.getColor("quality_slider_available") : UM.Theme.getColor("quality_slider_unavailable")
implicitWidth: UM.Theme.getSize("print_setup_slider_tickmarks").width
implicitHeight: UM.Theme.getSize("print_setup_slider_tickmarks").height
anchors.verticalCenter: parent.verticalCenter
// Do not use Math.round otherwise the tickmarks won't be aligned
// (space between steps) * index of step
x: (backgroundLine.width / (repeater.count - 1)) * index
radius: Math.round(implicitWidth / 2)
visible: (index % 10) == 0 // Only show steps of 10%
UM.Label
{
text: index
visible: (index % 20) == 0 // Only show steps of 20%
anchors.horizontalCenter: parent.horizontalCenter
y: UM.Theme.getSize("thin_margin").height
color: UM.Theme.getColor("quality_slider_available")
}
}
}
}
handle: Rectangle
{
id: handleButton
x: infillSlider.leftPadding + infillSlider.visualPosition * (infillSlider.availableWidth - width)
y: infillSlider.topPadding + infillSlider.availableHeight / 2 - height / 2
color: infillSlider.enabled ? UM.Theme.getColor("primary") : UM.Theme.getColor("quality_slider_unavailable")
implicitWidth: UM.Theme.getSize("print_setup_slider_handle").width
implicitHeight: implicitWidth
radius: Math.round(implicitWidth / 2)
border.color: UM.Theme.getColor("slider_groove_fill")
border.width: UM.Theme.getSize("default_lining").height
}
Connections
{
target: infillSlider
function onValueChanged()
{
if (infillSlider.ignoreValueChange)
{
infillSlider.ignoreValueChange = false
return
}
// Don't update if the setting value, if the slider has the same value
if (parseInt(infillDensity.properties.value) == infillSlider.value)
{
return
}
// Round the slider value to the nearest multiple of 10 (simulate step size of 10)
var roundedSliderValue = Math.round(infillSlider.value / 10) * 10
// Update the slider value to represent the rounded value
infillSlider.value = roundedSliderValue
// Update value only if the Recommended mode is Active,
// Otherwise if I change the value in the Custom mode the Recommended view will try to repeat
// same operation
const active_mode = UM.Preferences.getValue("cura/active_mode")
if (visible // Workaround: 'visible' is checked because on startup in Windows it spuriously gets an 'onValueChanged' with value '0' if this isn't checked.
&& (active_mode == 0 || active_mode == "simple"))
{
Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", roundedSliderValue)
Cura.MachineManager.resetSettingForAllExtruders("infill_line_distance")
}
}
}
}
}
// Gradual Support Infill Checkbox
UM.CheckBox
{
id: enableGradualInfillCheckBox
property alias _hovered: enableGradualInfillMouseArea.containsMouse
anchors.top: infillSliderContainer.bottom
anchors.topMargin: UM.Theme.getSize("wide_margin").height
anchors.left: infillSliderContainer.left
text: catalog.i18nc("@label", "Gradual infill")
enabled: recommendedPrintSetup.settingsEnabled
visible: infillSteps.properties.enabled == "True"
checked: parseInt(infillSteps.properties.value) > 0
MouseArea
{
id: enableGradualInfillMouseArea
anchors.fill: parent
hoverEnabled: true
enabled: true
property var previousInfillDensity: parseInt(infillDensity.properties.value)
onClicked:
{
// Set to 90% only when enabling gradual infill
var newInfillDensity;
if (parseInt(infillSteps.properties.value) == 0)
{
previousInfillDensity = parseInt(infillDensity.properties.value)
newInfillDensity = 90
} else {
newInfillDensity = previousInfillDensity
}
Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", String(newInfillDensity))
var infill_steps_value = 0
if (parseInt(infillSteps.properties.value) == 0)
{
infill_steps_value = 5
}
Cura.MachineManager.setSettingForAllExtruders("gradual_infill_steps", "value", infill_steps_value)
}
onEntered: base.showTooltip(enableGradualInfillCheckBox, Qt.point(-infillSliderContainer.x - UM.Theme.getSize("thick_margin").width, 0),
catalog.i18nc("@label", "Gradual infill will gradually increase the amount of infill towards the top."))
onExited: base.hideTooltip()
}
}
UM.SettingPropertyProvider
{
id: infillDensity
containerStackId: Cura.MachineManager.activeStackId
key: "infill_sparse_density"
watchedProperties: [ "value" ]
storeIndex: 0
}
UM.SettingPropertyProvider
{
id: infillSteps
containerStackId: Cura.MachineManager.activeStackId
key: "gradual_infill_steps"
watchedProperties: ["value", "enabled"]
storeIndex: 0
}
}

View File

@ -1,4 +1,4 @@
//Copyright (c) 2022 Ultimaker B.V. // Copyright (c) 2022 UltiMaker
//Cura is released under the terms of the LGPLv3 or higher. //Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10 import QtQuick 2.10
@ -17,7 +17,9 @@ Item
property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1 property bool settingsEnabled: Cura.ExtruderManager.activeExtruderStackId || extrudersEnabledCount.properties.value == 1
property real padding: UM.Theme.getSize("default_margin").width property real padding: UM.Theme.getSize("default_margin").width
ColumnLayout function onModeChanged() {}
Column
{ {
spacing: UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("default_margin").height
@ -47,7 +49,6 @@ Item
RecommendedResolutionSelector RecommendedResolutionSelector
{ {
id: recommendedResolutionSelector id: recommendedResolutionSelector
Layout.fillWidth: true
width: parent.width width: parent.width
} }
@ -55,55 +56,72 @@ Item
{ {
width: parent.width width: parent.width
visible: !recommendedResolutionSelector.visible visible: !recommendedResolutionSelector.visible
Layout.fillWidth: true
} }
Item { height: UM.Theme.getSize("default_margin").height } // Spacer
ProfileWarningReset ProfileWarningReset
{ {
width: parent.width width: parent.width
Layout.fillWidth: true
Layout.topMargin: UM.Theme.getSize("default_margin").height
Layout.bottomMargin: UM.Theme.getSize("thin_margin").height
} }
Item { height: UM.Theme.getSize("thin_margin").height + UM.Theme.getSize("narrow_margin").height} // Spacer
//Line between the sections. //Line between the sections.
Rectangle Rectangle
{ {
width: parent.width width: parent.width
height: UM.Theme.getSize("default_lining").height height: UM.Theme.getSize("default_lining").height
Layout.topMargin: UM.Theme.getSize("narrow_margin").height
Layout.bottomMargin: UM.Theme.getSize("narrow_margin").height
Layout.fillWidth: true
color: UM.Theme.getColor("lining") color: UM.Theme.getColor("lining")
} }
Item { height: UM.Theme.getSize("narrow_margin").height } //Spacer
Column
{
id: settingColumn
width: parent.width
spacing: UM.Theme.getSize("thin_margin").height
Item
{
id: recommendedPrintSettingsHeader
height: childrenRect.height
width: parent.width
UM.Label UM.Label
{ {
text: catalog.i18nc("@label", "Print settings") anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
text: catalog.i18nc("@label", "Recommended print settings")
font: UM.Theme.getFont("medium") font: UM.Theme.getFont("medium")
} }
RecommendedInfillDensitySelector Cura.SecondaryButton
{
id: customSettingsButton
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
text: catalog.i18nc("@button", "Show Custom")
textFont: UM.Theme.getFont("medium_bold")
outlineColor: "transparent"
onClicked: onModeChanged()
}
}
RecommendedStrengthSelector
{ {
width: parent.width width: parent.width
labelColumnWidth: parent.firstColumnWidth
Layout.fillWidth: true
Layout.rightMargin: UM.Theme.getSize("default_margin").width
} }
RecommendedSupportSelector RecommendedSupportSelector
{ {
width: parent.width width: parent.width
labelColumnWidth: parent.firstColumnWidth
Layout.fillWidth: true
} }
RecommendedAdhesionSelector RecommendedAdhesionSelector
{ {
width: parent.width width: parent.width
labelColumnWidth: parent.firstColumnWidth }
Layout.fillWidth: true
} }
} }

View File

@ -0,0 +1,90 @@
// Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 2.10
import UM 1.5 as UM
import Cura 1.7 as Cura
Item
{
id: settingItem
width: parent.width
Layout.minimumHeight: UM.Theme.getSize("section_header").height
Layout.fillWidth: true
property alias settingControl: settingContainer.children
property alias settingName: settingLabel.text
property string tooltipText: ""
property bool isCompressed: false
UM.Label
{
id: settingLabel
width: leftColumnWidth
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
// These numbers come from the IconWithText in RecommendedSettingSection
anchors.leftMargin: UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
}
MouseArea
{
id: tooltipArea
anchors.fill: settingLabel
propagateComposedEvents: true
hoverEnabled: true
onEntered: base.showTooltip(parent, Qt.point(-UM.Theme.getSize("thick_margin").width, 0), tooltipText)
onExited: base.hideTooltip()
}
Item
{
id: settingContainer
height: childrenRect.height
anchors.left: settingLabel.right
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
states:
[
State
{
name: "sectionClosed" // Section is hidden when the switch in parent is off
when: isCompressed
PropertyChanges
{
target: settingItem;
opacity: 0
height: 0
implicitHeight: 0
Layout.preferredHeight: 0
Layout.minimumHeight: 0
enabled: false // Components can still be clickable with height 0 so they need to be disabled as well.
}
},
State
{
// All values are default. This state is only here for the animation.
name: "sectionOpened"
when: !isCompressed
}
]
transitions: Transition
{
from: "sectionOpened"; to: "sectionClosed"
reversible: true
ParallelAnimation
{
// Animate section compressing as it closes
NumberAnimation { property: "Layout.minimumHeight"; duration: 100; }
// Animate section dissapearring as it closes
NumberAnimation { property: "opacity"; duration: 100; }
}
}
}

View File

@ -0,0 +1,129 @@
// Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 2.10
import UM 1.7 as UM
import Cura 1.7 as Cura
Item
{
id: settingSection
property alias title: sectionTitle.text
property alias icon: sectionTitle.source
property alias enableSectionSwitchVisible: enableSectionSwitch.visible
property alias enableSectionSwitchChecked: enableSectionSwitch.checked
property alias enableSectionSwitchEnabled: enableSectionSwitch.enabled
property string tooltipText: ""
property var enableSectionClicked: { return }
property int leftColumnWidth: Math.floor(width * 0.35)
property bool isCompressed: false
property alias contents: settingColumn.children
function onEnableSectionChanged(state) {}
height: childrenRect.height
Item
{
id: sectionHeader
anchors.top: parent.top
anchors.right: parent.right
anchors.left: parent.left
height: UM.Theme.getSize("section_header").height
Cura.IconWithText
{
id: sectionTitle
width: leftColumnWidth
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
source: UM.Theme.getIcon("PrintQuality")
spacing: UM.Theme.getSize("default_margin").width
iconSize: UM.Theme.getSize("medium_button_icon").width
iconColor: UM.Theme.getColor("text")
font: UM.Theme.getFont("medium_bold")
}
MouseArea
{
id: tooltipArea
anchors.fill: sectionTitle
propagateComposedEvents: true
hoverEnabled: true
onEntered: base.showTooltip(parent, Qt.point(-UM.Theme.getSize("thick_margin").width, 0), tooltipText)
onExited: base.hideTooltip()
}
}
UM.Switch
{
id: enableSectionSwitch
anchors.left: parent.left
// These numbers come from the IconWithText in RecommendedSettingSection.
anchors.leftMargin: leftColumnWidth + UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
anchors.verticalCenter: sectionHeader.verticalCenter
visible: false
// This delay forces the setting change to happen after the setting section open/close animation. This is so the animation is smooth.
Timer
{
id: updateTimer
interval: 500 // This interval is set long enough so you can spam click the button on/off without lag.
repeat: false
onTriggered: onEnableSectionChanged(enableSectionSwitch.checked)
}
onClicked: updateTimer.restart()
}
ColumnLayout
{
id: settingColumn
width: parent.width
spacing: UM.Theme.getSize("thin_margin").height
anchors.left: parent.left
anchors.right: parent.right
anchors.top: sectionHeader.bottom
anchors.topMargin: UM.Theme.getSize("narrow_margin").height
}
states:
[
State
{
name: "settingListClosed"
when: !enableSectionSwitchChecked && enableSectionSwitchEnabled
PropertyChanges
{
target: settingSection
isCompressed: true
implicitHeight: 0
}
PropertyChanges
{
target: settingColumn
spacing: 0
}
},
State
{
// Use default properties. This is only here for the animation.
name: "settingListOpened"
when: enableSectionSwitchChecked && enableSectionSwitchEnabled
}
]
// Animate section closing
transitions: Transition
{
from: "settingListOpened"; to: "settingListClosed"
reversible: true
// Animate section compressing as it closes
NumberAnimation { property: "implicitHeight"; duration: 100; }
}
}

View File

@ -0,0 +1,105 @@
// Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.15
import QtQuick.Layouts 2.10
import UM 1.7 as UM
import Cura 1.7 as Cura
RecommendedSettingSection
{
id: strengthSection
title: catalog.i18nc("@label", "Strength")
icon: UM.Theme.getIcon("Hammer")
enableSectionSwitchVisible: false
enableSectionSwitchEnabled: false
tooltipText: catalog.i18nc("@label", "The following settings define the strength of your part.")
UM.SettingPropertyProvider
{
id: infillSteps
containerStackId: Cura.MachineManager.activeStackId
key: "gradual_infill_steps"
watchedProperties: ["value", "enabled"]
storeIndex: 0
}
contents: [
RecommendedSettingItem
{
settingName: catalog.i18nc("infill_sparse_density description", "Infill Density")
tooltipText: catalog.i18nc("@label", "Adjusts the density of infill of the print.")
settingControl: Cura.SingleSettingSlider
{
height: UM.Theme.getSize("combobox").height
width: parent.width
settingName: "infill_sparse_density"
updateAllExtruders: true
// disable slider when gradual support is enabled
enabled: parseInt(infillSteps.properties.value) === 0
function updateSetting(value)
{
Cura.MachineManager.setSettingForAllExtruders("infill_sparse_density", "value", value)
Cura.MachineManager.resetSettingForAllExtruders("infill_line_distance")
}
}
},
RecommendedSettingItem
{
settingName: catalog.i18nc("@action:label", "Infill Pattern")
tooltipText: catalog.i18nc("@label",
"The pattern of the infill material of the print:\n\nFor quick prints of non functional model choose line, zig zag or lighting infill.\n\nFor functional part not subjected to a lot of stress we reccomend grid or triangle or tri hexagon.\n\nFor functional 3D prints which require high strenght in multiple directions use cubic, cubic subdivision, quarter cubic, octet, and gyroid.")
settingControl: Cura.SingleSettingComboBox
{
width: parent.width
settingName: "infill_pattern"
updateAllExtruders: true
}
},
RecommendedSettingItem
{
settingName: catalog.i18nc("@action:label", "Shell Thickness")
tooltipText: catalog.i18nc("@label", "Defines the tickness of your part side walls, roof and floor.")
settingControl: RowLayout
{
anchors.fill: parent
spacing: UM.Theme.getSize("default_margin").width
UM.ComponentWithIcon
{
Layout.fillWidth: true
source: UM.Theme.getIcon("PrintWalls")
Cura.SingleSettingTextField
{
width: parent.width
settingName: "wall_thickness"
updateAllExtruders: true
validator: UM.FloatValidator {}
unitText: catalog.i18nc("@label", "mm")
}
}
UM.ComponentWithIcon
{
Layout.fillWidth: true
source: UM.Theme.getIcon("PrintTopBottom")
Cura.SingleSettingTextField
{
width: parent.width
settingName: "top_bottom_thickness"
updateAllExtruders: true
validator: UM.FloatValidator {}
unitText: catalog.i18nc("@label", "mm")
}
}
}
}
]
}

View File

@ -1,307 +1,31 @@
// Copyright (c) 2022 Ultimaker B.V. // Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10 import QtQuick 2.10
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import UM 1.5 as UM import UM 1.5 as UM
import Cura 1.0 as Cura import Cura 1.7 as Cura
// RecommendedSettingSection
// Enable support
//
Item
{ {
id: enableSupportRow id: enableSupportRow
height: UM.Theme.getSize("print_setup_big_item").height
property real labelColumnWidth: Math.round(width / 3) title: catalog.i18nc("@label", "Support")
icon: UM.Theme.getIcon("Support")
enableSectionSwitchVisible: supportEnabled.properties.enabled == "True"
enableSectionSwitchChecked: supportEnabled.properties.value == "True"
enableSectionSwitchEnabled: recommendedPrintSetup.settingsEnabled
tooltipText: catalog.i18nc("@label", "Generate structures to support parts of the model which have overhangs. Without these structures, these parts would collapse during printing.")
Item function onEnableSectionChanged(state)
{ {
id: enableSupportContainer supportEnabled.setPropertyValue("value", state)
width: labelColumnWidth + enableSupportCheckBox.width
anchors
{
left: parent.left
top: parent.top
bottom: parent.bottom
rightMargin: UM.Theme.getSize("thick_margin").width
} }
Cura.IconWithText property UM.SettingPropertyProvider supportEnabled: UM.SettingPropertyProvider
{
id: enableSupportRowTitle
anchors.left: parent.left
visible: enableSupportCheckBox.visible
source: UM.Theme.getIcon("Support")
text: catalog.i18nc("@label", "Support")
font: UM.Theme.getFont("medium")
width: labelColumnWidth
iconSize: UM.Theme.getSize("medium_button_icon").width
tooltipText: catalog.i18nc("@label", "Generate structures to support parts of the model which have overhangs. Without these structures, such parts would collapse during printing.")
}
UM.CheckBox
{
id: enableSupportCheckBox
anchors.verticalCenter: parent.verticalCenter
anchors.left: enableSupportRowTitle.right
property alias _hovered: enableSupportMouseArea.containsMouse
enabled: recommendedPrintSetup.settingsEnabled
visible: supportEnabled.properties.enabled == "True"
checked: supportEnabled.properties.value == "True"
MouseArea
{
id: enableSupportMouseArea
anchors.fill: parent
hoverEnabled: true
// propagateComposedEvents used on supportToolTipMouseArea does not work with Controls Components.
// It only works with other MouseAreas, so this is required
onClicked: supportEnabled.setPropertyValue("value", supportEnabled.properties.value != "True")
}
}
MouseArea
{
id: supportToolTipMouseArea
anchors.fill: parent
propagateComposedEvents: true
hoverEnabled: true
onEntered: base.showTooltip(enableSupportContainer, Qt.point(-enableSupportContainer.x - UM.Theme.getSize("thick_margin").width, 0),
catalog.i18nc("@label", "Generate structures to support parts of the model which have overhangs. Without these structures, such parts would collapse during printing."))
onExited: base.hideTooltip()
}
}
ComboBox
{
id: supportExtruderCombobox
height: UM.Theme.getSize("print_setup_big_item").height
anchors
{
left: enableSupportContainer.right
right: parent.right
leftMargin: UM.Theme.getSize("default_margin").width
rightMargin: UM.Theme.getSize("thick_margin").width
verticalCenter: parent.verticalCenter
}
enabled: recommendedPrintSetup.settingsEnabled
visible: enableSupportCheckBox.visible && (supportEnabled.properties.value == "True") && (extrudersEnabledCount.properties.value > 1)
textRole: "name" // this solves that the combobox isn't populated in the first time Cura is started
model: extruderModel
// knowing the extruder position, try to find the item index in the model
function getIndexByPosition(position)
{
var itemIndex = -1 // if position is not found, return -1
for (var item_index in model.items)
{
var item = model.getItem(item_index)
if (item.index == position)
{
itemIndex = item_index
break
}
}
return itemIndex
}
onActivated:
{
if (model.getItem(index).enabled)
{
forceActiveFocus();
supportExtruderNr.setPropertyValue("value", model.getItem(index).index);
} else
{
currentIndex = supportExtruderNr.properties.value; // keep the old value
}
}
currentIndex: (supportExtruderNr.properties.value !== undefined) ? supportExtruderNr.properties.value : 0
property string color: "#fff"
Connections
{
target: extruderModel
function onModelChanged()
{
var maybeColor = supportExtruderCombobox.model.getItem(supportExtruderCombobox.currentIndex).color
if (maybeColor)
{
supportExtruderCombobox.color = maybeColor
}
}
}
onCurrentIndexChanged:
{
var maybeColor = supportExtruderCombobox.model.getItem(supportExtruderCombobox.currentIndex).color
if(maybeColor)
{
supportExtruderCombobox.color = maybeColor
}
}
Binding
{
target: supportExtruderCombobox
property: "currentIndex"
value: supportExtruderCombobox.getIndexByPosition(supportExtruderNr.properties.value)
// Sometimes when the value is already changed, the model is still being built.
// The when clause ensures that the current index is not updated when this happens.
when: supportExtruderCombobox.model.count > 0
}
indicator: UM.ColorImage
{
id: downArrow
x: supportExtruderCombobox.width - width - supportExtruderCombobox.rightPadding
y: supportExtruderCombobox.topPadding + Math.round((supportExtruderCombobox.availableHeight - height) / 2)
source: UM.Theme.getIcon("ChevronSingleDown")
width: UM.Theme.getSize("standard_arrow").width
height: UM.Theme.getSize("standard_arrow").height
color: UM.Theme.getColor("setting_control_button")
}
background: Rectangle
{
color:
{
if (!enabled)
{
return UM.Theme.getColor("setting_control_disabled")
}
if (supportExtruderCombobox.hovered || base.activeFocus)
{
return UM.Theme.getColor("setting_control_highlight")
}
return UM.Theme.getColor("setting_control")
}
radius: UM.Theme.getSize("setting_control_radius").width
border.width: UM.Theme.getSize("default_lining").width
border.color:
{
if (!enabled)
{
return UM.Theme.getColor("setting_control_disabled_border")
}
if (supportExtruderCombobox.hovered || supportExtruderCombobox.activeFocus)
{
return UM.Theme.getColor("setting_control_border_highlight")
}
return UM.Theme.getColor("setting_control_border")
}
}
contentItem: UM.Label
{
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width
anchors.right: downArrow.left
rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width
text: supportExtruderCombobox.currentText
textFormat: Text.PlainText
color: enabled ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
elide: Text.ElideLeft
background: Rectangle
{
id: swatch
height: Math.round(parent.height / 2)
width: height
radius: Math.round(width / 2)
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: UM.Theme.getSize("thin_margin").width
color: supportExtruderCombobox.color
}
}
popup: Popup
{
y: supportExtruderCombobox.height - UM.Theme.getSize("default_lining").height
width: supportExtruderCombobox.width
implicitHeight: contentItem.implicitHeight + 2 * UM.Theme.getSize("default_lining").width
padding: UM.Theme.getSize("default_lining").width
contentItem: ListView
{
implicitHeight: contentHeight
ScrollBar.vertical: UM.ScrollBar {}
clip: true
model: supportExtruderCombobox.popup.visible ? supportExtruderCombobox.delegateModel : null
currentIndex: supportExtruderCombobox.highlightedIndex
}
background: Rectangle
{
color: UM.Theme.getColor("setting_control")
border.color: UM.Theme.getColor("setting_control_border")
}
}
delegate: ItemDelegate
{
width: supportExtruderCombobox.width - 2 * UM.Theme.getSize("default_lining").width
height: supportExtruderCombobox.height
highlighted: supportExtruderCombobox.highlightedIndex == index
contentItem: UM.Label
{
anchors.fill: parent
anchors.leftMargin: UM.Theme.getSize("setting_unit_margin").width
anchors.rightMargin: UM.Theme.getSize("setting_unit_margin").width
text: model.name
color: model.enabled ? UM.Theme.getColor("setting_control_text"): UM.Theme.getColor("action_button_disabled_text")
elide: Text.ElideRight
rightPadding: swatch.width + UM.Theme.getSize("setting_unit_margin").width
background: Rectangle
{
id: swatch
height: Math.round(parent.height / 2)
width: height
radius: Math.round(width / 2)
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: UM.Theme.getSize("thin_margin").width
color: supportExtruderCombobox.model.getItem(index).color
}
}
background: Rectangle
{
color: parent.highlighted ? UM.Theme.getColor("setting_control_highlight") : "transparent"
border.color: parent.highlighted ? UM.Theme.getColor("setting_control_border_highlight") : "transparent"
}
}
}
property var extruderModel: CuraApplication.getExtrudersModel()
UM.SettingPropertyProvider
{ {
id: supportEnabled id: supportEnabled
containerStack: Cura.MachineManager.activeMachine containerStack: Cura.MachineManager.activeMachine
@ -310,21 +34,45 @@ Item
storeIndex: 0 storeIndex: 0
} }
UM.SettingPropertyProvider contents: [
RecommendedSettingItem
{ {
id: supportExtruderNr settingName: catalog.i18nc("@action:label", "Support Type")
containerStack: Cura.MachineManager.activeMachine tooltipText: catalog.i18nc("@label", "Chooses between the techniques available to generate support. \n\n\"Normal\" support creates a support structure directly below the overhanging parts and drops those areas straight down. \n\n\"Tree\" support creates branches towards the overhanging areas that support the model on the tips of those branches, and allows the branches to crawl around the model to support it from the build plate as much as possible.")
key: "support_extruder_nr" isCompressed: enableSupportRow.isCompressed
watchedProperties: [ "value" ]
storeIndex: 0
}
UM.SettingPropertyProvider settingControl: Cura.SingleSettingComboBox
{ {
id: machineExtruderCount width: parent.width
containerStack: Cura.MachineManager.activeMachine settingName: "support_structure"
key: "machine_extruder_count" }
watchedProperties: ["value"] },
storeIndex: 0 RecommendedSettingItem
{
Layout.preferredHeight: childrenRect.height
settingName: catalog.i18nc("@action:label", "Print with")
tooltipText: catalog.i18nc("@label", "The extruder train to use for printing the support. This is used in multi-extrusion.")
// Hide this component when there is only one extruder
enabled: Cura.ExtruderManager.enabledExtruderCount > 1
visible: Cura.ExtruderManager.enabledExtruderCount > 1
isCompressed: enableSupportRow.isCompressed || Cura.ExtruderManager.enabledExtruderCount <= 1
settingControl: Cura.SingleSettingExtruderSelectorBar
{
extruderSettingName: "support_extruder_nr"
}
},
RecommendedSettingItem
{
settingName: catalog.i18nc("@action:label", "Placement")
tooltipText: catalog.i18nc("support_type description", "Adjusts the placement of the support structures. The placement can be set to touching build plate or everywhere. When set to everywhere the support structures will also be printed on the model.")
isCompressed: enableSupportRow.isCompressed
settingControl: Cura.SingleSettingComboBox
{
width: parent.width
settingName: "support_type"
} }
} }
]
}

View File

@ -11,7 +11,7 @@ UM.PointingRectangle
id: base id: base
property real sourceWidth: 0 property real sourceWidth: 0
width: UM.Theme.getSize("tooltip").width width: UM.Theme.getSize("tooltip").width
height: textScroll.height + UM.Theme.getSize("tooltip_margins").height * 2 height: textScroll.height + UM.Theme.getSize("tooltip_margins").height
color: UM.Theme.getColor("tooltip") color: UM.Theme.getColor("tooltip")
arrowSize: UM.Theme.getSize("default_arrow").width arrowSize: UM.Theme.getSize("default_arrow").width

View File

@ -4,7 +4,7 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import UM 1.5 as UM import UM 1.7 as UM
SettingItem SettingItem
{ {
@ -14,6 +14,11 @@ SettingItem
property string textBeforeEdit property string textBeforeEdit
property bool textHasChanged property bool textHasChanged
property bool focusGainedByClick: false property bool focusGainedByClick: false
readonly property UM.IntValidator intValidator: UM.IntValidator {}
readonly property UM.FloatValidator floatValidator: UM.FloatValidator {}
readonly property UM.IntListValidator intListValidator: UM.IntListValidator {}
onFocusReceived: onFocusReceived:
{ {
textHasChanged = false; textHasChanged = false;
@ -159,7 +164,23 @@ SettingItem
// should be done as little as possible) // should be done as little as possible)
clip: definition.type == "str" || definition.type == "[int]" clip: definition.type == "str" || definition.type == "[int]"
validator: RegularExpressionValidator { regularExpression: (definition.type == "[int]") ? /^\[?(\s*-?[0-9]{0,11}\s*,)*(\s*-?[0-9]{0,11})\s*\]?$/ : (definition.type == "int") ? /^-?[0-9]{0,12}$/ : (definition.type == "float") ? /^-?[0-9]{0,11}[.,]?[0-9]{0,3}$/ : /^.*$/ } // definition.type property from parent loader used to disallow fractional number entry validator: RegularExpressionValidator
{
regularExpression:
{
switch (definition.type)
{
case "[int]":
return new RegExp(intListValidator.regexString)
case "int":
return new RegExp(intValidator.regexString)
case "float":
return new RegExp(floatValidator.regexString)
default:
return new RegExp("^.*$")
}
}
}
Binding Binding
{ {

View File

@ -5,7 +5,7 @@ import QtQuick 2.2
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import UM 1.5 as UM import UM 1.5 as UM
import Cura 1.0 as Cura import Cura 1.7 as Cura
Item Item
{ {
@ -29,13 +29,13 @@ Item
anchors anchors
{ {
fill: toolButtons fill: toolButtons
leftMargin: -radius - border.width leftMargin: -radius - border.width // Removes border on left side
rightMargin: -border.width
topMargin: -border.width
bottomMargin: -border.width
} }
radius: UM.Theme.getSize("default_radius").width radius: UM.Theme.getSize("default_radius").width
color: UM.Theme.getColor("lining") color: UM.Theme.getColor("toolbar_background")
border.color: UM.Theme.getColor("lining")
border.width: UM.Theme.getSize("default_lining").width
} }
Column Column
@ -111,13 +111,12 @@ Item
anchors anchors
{ {
fill: extruderButtons fill: extruderButtons
leftMargin: -radius - border.width leftMargin: -radius - border.width // Removes border on left side
rightMargin: -border.width
topMargin: -border.width
bottomMargin: -border.width
} }
radius: UM.Theme.getSize("default_radius").width radius: UM.Theme.getSize("default_radius").width
color: UM.Theme.getColor("lining") color: UM.Theme.getColor("toolbar_background")
border.color: UM.Theme.getColor("lining")
border.width: UM.Theme.getSize("default_lining").width
visible: extrudersModel.items.length > 1 visible: extrudersModel.items.length > 1
} }
@ -135,11 +134,21 @@ Item
height: childrenRect.height height: childrenRect.height
model: extrudersModel.items.length > 1 ? extrudersModel : 0 model: extrudersModel.items.length > 1 ? extrudersModel : 0
delegate: ExtruderButton delegate: Cura.ExtruderButton
{ {
extruder: model extruder: model
isTopElement: extrudersModel.getItem(0).id == model.id isTopElement: extrudersModel.getItem(0).id === model.id
isBottomElement: extrudersModel.getItem(extrudersModel.rowCount() - 1).id == model.id isBottomElement: extrudersModel.getItem(extrudersModel.rowCount() - 1).id === model.id
text: catalog.i18ncp("@label %1 is filled in with the name of an extruder", "Print Selected Model with %1", "Print Selected Models with %1", UM.Selection.selectionCount).arg(extruder.name)
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(extruder.id) !== -1
enabled: UM.Selection.hasSelection && extruder.stack.isEnabled
font: UM.Theme.getFont("small_emphasis")
onClicked:
{
forceActiveFocus() //First grab focus, so all the text fields are updated
CuraActions.setExtruderForSelection(extruder.id)
}
} }
} }
} }

View File

@ -25,6 +25,8 @@ ComboBox
enabled: delegateModel.count > 0 enabled: delegateModel.count > 0
height: UM.Theme.getSize("combobox").height
onVisibleChanged: { popup.close() } onVisibleChanged: { popup.close() }
states: [ states: [

View File

@ -0,0 +1,102 @@
// Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import UM 1.5 as UM
import Cura 1.7 as Cura
// This ComboBox allows changing of a single setting. Only the setting name has to be passed in to "settingName".
// All of the setting updating logic is handled by this component.
// This uses the "options" value of a setting to populate the drop down. This will only work for settings with "options"
// If the setting is limited to a single extruder or is settable with different values per extruder use "updateAllExtruders: true"
Cura.ComboBox {
textRole: "text"
property alias settingName: propertyProvider.key
// If true, all extruders will have "settingName" property updated.
// The displayed value will be read from the extruder with index "defaultExtruderIndex" instead of the machine.
property bool updateAllExtruders: false
// This is only used if updateAllExtruders == true
property int defaultExtruderIndex: 0
model: ListModel
{
id: comboboxModel
// The propertyProvider has not loaded the setting when this components onComplete triggers. Populating the model
// is defered until propertyProvider signals "onIsValueUsedChanged". The defered upate is triggered with this function.
function updateModel()
{
clear()
if(!propertyProvider.properties.options) // No options have been loaded yet to populate combobox
{
return
}
for (var i = 0; i < propertyProvider.properties["options"].keys().length; i++)
{
var key = propertyProvider.properties["options"].keys()[i]
var value = propertyProvider.properties["options"][key]
comboboxModel.append({ text: value, code: key})
if (propertyProvider.properties.value === key)
{
// The combobox is cleared after each value change so the currentIndex must be set each time.
currentIndex = i
}
}
}
}
// Updates to the setting are delayed by interval. The signal onIsValueUsedChanged() is emitted early for some reason.
// This causes the selected value in the combobox to be updated to the previous value. (This issue is present with infill_pattern setting)
// This is a hack. If you see this in the future, try removing it and see if the combobox still works.
Timer
{
id: updateTimer
interval: 100
repeat: false
onTriggered: comboboxModel.updateModel(false)
}
property UM.SettingPropertyProvider propertyProvider: UM.SettingPropertyProvider
{
id: propertyProvider
containerStackId: updateAllExtruders ? Cura.ExtruderManager.extruderIds[defaultExtruderIndex] : Cura.MachineManager.activeMachine.id
watchedProperties: ["value" , "options"]
}
Connections
{
target: propertyProvider
function onContainerStackChanged() { updateTimer.restart() }
function onIsValueUsedChanged() { updateTimer.restart() }
}
onCurrentIndexChanged: parseValueAndUpdateSetting()
function parseValueAndUpdateSetting()
{
if (comboboxModel.get(currentIndex) && comboboxModel.get(currentIndex).code !== propertyProvider.properties.value)
{
updateSetting(comboboxModel.get(currentIndex).code)
}
}
function updateSetting(value)
{
if (updateAllExtruders)
{
Cura.MachineManager.setSettingForAllExtruders(propertyProvider.key, "value", value)
}
else
{
propertyProvider.setPropertyValue("value", value)
}
}
}

View File

@ -0,0 +1,70 @@
// Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import UM 1.5 as UM
import Cura 1.5 as Cura
// This component displays a row of extruder icons, clicking on the extruder will update the setting passed to "settingName"
// with the index of that extruder.
// This will only work for settings that take an extruder index.
Row
{
id: extruderSelectionBar
width: parent.width
height: childrenRect.height
spacing: 0
property int selectedIndex: extruderSettingProvider.properties.value !== undefined ? extruderSettingProvider.properties.value : 0
property alias model: extruderButtonRepeater.model
property alias extruderSettingName: extruderSettingProvider.key
property alias containerStack: extruderSettingProvider.containerStack
property UM.SettingPropertyProvider extruderSettingProvider: UM.SettingPropertyProvider
{
id: extruderSettingProvider
containerStack: Cura.MachineManager.activeMachine
watchedProperties: [ "value" ]
storeIndex: 0
}
function onClickExtruder(index)
{
forceActiveFocus();
extruderSettingProvider.setPropertyValue("value", index);
}
Repeater
{
id: extruderButtonRepeater
model: CuraApplication.getExtrudersModel()
delegate: Item
{
width: {
// This will "squish" the extruder buttons together when the fill up the horizontal space
const maximum_width = Math.floor(extruderSelectionBar.width / extruderButtonRepeater.count);
return Math.min(UM.Theme.getSize("large_button").width, maximum_width);
}
height: childrenRect.height
Cura.ExtruderButton
{
anchors.margins: 0
padding: 0
extruder: model
checked: extruder.index === selectedIndex
iconScale: 0.8
font: UM.Theme.getFont("tiny_emphasis")
buttonSize: UM.Theme.getSize("small_button").width
onClicked: extruder.enabled && onClickExtruder(extruder.index)
}
}
}
}

View File

@ -0,0 +1,105 @@
// Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 2.15
import UM 1.7 as UM
import Cura 1.7 as Cura
// This silder allows changing of a single setting. Only the setting name has to be passed in to "settingName".
// All of the setting updating logic is handled by this component.
// This component allows you to choose values between minValue -> maxValue and rounds them to the nearest 10.
// If the setting is limited to a single extruder or is settable with different values per extruder use "updateAllExtruders: true"
UM.Slider
{
id: settingSlider
property alias settingName: propertyProvider.key
// If true, all extruders will have "settingName" property updated.
// The displayed value will be read from the extruder with index "defaultExtruderIndex" instead of the machine.
property bool updateAllExtruders: false
// This is only used if updateAllExtruders == true
property int defaultExtruderIndex: 0
property int previousValue: -1
// set range from 0 to 100
from: 0; to: 100
// set stepSize to 10 and set snapMode to snap on release snapMode is needed
// otherwise the used percentage and slider handle show different values
stepSize: 10; snapMode: Slider.SnapOnRelease
UM.SettingPropertyProvider
{
id: propertyProvider
containerStackId: updateAllExtruders ? Cura.ExtruderManager.extruderIds[defaultExtruderIndex] : Cura.MachineManager.activeMachine.id
watchedProperties: ["value"]
storeIndex: 0
}
// set initial value from stack
value: parseInt(propertyProvider.properties.value)
// When the slider is released trigger an update immediately. This forces the slider to snap to the rounded value.
onPressedChanged: function(pressed)
{
if(!pressed)
{
updateSetting(settingSlider.value);
}
}
Connections
{
target: propertyProvider
function onContainerStackChanged()
{
updateTimer.restart()
}
function onIsValueUsedChanged()
{
updateTimer.restart()
}
}
// Updates to the setting are delayed by interval. This reduces lag by waiting a bit after a setting change to update the slider contents.
Timer
{
id: updateTimer
interval: 100
repeat: false
onTriggered: parseValueUpdateSetting(false)
}
function updateSlider(value)
{
settingSlider.value = value
}
function parseValueUpdateSetting(triggerUpdate)
{
// Only run when the setting value is updated by something other than the slider.
// This sets the slider value based on the setting value, it does not update the setting value.
if (parseInt(propertyProvider.properties.value) == settingSlider.value)
{
return
}
settingSlider.value = propertyProvider.properties.value
}
// Override this function to update a setting differently
function updateSetting(value)
{
if (updateAllExtruders)
{
Cura.MachineManager.setSettingForAllExtruders(propertyProvider.key, "value", value)
}
else
{
propertyProvider.setPropertyValue("value", value)
}
}
}

View File

@ -0,0 +1,188 @@
// Copyright (c) 2022 UltiMaker
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import UM 1.7 as UM
import Cura 1.7 as Cura
// This text field allows you to edit a single setting. The setting can be passed by "settingName".
// You must specify a validator with Validator. We store our default setting validators in qml/Validators
// If the setting is limited to a single extruder or is settable with different values per extruder use "updateAllExtruders: true"
UM.TextField
{
id: control
property alias settingName: propertyProvider.key
// If true, all extruders will have "settingName" property updated.
// The displayed value will be read from the extruder with index "defaultExtruderIndex" instead of the machine.
property bool updateAllExtruders: false
// This is only used if updateAllExtruders == true
property int defaultExtruderIndex: 0
// Resolving the value in the textField.
Binding
{
target: control
property: "text"
value:
{
if (control.activeFocus)
{
// This stops the text being reformatted as you edit. For example "10.1" -Edit-> "10." -Auto Format-> "10.0".
return control.text
}
if (( propertyProvider.properties.resolve != "None" && propertyProvider.properties.resolve) && ( propertyProvider.properties.stackLevels[0] != 0) && ( propertyProvider.properties.stackLevels[0] != 1))
{
// We have a resolve function. Indicates that the setting is not settable per extruder and that
// we have to choose between the resolved value (default) and the global value
// (if user has explicitly set this).
return base.resolve
}
return propertyProvider.properties.value
}
}
property UM.SettingPropertyProvider propertyProvider: UM.SettingPropertyProvider
{
id: propertyProvider
watchedProperties: ["value", "validationState", "resolve"]
containerStackId: updateAllExtruders ? Cura.ExtruderManager.extruderIds[defaultExtruderIndex] : Cura.MachineManager.activeMachine.id
}
Connections
{
target: propertyProvider
function onContainerStackChanged()
{
updateTimer.restart()
}
function onIsValueUsedChanged()
{
updateTimer.restart()
}
}
// Restart update timer right after releasing a key. This stops lag while typing, but you still get warning and error
// textfield styling while typing.
Keys.onReleased: updateTimer.restart()
// Forces formatting when you finish editing "10.1" -Edit-> "10." -Focus Change-> "10"
onActiveFocusChanged: updateTimer.restart()
// Updates to the setting are delayed by interval. This stops lag caused by calling the
// parseValueUpdateSetting() function being called repeatedly while changing the text value.
Timer
{
id: updateTimer
interval: 50
repeat: false
onTriggered: parseValueUpdateSetting()
}
function parseValueUpdateSetting()
{
if (propertyProvider.properties.value === text || (parseFloat(propertyProvider.properties.value) === parseFloat(text)))
{
// Don't set the property value from the control. It already has the same value
return
}
if (propertyProvider && text !== propertyProvider.properties.value)
{
updateSetting(text);
}
}
function updateSetting(value)
{
if (updateAllExtruders)
{
Cura.MachineManager.setSettingForAllExtruders(propertyProvider.key, "value", value)
}
else
{
propertyProvider.setPropertyValue("value", text)
}
}
// Forced to override parent states using overrideState. Otherwise hover in TextField.qml would override the validation states.
// The first state to evaluate true applies styling. States in inheriting components get appended to the state list of their parent.
overrideState: true
states:
[
State
{
name: "validationError"
when: propertyProvider.properties.validationState === "ValidatorState.Exception" || propertyProvider.properties.validationState === "ValidatorState.MinimumError" || propertyProvider.properties.validationState === "ValidatorState.MaximumError"
PropertyChanges
{
target: background
liningColor: UM.Theme.getColor("setting_validation_error")
color: UM.Theme.getColor("setting_validation_error_background")
}
},
State
{
name: "validationWarning"
when: propertyProvider.properties.validationState === "ValidatorState.MinimumWarning" || propertyProvider.properties.validationState === "ValidatorState.MaximumWarning"
PropertyChanges
{
target: background
liningColor: UM.Theme.getColor("setting_validation_warning")
color: UM.Theme.getColor("setting_validation_warning_background")
}
},
State
{
name: "disabled"
when: !control.enabled
PropertyChanges
{
target: control
color: UM.Theme.getColor("text_field_text_disabled")
}
PropertyChanges
{
target: background
liningColor: UM.Theme.getColor("text_field_border_disabled")
}
},
State
{
name: "invalid"
when: !control.acceptableInput
PropertyChanges
{
target: background
color: UM.Theme.getColor("setting_validation_error_background")
}
},
State
{
name: "active"
when: control.activeFocus
PropertyChanges
{
target: background
liningColor: UM.Theme.getColor("text_field_border_active")
borderColor: UM.Theme.getColor("text_field_border_active")
}
},
State
{
name: "hovered"
when: control.hovered && !control.activeFocus
PropertyChanges
{
target: background
liningColor: UM.Theme.getColor("text_field_border_hovered")
}
}
]
}

View File

@ -4,87 +4,12 @@
import QtQuick 2.10 import QtQuick 2.10
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import UM 1.5 as UM import UM 1.7 as UM
import Cura 1.1 as Cura import Cura 1.1 as Cura
UM.TextField
//
// Cura-style TextField
//
TextField
{ {
id: control id: control
property alias leftIcon: iconLeft.source
height: UM.Theme.getSize("setting_control").height height: UM.Theme.getSize("setting_control").height
leftPadding: UM.Theme.getSize("thin_margin").width
hoverEnabled: true
selectByMouse: true
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text_field_text")
selectedTextColor: UM.Theme.getColor("text_field_text")
placeholderTextColor: UM.Theme.getColor("text_field_text_disabled")
renderType: Text.NativeRendering
selectionColor: UM.Theme.getColor("text_selection")
leftPadding: iconLeft.visible ? iconLeft.width + UM.Theme.getSize("default_margin").width * 2 : UM.Theme.getSize("thin_margin").width
states: [
State
{
name: "disabled"
when: !control.enabled
PropertyChanges { target: control; color: UM.Theme.getColor("text_field_text_disabled")}
PropertyChanges { target: backgroundRectangle; liningColor: UM.Theme.getColor("text_field_border_disabled")}
},
State
{
name: "invalid"
when: !control.acceptableInput
PropertyChanges { target: backgroundRectangle; color: UM.Theme.getColor("setting_validation_error_background")}
},
State
{
name: "active"
when: control.activeFocus
PropertyChanges
{
target: backgroundRectangle
liningColor: UM.Theme.getColor("text_field_border_active")
borderColor: UM.Theme.getColor("text_field_border_active")
}
},
State
{
name: "hovered"
when: control.hovered && !control.activeFocus
PropertyChanges
{
target: backgroundRectangle
liningColor: UM.Theme.getColor("text_field_border_hovered")
}
}
]
background: UM.UnderlineBackground
{
id: backgroundRectangle
//Optional icon added on the left hand side.
UM.ColorImage
{
id: iconLeft
anchors
{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: UM.Theme.getSize("default_margin").width
}
visible: source != ""
height: UM.Theme.getSize("small_button_icon").height
width: visible ? height : 0
color: control.color
}
}
} }

View File

@ -19,7 +19,6 @@ SettingView 1.0 SettingView.qml
ProfileMenu 1.0 ProfileMenu.qml ProfileMenu 1.0 ProfileMenu.qml
PrintSelectorCard 1.0 PrintSelectorCard.qml PrintSelectorCard 1.0 PrintSelectorCard.qml
# Cura/WelcomePages # Cura/WelcomePages
WizardPanel 1.0 WizardPanel.qml WizardPanel 1.0 WizardPanel.qml
@ -38,6 +37,11 @@ ScrollView 1.0 ScrollView.qml
Menu 1.0 Menu.qml Menu 1.0 Menu.qml
MenuItem 1.0 MenuItem.qml MenuItem 1.0 MenuItem.qml
MenuSeparator 1.0 MenuSeparator.qml MenuSeparator 1.0 MenuSeparator.qml
SingleSettingExtruderSelectorBar 1.7 SingleSettingExtruderSelectorBar.qml
ExtruderButton 1.7 ExtruderButton.qml
SingleSettingComboBox 1.7 SingleSettingComboBox.qml
SingleSettingSlider 1.7 SingleSettingSlider.qml
SingleSettingTextField 1.7 SingleSettingTextField.qml
# Cura/MachineSettings # Cura/MachineSettings

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M5.98284 20.8333C6.79951 20.8164 7.57846 20.4864 8.15864 19.9114L14.5224 13.5467L16.644 15.6682L21.5932 10.719L14.9359 4.06189H9.86594L7.45194 6.47589L10.2797 9.30399L3.91544 15.6682C3.62636 15.9408 3.39604 16.2696 3.23862 16.6345C3.0812 16.9993 3 17.3924 3 17.7898C3 18.1871 3.0812 18.5803 3.23862 18.9451C3.39604 19.31 3.62636 19.6388 3.91544 19.9114C4.17985 20.1968 4.49937 20.4257 4.85471 20.5841C5.21005 20.7426 5.59382 20.8273 5.98284 20.8333ZM10.6938 6.06189H14.1078L18.7651 10.7191L16.644 12.8402L10.2797 6.47579L10.6938 6.06189ZM5.33544 17.0764L11.6938 10.718L13.1078 12.1331L6.74454 18.4973C6.65152 18.5911 6.54085 18.6656 6.41891 18.7164C6.29696 18.7672 6.16616 18.7933 6.03406 18.7934C5.90195 18.7934 5.77115 18.7672 5.6492 18.7164C5.52726 18.6656 5.41658 18.5911 5.32356 18.4973C5.23053 18.4035 5.15701 18.2922 5.10722 18.1699C5.05743 18.0475 5.03236 17.9165 5.03347 17.7844C5.03457 17.6523 5.06182 17.5217 5.11365 17.4002C5.16548 17.2787 5.24086 17.1686 5.33544 17.0764Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,12 @@
<svg width="24" height="25" viewBox="0 0 24 25" xmlns="http://www.w3.org/2000/svg">
<path d="M15 10.0619C15 10.6142 15.4477 11.0619 16 11.0619C16.5523 11.0619 17 10.6142 17 10.0619C17 9.5096 16.5523 9.06189 16 9.06189C15.4477 9.06189 15 9.5096 15 10.0619Z"/>
<path d="M15 14.0619C15 14.6142 15.4477 15.0619 16 15.0619C16.5523 15.0619 17 14.6142 17 14.0619C17 13.5096 16.5523 13.0619 16 13.0619C15.4477 13.0619 15 13.5096 15 14.0619Z"/>
<path d="M15 18.0619C15 18.6142 15.4477 19.0619 16 19.0619C16.5523 19.0619 17 18.6142 17 18.0619C17 17.5096 16.5523 17.0619 16 17.0619C15.4477 17.0619 15 17.5096 15 18.0619Z"/>
<path d="M7 18.0619C7 18.6142 7.44772 19.0619 8 19.0619C8.55228 19.0619 9 18.6142 9 18.0619C9 17.5096 8.55228 17.0619 8 17.0619C7.44772 17.0619 7 17.5096 7 18.0619Z" />
<path d="M7 14.0619C7 14.6142 7.44772 15.0619 8 15.0619C8.55228 15.0619 9 14.6142 9 14.0619C9 13.5096 8.55228 13.0619 8 13.0619C7.44772 13.0619 7 13.5096 7 14.0619Z" />
<path d="M7 10.0619C7 10.6142 7.44772 11.0619 8 11.0619C8.55228 11.0619 9 10.6142 9 10.0619C9 9.5096 8.55228 9.06189 8 9.06189C7.44772 9.06189 7 9.5096 7 10.0619Z" />
<path d="M7 6.06189C7 6.61417 7.44772 7.06189 8 7.06189C8.55228 7.06189 9 6.61417 9 6.06189C9 5.5096 8.55228 5.06189 8 5.06189C7.44772 5.06189 7 5.5096 7 6.06189Z" />
<path d="M15 6.06189C15 6.61417 15.4477 7.06189 16 7.06189C16.5523 7.06189 17 6.61417 17 6.06189C17 5.5096 16.5523 5.06189 16 5.06189C15.4477 5.06189 15 5.5096 15 6.06189Z" />
<path d="M19 6.06189L19 20.8819C19.5835 20.6756 20.089 20.2938 20.4471 19.789C20.8051 19.2841 20.9983 18.6808 21 18.0619L21 6.06189C20.9983 5.44295 20.8051 4.83969 20.4471 4.33482C20.089 3.82996 19.5835 3.4482 19 3.24189L19 6.06189Z"/>
<path d="M5 19.0619L5 3.24189C4.41645 3.4482 3.911 3.82996 3.55294 4.33482C3.19488 4.83969 3.00174 5.44295 3 6.06189L3 18.0619C3.00174 18.6808 3.19488 19.2841 3.55294 19.789C3.911 20.2938 4.41645 20.6756 5 20.8819L5 19.0619Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -172,6 +172,26 @@
"size": 0.9, "size": 0.9,
"weight": 700, "weight": 700,
"family": "Noto Sans" "family": "Noto Sans"
},
"tiny_emphasis": {
"size": 0.7,
"weight": 700,
"family": "Noto Sans"
},
"tiny_emphasis_ja_JP": {
"size": 0.7,
"weight": 700,
"family": "Noto Sans"
},
"tiny_emphasis_zh_CN": {
"size": 0.7,
"weight": 700,
"family": "Noto Sans"
},
"tiny_emphasis_zh_TW": {
"size": 0.7,
"weight": 700,
"family": "Noto Sans"
} }
}, },
@ -354,6 +374,10 @@
"checkbox_text": "text_default", "checkbox_text": "text_default",
"checkbox_text_disabled": "text_disabled", "checkbox_text_disabled": "text_disabled",
"switch": "background_1",
"switch_state_checked": "accent_1",
"switch_state_unchecked": "text_disabled",
"radio": "background_1", "radio": "background_1",
"radio_disabled": "background_2", "radio_disabled": "background_2",
"radio_selected": "accent_1", "radio_selected": "accent_1",
@ -486,9 +510,9 @@
"print_setup_widget": [38.0, 30.0], "print_setup_widget": [38.0, 30.0],
"print_setup_extruder_box": [0.0, 6.0], "print_setup_extruder_box": [0.0, 6.0],
"print_setup_slider_groove": [0.16, 0.16], "slider_widget_groove": [0.16, 0.16],
"print_setup_slider_handle": [1.0, 1.0], "slider_widget_handle": [1.3, 1.3],
"print_setup_slider_tickmarks": [0.32, 0.32], "slider_widget_tickmarks": [0.5, 0.5],
"print_setup_big_item": [28, 2.5], "print_setup_big_item": [28, 2.5],
"print_setup_icon": [1.2, 1.2], "print_setup_icon": [1.2, 1.2],
"drag_icon": [1.416, 0.25], "drag_icon": [1.416, 0.25],
@ -649,6 +673,8 @@
"recommended_button_icon": [1.7, 1.7], "recommended_button_icon": [1.7, 1.7],
"recommended_section_setting_item": [14.0, 2.0],
"reset_profile_icon": [1, 1] "reset_profile_icon": [1, 1]
} }
} }

View File

@ -6,6 +6,7 @@
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
import pytest import pytest
from UM.Application import Application
from UM.Qt.QtApplication import QtApplication # QtApplication import is required, even though it isn't used. from UM.Qt.QtApplication import QtApplication # QtApplication import is required, even though it isn't used.
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
@ -22,6 +23,12 @@ def application() -> CuraApplication:
app = MagicMock() app = MagicMock()
return app return app
@pytest.fixture()
def um_application() -> Application:
app = MagicMock()
app.getInstance = MagicMock(return_value=app)
return app
# Returns a MachineActionManager instance. # Returns a MachineActionManager instance.
@pytest.fixture() @pytest.fixture()
@ -43,13 +50,14 @@ def container_registry(application, global_stack) -> ContainerRegistry:
@pytest.fixture() @pytest.fixture()
def extruder_manager(application, container_registry) -> ExtruderManager: def extruder_manager(application, um_application, container_registry) -> ExtruderManager:
if ExtruderManager.getInstance() is not None: if ExtruderManager.getInstance() is not None:
# Reset the data # Reset the data
ExtruderManager._ExtruderManager__instance = None ExtruderManager._ExtruderManager__instance = None
with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=application)): with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=application)):
with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value=container_registry)): with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value=container_registry)):
with patch("UM.Application.Application.getInstance", um_application):
manager = ExtruderManager() manager = ExtruderManager()
return manager return manager