// Copyright (c) 2017 Ultimaker B.V. // Uranium is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.2 import UM 1.2 as UM import Cura 1.0 as Cura import ".." Item { id: base width: childrenRect.width height: childrenRect.height property var all_categories_except_support: [ "machine_settings", "resolution", "shell", "infill", "material", "speed", "travel", "cooling", "platform_adhesion", "dual", "meshfix", "blackmagic", "experimental"] readonly property var normal_mesh_type: "" readonly property var support_mesh_type: "support_mesh" readonly property var cutting_mesh_type: "cutting_mesh" readonly property var infill_mesh_type: "infill_mesh" readonly property var anti_overhang_mesh_type: "anti_overhang_mesh" property var current_mesh_type: normal_mesh_type function setOverhangsMeshType(){ if(infillOnlyCheckbox.checked) { setMeshType(infill_mesh_type) } else { setMeshType(cutting_mesh_type) } } function setMeshType(type) { current_mesh_type = type // update the active object if(UM.ActiveTool.properties.getValue("MeshType") !== type) { UM.ActiveTool.setProperty("MeshType", type) } // set checked state of mesh type buttons normalButton.checked = current_mesh_type === normal_mesh_type supportMeshButton.checked = current_mesh_type === support_mesh_type overhangMeshButton.checked = current_mesh_type === infill_mesh_type || current_mesh_type === cutting_mesh_type antiOverhangMeshButton.checked = current_mesh_type === anti_overhang_mesh_type // update active type label for (var button in meshTypeButtons.children) { if(meshTypeButtons.children[button].checked){ meshTypeLabel.text = catalog.i18nc("@label","Mesh Type") + ": " + meshTypeButtons.children[button].text break } } } UM.I18nCatalog { id: catalog; name: "uranium"} Column { id: items anchors.top: parent.top; anchors.left: parent.left; spacing: UM.Theme.getSize("default_margin").height Component.onCompleted: setMeshType(UM.ActiveTool.properties.getValue("MeshType")) Row // Mesh type buttons { id: meshTypeButtons spacing: UM.Theme.getSize("default_margin").width Button { id: normalButton text: catalog.i18nc("@label", "Normal model") iconSource: UM.Theme.getIcon("pos_normal"); property bool needBorder: true checkable: true onClicked: setMeshType(normal_mesh_type); style: UM.Theme.styles.tool_button; z: 4 } Button { id: supportMeshButton text: catalog.i18nc("@label", "Print as support") iconSource: UM.Theme.getIcon("pos_print_as_support"); property bool needBorder: true checkable:true onClicked: setMeshType(support_mesh_type) style: UM.Theme.styles.tool_button; z: 3 } Button { id: overhangMeshButton text: catalog.i18nc("@label", "Modify settings for overlays") iconSource: UM.Theme.getIcon("pos_modify_overlaps"); property bool needBorder: true checkable:true onClicked: setMeshType(infill_mesh_type) style: UM.Theme.styles.tool_button; z: 2 } Button { id: antiOverhangMeshButton text: catalog.i18nc("@label", "Don't support overlaps") iconSource: UM.Theme.getIcon("pos_modify_dont_support_overlap"); property bool needBorder: true checkable: true onClicked: setMeshType(anti_overhang_mesh_type) style: UM.Theme.styles.tool_button; z: 1 } } Row // Selected mesh type label { spacing: UM.Theme.getSize("default_margin").width Label { id: meshTypeLabel font: UM.Theme.getFont("default") color: UM.Theme.getColor("text") height: UM.Theme.getSize("setting").height verticalAlignment: Text.AlignVCenter } } Row // Infill-only checkbox (visible for overhang mesh button) { spacing: UM.Theme.getSize("default_margin").width CheckBox { id: infillOnlyCheckbox text: catalog.i18nc("@action:checkbox","Infill only"); style: UM.Theme.styles.checkbox; checked: current_mesh_type === infill_mesh_type visible: current_mesh_type === infill_mesh_type || current_mesh_type === cutting_mesh_type onClicked: setOverhangsMeshType() } } Row { spacing: UM.Theme.getSize("default_margin").width Button { id: customiseSettingsButton; height: UM.Theme.getSize("setting_control").height; visible: currentSettings.visible text: catalog.i18nc("@action:button", "Select settings"); style: ButtonStyle { background: Rectangle { width: control.width; height: control.height; border.width: UM.Theme.getSize("default_lining").width; border.color: control.pressed ? UM.Theme.getColor("action_button_active_border") : control.hovered ? UM.Theme.getColor("action_button_hovered_border") : UM.Theme.getColor("action_button_border") color: control.pressed ? UM.Theme.getColor("action_button_active") : control.hovered ? UM.Theme.getColor("action_button_hovered") : UM.Theme.getColor("action_button") } label: Label { text: control.text; color: UM.Theme.getColor("setting_control_text"); font: UM.Theme.getFont("default") anchors.centerIn: parent } } onClicked: { settingPickDialog.visible = true; if (meshTypeSelection.model.get(meshTypeSelection.currentIndex).type == "support_mesh") { settingPickDialog.additional_excluded_settings = base.all_categories_except_support; } else { settingPickDialog.additional_excluded_settings = [] } } } } } Column // Settings Dialog { // This is to ensure that the panel is first increasing in size up to 200 and then shows a scrollbar. // It kinda looks ugly otherwise (big panel, no content on it) id: currentSettings property int maximumHeight: 200 * screenScaleFactor height: Math.min(contents.count * (UM.Theme.getSize("section").height + UM.Theme.getSize("default_lining").height), maximumHeight) visible: current_mesh_type != "anti_overhang_mesh" ScrollView { height: parent.height width: UM.Theme.getSize("setting").width + UM.Theme.getSize("default_margin").width style: UM.Theme.styles.scrollview ListView { id: contents spacing: UM.Theme.getSize("default_lining").height model: UM.SettingDefinitionsModel { id: addedSettingsModel; containerId: Cura.MachineManager.activeMachine != null ? Cura.MachineManager.activeMachine.definition.id: "" expanded: [ "*" ] filter: { if (printSequencePropertyProvider.properties.value == "one_at_a_time") { return {"settable_per_meshgroup": true}; } return {"settable_per_mesh": true}; } exclude: { var excluded_settings = [ "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ]; if(current_mesh_type == "support_mesh") { excluded_settings = excluded_settings.concat(base.all_categories_except_support); } return excluded_settings; } visibilityHandler: Cura.PerObjectSettingVisibilityHandler { selectedObjectId: UM.ActiveTool.properties.getValue("SelectedObjectId") } // For some reason the model object is updated after removing him from the memory and // it happens only on Windows. For this reason, set the destroyed value manually. Component.onDestruction: { setDestroyed(true); } } delegate: Row { spacing: - UM.Theme.getSize("default_margin").width Loader { id: settingLoader width: UM.Theme.getSize("setting").width height: UM.Theme.getSize("section").height property var definition: model property var settingDefinitionsModel: addedSettingsModel property var propertyProvider: provider property var globalPropertyProvider: inheritStackProvider property var externalResetHandler: false //Qt5.4.2 and earlier has a bug where this causes a crash: https://bugreports.qt.io/browse/QTBUG-35989 //In addition, while it works for 5.5 and higher, the ordering of the actual combo box drop down changes, //causing nasty issues when selecting different options. So disable asynchronous loading of enum type completely. asynchronous: model.type != "enum" && model.type != "extruder" onLoaded: { settingLoader.item.showRevertButton = false settingLoader.item.showInheritButton = false settingLoader.item.showLinkedSettingIcon = false settingLoader.item.doDepthIndentation = false settingLoader.item.doQualityUserSettingEmphasis = false } sourceComponent: { switch(model.type) { case "int": return settingTextField case "[int]": return settingTextField case "float": return settingTextField case "enum": return settingComboBox case "extruder": return settingExtruder case "optional_extruder": return settingOptionalExtruder case "bool": return settingCheckBox case "str": return settingTextField case "category": return settingCategory default: return settingUnknown } } } Button { width: Math.round(UM.Theme.getSize("setting").height / 2) height: UM.Theme.getSize("setting").height onClicked: addedSettingsModel.setVisible(model.key, false) style: ButtonStyle { background: Item { UM.RecolorImage { anchors.verticalCenter: parent.verticalCenter width: parent.width height: width sourceSize.height: width color: control.hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button") source: UM.Theme.getIcon("minus") } } } } // Specialty provider that only watches global_inherits (we cant filter on what property changed we get events // so we bypass that to make a dedicated provider). UM.SettingPropertyProvider { id: provider containerStackId: UM.ActiveTool.properties.getValue("ContainerID") key: model.key watchedProperties: [ "value", "enabled", "validationState" ] storeIndex: 0 removeUnusedValue: false } UM.SettingPropertyProvider { id: inheritStackProvider containerStackId: UM.ActiveTool.properties.getValue("ContainerID") key: model.key watchedProperties: [ "limit_to_extruder" ] } Connections { target: inheritStackProvider onPropertiesChanged: { provider.forcePropertiesChanged(); } } Connections { target: UM.ActiveTool onPropertiesChanged: { // the values cannot be bound with UM.ActiveTool.properties.getValue() calls, // so here we connect to the signal and update the those values. if (typeof UM.ActiveTool.properties.getValue("SelectedObjectId") !== "undefined") { const selectedObjectId = UM.ActiveTool.properties.getValue("SelectedObjectId"); if (addedSettingsModel.visibilityHandler.selectedObjectId != selectedObjectId) { addedSettingsModel.visibilityHandler.selectedObjectId = selectedObjectId; } } if (typeof UM.ActiveTool.properties.getValue("ContainerID") !== "undefined") { const containerId = UM.ActiveTool.properties.getValue("ContainerID"); if (provider.containerStackId != containerId) { provider.containerStackId = containerId; } if (inheritStackProvider.containerStackId != containerId) { inheritStackProvider.containerStackId = containerId; } } } } } } } } UM.Dialog { id: settingPickDialog title: catalog.i18nc("@title:window", "Select Settings to Customize for this model") width: screenScaleFactor * 360 property var additional_excluded_settings onVisibilityChanged: { // force updating the model to sync it with addedSettingsModel if(visible) { // Set skip setting, it will prevent from resetting selected mesh_type contents.model.visibilityHandler.addSkipResetSetting(meshTypeSelection.model.get(meshTypeSelection.currentIndex).type) listview.model.forceUpdate() updateFilter() } } function updateFilter() { var new_filter = {}; new_filter["settable_per_mesh"] = true; // Don't filter on "settable_per_meshgroup" any more when `printSequencePropertyProvider.properties.value` // is set to "one_at_a_time", because the current backend architecture isn't ready for that. if(filterInput.text != "") { new_filter["i18n_label"] = "*" + filterInput.text; } listview.model.filter = new_filter; } TextField { id: filterInput anchors { top: parent.top left: parent.left right: toggleShowAll.left rightMargin: UM.Theme.getSize("default_margin").width } placeholderText: catalog.i18nc("@label:textbox", "Filter..."); onTextChanged: settingPickDialog.updateFilter() } CheckBox { id: toggleShowAll anchors { top: parent.top right: parent.right } text: catalog.i18nc("@label:checkbox", "Show all") checked: listview.model.showAll onClicked: { listview.model.showAll = checked; } } ScrollView { id: scrollView anchors { top: filterInput.bottom; left: parent.left; right: parent.right; bottom: parent.bottom; } ListView { id:listview model: UM.SettingDefinitionsModel { id: definitionsModel; containerId: Cura.MachineManager.activeMachine != null ? Cura.MachineManager.activeMachine.definition.id: "" visibilityHandler: UM.SettingPreferenceVisibilityHandler {} expanded: [ "*" ] exclude: { var excluded_settings = [ "machine_settings", "command_line_settings", "support_mesh", "anti_overhang_mesh", "cutting_mesh", "infill_mesh" ]; excluded_settings = excluded_settings.concat(settingPickDialog.additional_excluded_settings); return excluded_settings; } } delegate:Loader { id: loader width: parent.width height: model.type != undefined ? UM.Theme.getSize("section").height : 0; property var definition: model property var settingDefinitionsModel: definitionsModel asynchronous: true source: { switch(model.type) { case "category": return "PerObjectCategory.qml" default: return "PerObjectItem.qml" } } } Component.onCompleted: settingPickDialog.updateFilter() } } rightButtons: [ Button { text: catalog.i18nc("@action:button", "Close"); onClicked: { settingPickDialog.visible = false; } } ] } UM.SettingPropertyProvider { id: machineExtruderCount containerStack: Cura.MachineManager.activeMachine key: "machine_extruder_count" watchedProperties: [ "value" ] storeIndex: 0 } UM.SettingPropertyProvider { id: printSequencePropertyProvider containerStack: Cura.MachineManager.activeMachine key: "print_sequence" watchedProperties: [ "value" ] storeIndex: 0 } SystemPalette { id: palette; } Component { id: settingTextField; Cura.SettingTextField { } } Component { id: settingComboBox; Cura.SettingComboBox { } } Component { id: settingExtruder; Cura.SettingExtruder { } } Component { id: settingOptionalExtruder Cura.SettingOptionalExtruder { } } Component { id: settingCheckBox; Cura.SettingCheckBox { } } Component { id: settingCategory; Cura.SettingCategory { } } Component { id: settingUnknown; Cura.SettingUnknown { } } }