mirror of
https://github.com/Ultimaker/Cura.git
synced 2026-03-05 01:54:37 -07:00
Introduced isMultilineSetting() to parse the comments field for multiline directives in various formats. Updated the string setting type to use this helper, improving flexibility in specifying multiline text areas. Supports "multiline" or "@[multiline]" or "@[multiline, other] comment" which can be extended later if required.
557 lines
20 KiB
QML
557 lines
20 KiB
QML
// Copyright (c) 2022 Jaime van Kessel, Ultimaker B.V.
|
|
// The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
|
|
|
|
import QtQuick 2.2
|
|
import QtQuick.Controls 2.15
|
|
import QtQml.Models 2.15 as Models
|
|
import QtQuick.Layouts 1.1
|
|
import QtQuick.Window 2.2
|
|
|
|
import UM 1.5 as UM
|
|
import Cura 1.0 as Cura
|
|
|
|
UM.Dialog
|
|
{
|
|
id: dialog
|
|
|
|
title: catalog.i18nc("@title:window", "Post Processing Plugin")
|
|
width: 700 * screenScaleFactor
|
|
height: 500 * screenScaleFactor
|
|
minimumWidth: 400 * screenScaleFactor
|
|
minimumHeight: 250 * screenScaleFactor
|
|
backgroundColor: UM.Theme.getColor("main_background")
|
|
onVisibleChanged:
|
|
{
|
|
// Whenever the window is closed (either via the "Close" button or the X on the window frame), we want to update it in the stack.
|
|
if (!visible)
|
|
{
|
|
manager.writeScriptsToStack()
|
|
}
|
|
}
|
|
|
|
Item
|
|
{
|
|
UM.I18nCatalog{id: catalog; name: "cura"}
|
|
id: base
|
|
property int columnWidth: Math.round((base.width / 2) - UM.Theme.getSize("default_margin").width)
|
|
property int textMargin: UM.Theme.getSize("narrow_margin").width
|
|
property string activeScriptName
|
|
|
|
anchors.fill: parent
|
|
|
|
// Helper function to check if a setting should use multiline text area
|
|
// Supports "multiline" or "@[multiline]" or "@[multiline, other] comment"
|
|
function isMultilineSetting(definition)
|
|
{
|
|
if (!definition || !definition.comments)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var commentsLower = definition.comments.toLowerCase();
|
|
|
|
// Simple format: exact match
|
|
if (commentsLower === "multiline")
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Directive format: parse @[...] and check if multiline is in the list
|
|
var directiveStart = commentsLower.indexOf("@[");
|
|
var directiveEnd = commentsLower.indexOf("]", directiveStart);
|
|
if (directiveStart >= 0 && directiveEnd > directiveStart)
|
|
{
|
|
var directivesText = commentsLower.substring(directiveStart + 2, directiveEnd);
|
|
var directives = directivesText.split(",");
|
|
for (var i = 0; i < directives.length; i++)
|
|
{
|
|
if (directives[i].trim() === "multiline")
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ButtonGroup
|
|
{
|
|
id: selectedScriptGroup
|
|
}
|
|
Column
|
|
{
|
|
id: activeScripts
|
|
width: base.columnWidth
|
|
height: parent.height
|
|
|
|
spacing: base.textMargin
|
|
|
|
UM.Label
|
|
{
|
|
id: activeScriptsHeader
|
|
text: catalog.i18nc("@label", "Post Processing Scripts")
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
font: UM.Theme.getFont("large_bold")
|
|
elide: Text.ElideRight
|
|
}
|
|
ListView
|
|
{
|
|
id: activeScriptsList
|
|
anchors
|
|
{
|
|
left: parent.left
|
|
right: parent.right
|
|
rightMargin: base.textMargin
|
|
}
|
|
height: Math.min(contentHeight, parent.height - parent.spacing * 2 - activeScriptsHeader.height - addButton.height) //At the window height, start scrolling this one.
|
|
|
|
clip: true
|
|
ScrollBar.vertical: UM.ScrollBar
|
|
{
|
|
id: activeScriptsScrollBar
|
|
}
|
|
model: manager.scriptList
|
|
|
|
delegate: Button
|
|
{
|
|
id: activeScriptButton
|
|
|
|
width: parent.width - activeScriptsScrollBar.width
|
|
height: UM.Theme.getSize("standard_list_lineheight").height
|
|
|
|
ButtonGroup.group: selectedScriptGroup
|
|
checkable: true
|
|
|
|
checked:
|
|
{
|
|
if (manager.selectedScriptIndex == index)
|
|
{
|
|
base.activeScriptName = manager.getScriptLabelByKey(modelData.toString())
|
|
return true
|
|
}
|
|
else
|
|
{
|
|
return false
|
|
}
|
|
}
|
|
|
|
background: Rectangle
|
|
{
|
|
color: activeScriptButton.checked ? UM.Theme.getColor("background_3") : "transparent"
|
|
}
|
|
|
|
onClicked:
|
|
{
|
|
forceActiveFocus()
|
|
manager.setSelectedScriptIndex(index)
|
|
base.activeScriptName = manager.getScriptLabelByKey(modelData.toString())
|
|
}
|
|
|
|
RowLayout
|
|
{
|
|
anchors.fill: parent
|
|
|
|
UM.Label
|
|
{
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: height
|
|
elide: Text.ElideRight
|
|
text: manager.getScriptLabelByKey(modelData.toString())
|
|
}
|
|
|
|
Item
|
|
{
|
|
id: downButton
|
|
Layout.preferredWidth: height
|
|
Layout.fillHeight: true
|
|
enabled: index != manager.scriptList.length - 1
|
|
|
|
MouseArea
|
|
{
|
|
anchors.fill: parent
|
|
onClicked:
|
|
{
|
|
if (manager.selectedScriptIndex == index)
|
|
{
|
|
manager.setSelectedScriptIndex(index + 1)
|
|
}
|
|
return manager.moveScript(index, index + 1)
|
|
}
|
|
}
|
|
|
|
UM.ColorImage
|
|
{
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: UM.Theme.getSize("standard_arrow").width
|
|
height: UM.Theme.getSize("standard_arrow").height
|
|
color: parent.enabled ? UM.Theme.getColor("text") : UM.Theme.getColor("text_disabled")
|
|
source: UM.Theme.getIcon("ChevronSingleDown")
|
|
}
|
|
}
|
|
Item
|
|
{
|
|
id: upButton
|
|
Layout.preferredWidth: height
|
|
Layout.fillHeight: true
|
|
enabled: index != 0
|
|
|
|
MouseArea
|
|
{
|
|
anchors.fill: parent
|
|
onClicked:
|
|
{
|
|
if (manager.selectedScriptIndex == index)
|
|
{
|
|
manager.setSelectedScriptIndex(index - 1)
|
|
}
|
|
return manager.moveScript(index, index - 1)
|
|
}
|
|
}
|
|
|
|
UM.ColorImage
|
|
{
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: UM.Theme.getSize("standard_arrow").width
|
|
height: UM.Theme.getSize("standard_arrow").height
|
|
color: upButton.enabled ? UM.Theme.getColor("text") : UM.Theme.getColor("text_disabled")
|
|
source: UM.Theme.getIcon("ChevronSingleUp")
|
|
}
|
|
}
|
|
|
|
Item
|
|
{
|
|
id: removeButton
|
|
Layout.preferredWidth: height
|
|
Layout.fillHeight: true
|
|
|
|
MouseArea
|
|
{
|
|
anchors.fill: parent
|
|
onClicked: manager.removeScriptByIndex(index)
|
|
}
|
|
|
|
UM.ColorImage
|
|
{
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: UM.Theme.getSize("standard_arrow").width
|
|
height: UM.Theme.getSize("standard_arrow").height
|
|
color: UM.Theme.getColor("text")
|
|
source: UM.Theme.getIcon("Cancel")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Cura.SecondaryButton
|
|
{
|
|
id: addButton
|
|
text: catalog.i18nc("@action", "Add a script")
|
|
onClicked: scriptsMenu.open()
|
|
}
|
|
}
|
|
|
|
Cura.Menu
|
|
{
|
|
id: scriptsMenu
|
|
|
|
Models.Instantiator
|
|
{
|
|
model: manager.loadedScriptList
|
|
|
|
Cura.MenuItem
|
|
{
|
|
text: manager.getScriptLabelByKey(modelData.toString())
|
|
onTriggered: manager.addScriptToList(modelData.toString())
|
|
}
|
|
|
|
onObjectAdded: function(index, object) { scriptsMenu.insertItem(index, object)}
|
|
onObjectRemoved: function(index, object) { scriptsMenu.removeItem(object) }
|
|
}
|
|
}
|
|
|
|
Rectangle
|
|
{
|
|
color: UM.Theme.getColor("main_background")
|
|
anchors.left: activeScripts.right
|
|
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
|
anchors.right: parent.right
|
|
height: parent.height
|
|
id: settingsPanel
|
|
|
|
UM.Label
|
|
{
|
|
id: scriptSpecsHeader
|
|
text: manager.selectedScriptIndex == -1 ? catalog.i18nc("@label", "Settings") : base.activeScriptName
|
|
anchors
|
|
{
|
|
top: parent.top
|
|
topMargin: base.textMargin
|
|
left: parent.left
|
|
leftMargin: base.textMargin
|
|
right: parent.right
|
|
rightMargin: base.textMargin
|
|
}
|
|
|
|
elide: Text.ElideRight
|
|
height: 20 * screenScaleFactor
|
|
font: UM.Theme.getFont("large_bold")
|
|
}
|
|
|
|
ListView
|
|
{
|
|
id: listview
|
|
anchors
|
|
{
|
|
top: scriptSpecsHeader.bottom
|
|
topMargin: settingsPanel.textMargin
|
|
left: parent.left
|
|
leftMargin: UM.Theme.getSize("default_margin").width
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
}
|
|
|
|
ScrollBar.vertical: UM.ScrollBar {}
|
|
clip: true
|
|
visible: manager.selectedScriptDefinitionId != ""
|
|
spacing: UM.Theme.getSize("default_lining").height
|
|
|
|
model: UM.SettingDefinitionsModel
|
|
{
|
|
id: definitionsModel
|
|
containerId: manager.selectedScriptDefinitionId
|
|
onContainerIdChanged: definitionsModel.setAllVisible(true)
|
|
showAll: true
|
|
}
|
|
|
|
delegate: Loader
|
|
{
|
|
id: settingLoader
|
|
|
|
width: listview.width
|
|
height:
|
|
{
|
|
if (provider.properties.enabled == "True" && model.type != undefined)
|
|
{
|
|
if (definition && definition.comments && definition.comments.toLowerCase() === "multiline")
|
|
{
|
|
return UM.Theme.getSize("standard_list_lineheight").height + UM.Theme.getSize("narrow_margin").height + (UM.Theme.getSize("setting_control").height * 3);
|
|
}
|
|
return UM.Theme.getSize("section").height;
|
|
}
|
|
else
|
|
{
|
|
return 0
|
|
}
|
|
}
|
|
Behavior on height { NumberAnimation { duration: 100 } }
|
|
opacity: provider.properties.enabled == "True" ? 1 : 0
|
|
|
|
Behavior on opacity { NumberAnimation { duration: 100 } }
|
|
enabled: opacity > 0
|
|
|
|
property var definition: model
|
|
property var settingDefinitionsModel: definitionsModel
|
|
property var propertyProvider: provider
|
|
property var globalPropertyProvider: inheritStackProvider
|
|
|
|
//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
|
|
// Pass properties explicitly to custom components that don't extend SettingItem
|
|
if (settingLoader.item.hasOwnProperty("definition")) {
|
|
settingLoader.item.definition = settingLoader.definition
|
|
}
|
|
if (settingLoader.item.hasOwnProperty("settingDefinitionsModel")) {
|
|
settingLoader.item.settingDefinitionsModel = settingLoader.settingDefinitionsModel
|
|
}
|
|
if (settingLoader.item.hasOwnProperty("propertyProvider")) {
|
|
settingLoader.item.propertyProvider = settingLoader.propertyProvider
|
|
}
|
|
if (settingLoader.item.hasOwnProperty("globalPropertyProvider")) {
|
|
settingLoader.item.globalPropertyProvider = settingLoader.globalPropertyProvider
|
|
}
|
|
}
|
|
|
|
sourceComponent:
|
|
{
|
|
switch(model.type)
|
|
{
|
|
case "int":
|
|
return settingTextField
|
|
case "float":
|
|
return settingTextField
|
|
case "enum":
|
|
return settingComboBox
|
|
case "extruder":
|
|
return settingExtruder
|
|
case "bool":
|
|
return settingCheckBox
|
|
case "str":
|
|
return base.isMultilineSetting(definition) ? settingTextArea : settingTextField
|
|
case "category":
|
|
return settingCategory
|
|
default:
|
|
return settingUnknown
|
|
}
|
|
}
|
|
|
|
UM.SettingPropertyProvider
|
|
{
|
|
id: provider
|
|
containerStackId: manager.selectedScriptStackId
|
|
key: model.key ? model.key : "None"
|
|
watchedProperties: [ "value", "enabled", "state", "validationState" ]
|
|
storeIndex: 0
|
|
}
|
|
|
|
// Specialty provider that only watches global_inherits (we can't filter on what property changed we get events
|
|
// so we bypass that to make a dedicated provider).
|
|
UM.SettingPropertyProvider
|
|
{
|
|
id: inheritStackProvider
|
|
containerStack: Cura.MachineManager.activeMachine
|
|
key: model.key ? model.key : "None"
|
|
watchedProperties: [ "limit_to_extruder" ]
|
|
}
|
|
|
|
Connections
|
|
{
|
|
target: item
|
|
|
|
function onShowTooltip(text)
|
|
{
|
|
tooltip.text = text;
|
|
var position = settingLoader.mapToItem(settingsPanel, settingsPanel.x, 0);
|
|
tooltip.show(position);
|
|
tooltip.target.x = position.x + 1;
|
|
}
|
|
|
|
function onHideTooltip() { tooltip.hide() }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Cura.PrintSetupTooltip
|
|
{
|
|
id: tooltip
|
|
}
|
|
|
|
Component
|
|
{
|
|
id: settingTextField;
|
|
|
|
Cura.SettingTextField { }
|
|
}
|
|
|
|
Component
|
|
{
|
|
id: settingTextArea;
|
|
|
|
SettingTextArea { }
|
|
}
|
|
|
|
Component
|
|
{
|
|
id: settingComboBox;
|
|
|
|
Cura.SettingComboBox { }
|
|
}
|
|
|
|
Component
|
|
{
|
|
id: settingExtruder;
|
|
|
|
Cura.SettingExtruder { }
|
|
}
|
|
|
|
Component
|
|
{
|
|
id: settingCheckBox;
|
|
|
|
Cura.SettingCheckBox { }
|
|
}
|
|
|
|
Component
|
|
{
|
|
id: settingCategory;
|
|
|
|
Cura.SettingCategory { }
|
|
}
|
|
|
|
Component
|
|
{
|
|
id: settingUnknown;
|
|
|
|
Cura.SettingUnknown { }
|
|
}
|
|
}
|
|
|
|
rightButtons: Cura.TertiaryButton
|
|
{
|
|
text: catalog.i18nc("@action:button", "Close")
|
|
onClicked: dialog.accept()
|
|
}
|
|
|
|
Item
|
|
{
|
|
objectName: "postProcessingSaveAreaButton"
|
|
visible: activeScriptsList.count > 0
|
|
height: UM.Theme.getSize("action_button").height
|
|
width: height
|
|
|
|
Cura.SecondaryButton
|
|
{
|
|
height: UM.Theme.getSize("action_button").height
|
|
tooltip:
|
|
{
|
|
var tipText = catalog.i18nc("@info:tooltip", "Change active post-processing scripts.");
|
|
if (activeScriptsList.count > 0)
|
|
{
|
|
tipText += "<br><br>" + catalog.i18ncp("@info:tooltip",
|
|
"The following script is active:",
|
|
"The following scripts are active:",
|
|
activeScriptsList.count
|
|
) + "<ul>";
|
|
for(var i = 0; i < activeScriptsList.count; i++)
|
|
{
|
|
tipText += "<li>" + manager.getScriptLabelByKey(manager.scriptList[i]) + "</li>";
|
|
}
|
|
tipText += "</ul>";
|
|
}
|
|
return tipText
|
|
}
|
|
toolTipContentAlignment: UM.Enums.ContentAlignment.AlignLeft
|
|
onClicked: dialog.show()
|
|
iconSource: Qt.resolvedUrl("Script.svg")
|
|
fixedWidthMode: false
|
|
}
|
|
|
|
Cura.NotificationIcon
|
|
{
|
|
id: activeScriptCountIcon
|
|
visible: activeScriptsList.count > 0
|
|
anchors
|
|
{
|
|
horizontalCenter: parent.right
|
|
verticalCenter: parent.top
|
|
}
|
|
|
|
labelText: activeScriptsList.count
|
|
}
|
|
}
|
|
}
|