diff --git a/.gitignore b/.gitignore
index 5cc60c2f4c..0a66b6eb33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,7 @@ LC_MESSAGES
*.lprof
*~
*.qm
+.directory
.idea
cura.desktop
diff --git a/cura/Machines/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py
index 43b42c55ff..1b20e1188c 100644
--- a/cura/Machines/Models/BaseMaterialsModel.py
+++ b/cura/Machines/Models/BaseMaterialsModel.py
@@ -124,7 +124,7 @@ class BaseMaterialsModel(ListModel):
"description": metadata["description"],
"material": metadata["material"],
"color_name": metadata["color_name"],
- "color_code": metadata["color_code"],
+ "color_code": metadata.get("color_code", ""),
"density": metadata.get("properties", {}).get("density", ""),
"diameter": metadata.get("properties", {}).get("diameter", ""),
"approximate_diameter": metadata["approximate_diameter"],
diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py
index 59c4f4fa5b..a01cc1194f 100644
--- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py
+++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py
@@ -6,10 +6,10 @@ from PyQt5.QtCore import Qt
from UM.Application import Application
from UM.Logger import Logger
from UM.Qt.ListModel import ListModel
+from UM.Settings.SettingFunction import SettingFunction
from cura.Machines.QualityManager import QualityGroup
-
#
# QML Model for all built-in quality profiles. This model is used for the drop-down quality menu.
#
@@ -106,4 +106,8 @@ class QualityProfilesDropDownMenuModel(ListModel):
container = global_stack.definition
if container and container.hasProperty("layer_height", "value"):
layer_height = container.getProperty("layer_height", "value")
+
+ if isinstance(layer_height, SettingFunction):
+ layer_height = layer_height(global_stack)
+
return float(layer_height)
diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py
index cb2776429f..6869d99bc7 100644
--- a/cura/Machines/QualityManager.py
+++ b/cura/Machines/QualityManager.py
@@ -363,8 +363,19 @@ class QualityManager(QObject):
@pyqtSlot(QObject)
def removeQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup"):
Logger.log("i", "Removing quality changes group [%s]", quality_changes_group.name)
+ removed_quality_changes_ids = set()
for node in quality_changes_group.getAllNodes():
- self._container_registry.removeContainer(node.getMetaDataEntry("id"))
+ container_id = node.getMetaDataEntry("id")
+ self._container_registry.removeContainer(container_id)
+ removed_quality_changes_ids.add(container_id)
+
+ # Reset all machines that have activated this quality changes to empty.
+ for global_stack in self._container_registry.findContainerStacks(type = "machine"):
+ if global_stack.qualityChanges.getId() in removed_quality_changes_ids:
+ global_stack.qualityChanges = self._empty_quality_changes_container
+ for extruder_stack in self._container_registry.findContainerStacks(type = "extruder_train"):
+ if extruder_stack.qualityChanges.getId() in removed_quality_changes_ids:
+ extruder_stack.qualityChanges = self._empty_quality_changes_container
#
# Rename a set of quality changes containers. Returns the new name.
diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py
index 16ab22473b..6d55e0643d 100755
--- a/plugins/3MFReader/ThreeMFWorkspaceReader.py
+++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py
@@ -85,14 +85,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
def __init__(self) -> None:
super().__init__()
- MimeTypeDatabase.addMimeType(
- MimeType(
- name="application/x-curaproject+xml",
- comment="Cura Project File",
- suffixes=["curaproject.3mf"]
- )
- )
-
self._supported_extensions = [".3mf"]
self._dialog = WorkspaceDialog()
self._3mf_mesh_reader = None
@@ -726,8 +718,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
nodes = []
base_file_name = os.path.basename(file_name)
- if base_file_name.endswith(".curaproject.3mf"):
- base_file_name = base_file_name[:base_file_name.rfind(".curaproject.3mf")]
self.setWorkspaceName(base_file_name)
return nodes
diff --git a/plugins/3MFReader/__init__.py b/plugins/3MFReader/__init__.py
index 3a4fde4ab8..ce94bbe69c 100644
--- a/plugins/3MFReader/__init__.py
+++ b/plugins/3MFReader/__init__.py
@@ -18,11 +18,7 @@ catalog = i18nCatalog("cura")
def getMetaData() -> Dict:
- # Workaround for osx not supporting double file extensions correctly.
- if Platform.isOSX():
- workspace_extension = "3mf"
- else:
- workspace_extension = "curaproject.3mf"
+ workspace_extension = "3mf"
metaData = {}
if "3MFReader.ThreeMFReader" in sys.modules:
diff --git a/plugins/3MFReader/plugin.json b/plugins/3MFReader/plugin.json
index 5d15123017..5e41975752 100644
--- a/plugins/3MFReader/plugin.json
+++ b/plugins/3MFReader/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides support for reading 3MF files.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/3MFWriter/__init__.py b/plugins/3MFWriter/__init__.py
index e779628f7e..4b8a03888d 100644
--- a/plugins/3MFWriter/__init__.py
+++ b/plugins/3MFWriter/__init__.py
@@ -15,11 +15,7 @@ from UM.Platform import Platform
i18n_catalog = i18nCatalog("uranium")
def getMetaData():
- # Workarround for osx not supporting double file extensions correctly.
- if Platform.isOSX():
- workspace_extension = "3mf"
- else:
- workspace_extension = "curaproject.3mf"
+ workspace_extension = "3mf"
metaData = {}
@@ -36,7 +32,7 @@ def getMetaData():
"output": [{
"extension": workspace_extension,
"description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"),
- "mime_type": "application/x-curaproject+xml",
+ "mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
"mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
}]
}
diff --git a/plugins/3MFWriter/plugin.json b/plugins/3MFWriter/plugin.json
index 22d18b2cf1..9ec4fb0c20 100644
--- a/plugins/3MFWriter/plugin.json
+++ b/plugins/3MFWriter/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides support for writing 3MF files.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/ChangeLogPlugin/plugin.json b/plugins/ChangeLogPlugin/plugin.json
index e9414b9b71..e09a08564a 100644
--- a/plugins/ChangeLogPlugin/plugin.json
+++ b/plugins/ChangeLogPlugin/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Shows changes since latest checked version.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/CuraEngineBackend/plugin.json b/plugins/CuraEngineBackend/plugin.json
index e5df06f228..111698d8d1 100644
--- a/plugins/CuraEngineBackend/plugin.json
+++ b/plugins/CuraEngineBackend/plugin.json
@@ -2,7 +2,7 @@
"name": "CuraEngine Backend",
"author": "Ultimaker B.V.",
"description": "Provides the link to the CuraEngine slicing backend.",
- "api": 4,
+ "api": 5,
"version": "1.0.0",
"i18n-catalog": "cura"
}
diff --git a/plugins/CuraProfileReader/plugin.json b/plugins/CuraProfileReader/plugin.json
index 004a1ade4d..66a2a6a56b 100644
--- a/plugins/CuraProfileReader/plugin.json
+++ b/plugins/CuraProfileReader/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides support for importing Cura profiles.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/CuraProfileWriter/plugin.json b/plugins/CuraProfileWriter/plugin.json
index d9accce770..16c8c34152 100644
--- a/plugins/CuraProfileWriter/plugin.json
+++ b/plugins/CuraProfileWriter/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides support for exporting Cura profiles.",
- "api": 4,
+ "api": 5,
"i18n-catalog":"cura"
}
diff --git a/plugins/FirmwareUpdateChecker/plugin.json b/plugins/FirmwareUpdateChecker/plugin.json
index d6a9f9fbd7..cbbd41e420 100644
--- a/plugins/FirmwareUpdateChecker/plugin.json
+++ b/plugins/FirmwareUpdateChecker/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Checks for firmware updates.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/GCodeGzReader/plugin.json b/plugins/GCodeGzReader/plugin.json
index e9f14724e0..3bd6a4097d 100644
--- a/plugins/GCodeGzReader/plugin.json
+++ b/plugins/GCodeGzReader/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Reads g-code from a compressed archive.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/GCodeGzWriter/plugin.json b/plugins/GCodeGzWriter/plugin.json
index 9774e9a25c..4c6497317b 100644
--- a/plugins/GCodeGzWriter/plugin.json
+++ b/plugins/GCodeGzWriter/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Writes g-code to a compressed archive.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/GCodeProfileReader/plugin.json b/plugins/GCodeProfileReader/plugin.json
index f8f7d4c291..9677628c85 100644
--- a/plugins/GCodeProfileReader/plugin.json
+++ b/plugins/GCodeProfileReader/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides support for importing profiles from g-code files.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/GCodeReader/plugin.json b/plugins/GCodeReader/plugin.json
index f72a8cc12c..75b4d0cd4f 100644
--- a/plugins/GCodeReader/plugin.json
+++ b/plugins/GCodeReader/plugin.json
@@ -3,6 +3,6 @@
"author": "Victor Larchenko",
"version": "1.0.0",
"description": "Allows loading and displaying G-code files.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/GCodeWriter/plugin.json b/plugins/GCodeWriter/plugin.json
index 5fcb1a3bd7..3bbbab8b95 100644
--- a/plugins/GCodeWriter/plugin.json
+++ b/plugins/GCodeWriter/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Writes g-code to a file.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/ImageReader/plugin.json b/plugins/ImageReader/plugin.json
index 2752c6e8f4..08195863e8 100644
--- a/plugins/ImageReader/plugin.json
+++ b/plugins/ImageReader/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Enables ability to generate printable geometry from 2D image files.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/LegacyProfileReader/plugin.json b/plugins/LegacyProfileReader/plugin.json
index 2dc71511a9..179f5444e0 100644
--- a/plugins/LegacyProfileReader/plugin.json
+++ b/plugins/LegacyProfileReader/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides support for importing profiles from legacy Cura versions.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/MachineSettingsAction/plugin.json b/plugins/MachineSettingsAction/plugin.json
index 703a145deb..571658e40a 100644
--- a/plugins/MachineSettingsAction/plugin.json
+++ b/plugins/MachineSettingsAction/plugin.json
@@ -3,6 +3,6 @@
"author": "fieldOfView",
"version": "1.0.0",
"description": "Provides a way to change machine settings (such as build volume, nozzle size, etc.).",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/ModelChecker/plugin.json b/plugins/ModelChecker/plugin.json
index a9190adcaa..3753c0cc88 100644
--- a/plugins/ModelChecker/plugin.json
+++ b/plugins/ModelChecker/plugin.json
@@ -2,7 +2,7 @@
"name": "Model Checker",
"author": "Ultimaker B.V.",
"version": "0.1",
- "api": 4,
+ "api": 5,
"description": "Checks models and print configuration for possible printing issues and give suggestions.",
"i18n-catalog": "cura"
}
diff --git a/plugins/MonitorStage/plugin.json b/plugins/MonitorStage/plugin.json
index cb3f55a80d..88b53840e0 100644
--- a/plugins/MonitorStage/plugin.json
+++ b/plugins/MonitorStage/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides a monitor stage in Cura.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
\ No newline at end of file
diff --git a/plugins/PerObjectSettingsTool/plugin.json b/plugins/PerObjectSettingsTool/plugin.json
index 3254662d33..15fde63387 100644
--- a/plugins/PerObjectSettingsTool/plugin.json
+++ b/plugins/PerObjectSettingsTool/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides the Per Model Settings.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/PostProcessingPlugin/plugin.json b/plugins/PostProcessingPlugin/plugin.json
index ebfef8145a..fea061e93b 100644
--- a/plugins/PostProcessingPlugin/plugin.json
+++ b/plugins/PostProcessingPlugin/plugin.json
@@ -2,7 +2,7 @@
"name": "Post Processing",
"author": "Ultimaker",
"version": "2.2",
- "api": 4,
+ "api": 5,
"description": "Extension that allows for user created scripts for post processing",
"catalog": "cura"
}
\ No newline at end of file
diff --git a/plugins/PrepareStage/plugin.json b/plugins/PrepareStage/plugin.json
index 4fd55e955e..f0464313c7 100644
--- a/plugins/PrepareStage/plugin.json
+++ b/plugins/PrepareStage/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides a prepare stage in Cura.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
\ No newline at end of file
diff --git a/plugins/RemovableDriveOutputDevice/plugin.json b/plugins/RemovableDriveOutputDevice/plugin.json
index df11644256..36bb9ae186 100644
--- a/plugins/RemovableDriveOutputDevice/plugin.json
+++ b/plugins/RemovableDriveOutputDevice/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"description": "Provides removable drive hotplugging and writing support.",
"version": "1.0.0",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/SimulationView/plugin.json b/plugins/SimulationView/plugin.json
index 0e7bec0626..93df98068f 100644
--- a/plugins/SimulationView/plugin.json
+++ b/plugins/SimulationView/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides the Simulation view.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/SliceInfoPlugin/plugin.json b/plugins/SliceInfoPlugin/plugin.json
index d1c643266b..939e5ff235 100644
--- a/plugins/SliceInfoPlugin/plugin.json
+++ b/plugins/SliceInfoPlugin/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Submits anonymous slice info. Can be disabled through preferences.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/SolidView/plugin.json b/plugins/SolidView/plugin.json
index 6d6bda96f0..e70ec224dd 100644
--- a/plugins/SolidView/plugin.json
+++ b/plugins/SolidView/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides a normal solid mesh view.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
\ No newline at end of file
diff --git a/plugins/SupportEraser/plugin.json b/plugins/SupportEraser/plugin.json
index 5ccb639913..7af35e0fb5 100644
--- a/plugins/SupportEraser/plugin.json
+++ b/plugins/SupportEraser/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Creates an eraser mesh to block the printing of support in certain places",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/Toolbox/plugin.json b/plugins/Toolbox/plugin.json
index 12d4042b6b..2557185524 100644
--- a/plugins/Toolbox/plugin.json
+++ b/plugins/Toolbox/plugin.json
@@ -2,6 +2,6 @@
"name": "Toolbox",
"author": "Ultimaker B.V.",
"version": "1.0.0",
- "api": 4,
+ "api": 5,
"description": "Find, manage and install new Cura packages."
}
diff --git a/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml b/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml
index 04b055ed66..90b92bd832 100644
--- a/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxAuthorPage.qml
@@ -82,9 +82,16 @@ Item
}
spacing: Math.floor(UM.Theme.getSize("narrow_margin").height)
width: childrenRect.width
+
Label
{
- text: catalog.i18nc("@label", "Contact") + ":"
+ text: catalog.i18nc("@label", "Website") + ":"
+ font: UM.Theme.getFont("very_small")
+ color: UM.Theme.getColor("text_medium")
+ }
+ Label
+ {
+ text: catalog.i18nc("@label", "Email") + ":"
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text_medium")
}
@@ -100,18 +107,32 @@ Item
topMargin: UM.Theme.getSize("default_margin").height
}
spacing: Math.floor(UM.Theme.getSize("narrow_margin").height)
+
+ Label
+ {
+ text:
+ {
+ if (details.website)
+ {
+ return "" + details.website + ""
+ }
+ return ""
+ }
+ font: UM.Theme.getFont("very_small")
+ color: UM.Theme.getColor("text")
+ linkColor: UM.Theme.getColor("text_link")
+ onLinkActivated: Qt.openUrlExternally(link)
+ }
+
Label
{
text:
{
if (details.email)
{
- return ""+details.name+""
- }
- else
- {
- return ""+details.name+""
+ return "" + details.email + ""
}
+ return ""
}
font: UM.Theme.getFont("very_small")
color: UM.Theme.getColor("text")
diff --git a/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml b/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml
index 1efcde2110..4a008f2a83 100644
--- a/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxCompatibilityChart.qml
@@ -8,7 +8,18 @@ import UM 1.1 as UM
Item
{
+ id: base
+
property var packageData
+ property var technicalDataSheetUrl: {
+ var link = undefined
+ if ("Technical Data Sheet" in packageData.links)
+ {
+ link = packageData.links["Technical Data Sheet"]
+ }
+ return link
+ }
+
anchors.topMargin: UM.Theme.getSize("default_margin").height
height: visible ? childrenRect.height : 0
visible: packageData.type == "material" && packageData.has_configs
@@ -132,4 +143,25 @@ Item
width: Math.floor(table.width * 0.1)
}
}
+
+ Label
+ {
+ id: technical_data_sheet
+ anchors.top: table.bottom
+ anchors.topMargin: UM.Theme.getSize("default_margin").height / 2
+ visible: base.technicalDataSheetUrl !== undefined
+ text:
+ {
+ if (base.technicalDataSheetUrl !== undefined)
+ {
+ return "%2".arg(base.technicalDataSheetUrl).arg("Technical Data Sheet")
+ }
+ return ""
+ }
+ font: UM.Theme.getFont("very_small")
+ color: UM.Theme.getColor("text")
+ linkColor: UM.Theme.getColor("text_link")
+ onLinkActivated: Qt.openUrlExternally(link)
+ }
+
}
diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml
index ebd4c006f8..4366db041c 100644
--- a/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsGridTile.qml
@@ -9,7 +9,7 @@ import UM 1.1 as UM
Item
{
- property int packageCount: (toolbox.viewCategory == "material" && model.type === undefined) ? toolbox.getTotalNumberOfPackagesByAuthor(model.id) : 1
+ property int packageCount: (toolbox.viewCategory == "material" && model.type === undefined) ? toolbox.getTotalNumberOfMaterialPackagesByAuthor(model.id) : 1
property int installedPackages: (toolbox.viewCategory == "material" && model.type === undefined) ? toolbox.getNumberOfInstalledPackagesByAuthor(model.id) : (toolbox.isInstalled(model.id) ? 1 : 0)
height: childrenRect.height
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsPage.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsPage.qml
index 1089fcc51e..bcca02583d 100644
--- a/plugins/Toolbox/resources/qml/ToolboxDownloadsPage.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsPage.qml
@@ -30,7 +30,7 @@ ScrollView
id: allPlugins
width: parent.width
heading: toolbox.viewCategory == "material" ? catalog.i18nc("@label", "Community Contributions") : catalog.i18nc("@label", "Community Plugins")
- model: toolbox.viewCategory == "material" ? toolbox.authorsModel : toolbox.packagesModel
+ model: toolbox.viewCategory == "material" ? toolbox.materialsAvailableModel : toolbox.pluginsAvailableModel
}
ToolboxDownloadsGrid
diff --git a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml
index 15d1ae302c..845bbe8f91 100644
--- a/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml
+++ b/plugins/Toolbox/resources/qml/ToolboxDownloadsShowcaseTile.qml
@@ -9,7 +9,7 @@ import UM 1.1 as UM
Rectangle
{
- property int packageCount: toolbox.viewCategory == "material" ? toolbox.getTotalNumberOfPackagesByAuthor(model.id) : 1
+ property int packageCount: toolbox.viewCategory == "material" ? toolbox.getTotalNumberOfMaterialPackagesByAuthor(model.id) : 1
property int installedPackages: toolbox.viewCategory == "material" ? toolbox.getNumberOfInstalledPackagesByAuthor(model.id) : (toolbox.isInstalled(model.id) ? 1 : 0)
id: tileBase
width: UM.Theme.getSize("toolbox_thumbnail_large").width + (2 * UM.Theme.getSize("default_lining").width)
diff --git a/plugins/Toolbox/src/PackagesModel.py b/plugins/Toolbox/src/PackagesModel.py
index 8b9199b127..7892044d00 100644
--- a/plugins/Toolbox/src/PackagesModel.py
+++ b/plugins/Toolbox/src/PackagesModel.py
@@ -5,9 +5,13 @@ import re
from typing import Dict
from PyQt5.QtCore import Qt, pyqtProperty
+
+from UM.Logger import Logger
from UM.Qt.ListModel import ListModel
+
from .ConfigsModel import ConfigsModel
+
## Model that holds cura packages. By setting the filter property the instances held by this model can be changed.
class PackagesModel(ListModel):
def __init__(self, parent = None):
@@ -34,6 +38,8 @@ class PackagesModel(ListModel):
self.addRoleName(Qt.UserRole + 17, "supported_configs")
self.addRoleName(Qt.UserRole + 18, "download_count")
self.addRoleName(Qt.UserRole + 19, "tags")
+ self.addRoleName(Qt.UserRole + 20, "links")
+ self.addRoleName(Qt.UserRole + 21, "website")
# List of filters for queries. The result is the union of the each list of results.
self._filter = {} # type: Dict[str, str]
@@ -45,10 +51,16 @@ class PackagesModel(ListModel):
def _update(self):
items = []
- for package in self._metadata:
+ if self._metadata is None:
+ Logger.logException("w", "Failed to load packages for Toolbox")
+ self.setItems(items)
+ return
+ for package in self._metadata:
has_configs = False
configs_model = None
+
+ links_dict = {}
if "data" in package:
if "supported_configs" in package["data"]:
if len(package["data"]["supported_configs"]) > 0:
@@ -56,41 +68,48 @@ class PackagesModel(ListModel):
configs_model = ConfigsModel()
configs_model.setConfigs(package["data"]["supported_configs"])
+ # Links is a list of dictionaries with "title" and "url". Convert this list into a dict so it's easier
+ # to process.
+ link_list = package['data']['links'] if 'links' in package['data'] else []
+ links_dict = {d["title"]: d["url"] for d in link_list}
+
if "author_id" not in package["author"] or "display_name" not in package["author"]:
package["author"]["author_id"] = ""
package["author"]["display_name"] = ""
# raise Exception("Detected a package with malformed author data.")
items.append({
- "id": package["package_id"],
- "type": package["package_type"],
- "name": package["display_name"],
- "version": package["package_version"],
- "author_id": package["author"]["author_id"],
- "author_name": package["author"]["display_name"],
- "author_email": package["author"]["email"] if "email" in package["author"] else None,
- "description": package["description"] if "description" in package else None,
- "icon_url": package["icon_url"] if "icon_url" in package else None,
- "image_urls": package["image_urls"] if "image_urls" in package else None,
- "download_url": package["download_url"] if "download_url" in package else None,
- "last_updated": package["last_updated"] if "last_updated" in package else None,
- "is_bundled": package["is_bundled"] if "is_bundled" in package else False,
- "is_active": package["is_active"] if "is_active" in package else False,
- "is_installed": package["is_installed"] if "is_installed" in package else False,
- "has_configs": has_configs,
- "supported_configs": configs_model,
- "download_count": package["download_count"] if "download_count" in package else 0,
- "tags": package["tags"] if "tags" in package else []
+ "id": package["package_id"],
+ "type": package["package_type"],
+ "name": package["display_name"],
+ "version": package["package_version"],
+ "author_id": package["author"]["author_id"],
+ "author_name": package["author"]["display_name"],
+ "author_email": package["author"]["email"] if "email" in package["author"] else None,
+ "description": package["description"] if "description" in package else None,
+ "icon_url": package["icon_url"] if "icon_url" in package else None,
+ "image_urls": package["image_urls"] if "image_urls" in package else None,
+ "download_url": package["download_url"] if "download_url" in package else None,
+ "last_updated": package["last_updated"] if "last_updated" in package else None,
+ "is_bundled": package["is_bundled"] if "is_bundled" in package else False,
+ "is_active": package["is_active"] if "is_active" in package else False,
+ "is_installed": package["is_installed"] if "is_installed" in package else False,
+ "has_configs": has_configs,
+ "supported_configs": configs_model,
+ "download_count": package["download_count"] if "download_count" in package else 0,
+ "tags": package["tags"] if "tags" in package else [],
+ "links": links_dict,
+ "website": package["website"] if "website" in package else None,
})
# Filter on all the key-word arguments.
for key, value in self._filter.items():
if key is "tags":
- key_filter = lambda item, value = value: value in item["tags"]
+ key_filter = lambda item, v = value: v in item["tags"]
elif "*" in value:
- key_filter = lambda candidate, key = key, value = value: self._matchRegExp(candidate, key, value)
+ key_filter = lambda candidate, k = key, v = value: self._matchRegExp(candidate, k, v)
else:
- key_filter = lambda candidate, key = key, value = value: self._matchString(candidate, key, value)
+ key_filter = lambda candidate, k = key, v = value: self._matchString(candidate, k, v)
items = filter(key_filter, items)
# Execute all filters.
diff --git a/plugins/Toolbox/src/Toolbox.py b/plugins/Toolbox/src/Toolbox.py
index c4205b8ed5..00864c6b4e 100644
--- a/plugins/Toolbox/src/Toolbox.py
+++ b/plugins/Toolbox/src/Toolbox.py
@@ -83,7 +83,7 @@ class Toolbox(QObject, Extension):
"plugins_available": PackagesModel(self),
"plugins_installed": PackagesModel(self),
"materials_showcase": AuthorsModel(self),
- "materials_available": PackagesModel(self),
+ "materials_available": AuthorsModel(self),
"materials_installed": PackagesModel(self),
"materials_generic": PackagesModel(self)
} # type: Dict[str, ListModel]
@@ -514,12 +514,14 @@ class Toolbox(QObject, Extension):
count += 1
return count
+ # This slot is only used to get the number of material packages by author, not any other type of packages.
@pyqtSlot(str, result = int)
- def getTotalNumberOfPackagesByAuthor(self, author_id: str) -> int:
+ def getTotalNumberOfMaterialPackagesByAuthor(self, author_id: str) -> int:
count = 0
- for package in self._metadata["materials_available"]:
- if package["author"]["author_id"] == author_id:
- count += 1
+ for package in self._metadata["packages"]:
+ if package["package_type"] == "material":
+ if package["author"]["author_id"] == author_id:
+ count += 1
return count
@pyqtSlot(str, result = bool)
@@ -606,8 +608,21 @@ class Toolbox(QObject, Extension):
self.resetDownload()
return
+ # HACK: These request are not handled independently at this moment, but together from the "packages" call
+ do_not_handle = [
+ "materials_available",
+ "materials_showcase",
+ "plugins_available",
+ "plugins_showcase",
+ ]
+
if reply.operation() == QNetworkAccessManager.GetOperation:
for type, url in self._request_urls.items():
+
+ # HACK: Do nothing because we'll handle these from the "packages" call
+ if type in do_not_handle:
+ return
+
if reply.url() == url:
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200:
try:
@@ -623,25 +638,16 @@ class Toolbox(QObject, Extension):
if not self._models[type]:
Logger.log("e", "Could not find the %s model.", type)
break
-
- # HACK: Eventually get rid of the code from here...
- if type is "plugins_showcase" or type is "materials_showcase":
- self._metadata["plugins_showcase"] = json_data["data"]["plugin"]["packages"]
- self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"])
- self._metadata["materials_showcase"] = json_data["data"]["material"]["authors"]
- self._models["materials_showcase"].setMetadata(self._metadata["materials_showcase"])
- else:
- # ...until here.
- # This hack arises for multiple reasons but the main
- # one is because there are not separate API calls
- # for different kinds of showcases.
- self._metadata[type] = json_data["data"]
- self._models[type].setMetadata(self._metadata[type])
+
+ self._metadata[type] = json_data["data"]
+ self._models[type].setMetadata(self._metadata[type])
# Do some auto filtering
# TODO: Make multiple API calls in the future to handle this
if type is "packages":
self._models[type].setFilter({"type": "plugin"})
+ self.buildMaterialsModels()
+ self.buildPluginsModels()
if type is "authors":
self._models[type].setFilter({"package_types": "material"})
if type is "materials_generic":
@@ -755,6 +761,10 @@ class Toolbox(QObject, Extension):
def pluginsShowcaseModel(self) -> PackagesModel:
return cast(PackagesModel, self._models["plugins_showcase"])
+ @pyqtProperty(QObject, notify = metadataChanged)
+ def pluginsAvailableModel(self) -> PackagesModel:
+ return cast(PackagesModel, self._models["plugins_available"])
+
@pyqtProperty(QObject, notify = metadataChanged)
def pluginsInstalledModel(self) -> PackagesModel:
return cast(PackagesModel, self._models["plugins_installed"])
@@ -763,6 +773,10 @@ class Toolbox(QObject, Extension):
def materialsShowcaseModel(self) -> AuthorsModel:
return cast(AuthorsModel, self._models["materials_showcase"])
+ @pyqtProperty(QObject, notify = metadataChanged)
+ def materialsAvailableModel(self) -> AuthorsModel:
+ return cast(AuthorsModel, self._models["materials_available"])
+
@pyqtProperty(QObject, notify = metadataChanged)
def materialsInstalledModel(self) -> PackagesModel:
return cast(PackagesModel, self._models["materials_installed"])
@@ -798,3 +812,46 @@ class Toolbox(QObject, Extension):
return
self._models[model_type].setFilter({})
self.filterChanged.emit()
+
+
+ # HACK(S):
+ # --------------------------------------------------------------------------
+ def buildMaterialsModels(self) -> None:
+
+ self._metadata["materials_showcase"] = []
+ self._metadata["materials_available"] = []
+
+ processed_authors = [] # type: List[str]
+
+ for item in self._metadata["packages"]:
+ if item["package_type"] == "material":
+
+ author = item["author"]
+ if author["author_id"] in processed_authors:
+ continue
+
+ if "showcase" in item["tags"]:
+ self._metadata["materials_showcase"].append(author)
+ else:
+ self._metadata["materials_available"].append(author)
+
+ processed_authors.append(author["author_id"])
+
+ self._models["materials_showcase"].setMetadata(self._metadata["materials_showcase"])
+ self._models["materials_available"].setMetadata(self._metadata["materials_available"])
+
+ def buildPluginsModels(self) -> None:
+
+ self._metadata["plugins_showcase"] = []
+ self._metadata["plugins_available"] = []
+
+ for item in self._metadata["packages"]:
+ if item["package_type"] == "plugin":
+
+ if "showcase" in item["tags"]:
+ self._metadata["plugins_showcase"].append(item)
+ else:
+ self._metadata["plugins_available"].append(item)
+
+ self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"])
+ self._models["plugins_available"].setMetadata(self._metadata["plugins_available"])
diff --git a/plugins/UFPWriter/UFPWriter.py b/plugins/UFPWriter/UFPWriter.py
index ceb9d79087..a85ee489cb 100644
--- a/plugins/UFPWriter/UFPWriter.py
+++ b/plugins/UFPWriter/UFPWriter.py
@@ -13,6 +13,7 @@ from UM.PluginRegistry import PluginRegistry #To get the g-code writer.
from PyQt5.QtCore import QBuffer
from cura.Snapshot import Snapshot
+from cura.Utils.Threading import call_on_qt_thread
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@@ -29,6 +30,11 @@ class UFPWriter(MeshWriter):
Logger.log("d", "Creating thumbnail image...")
self._snapshot = Snapshot.snapshot(width = 300, height = 300)
+ # This needs to be called on the main thread (Qt thread) because the serialization of material containers can
+ # trigger loading other containers. Because those loaded containers are QtObjects, they must be created on the
+ # Qt thread. The File read/write operations right now are executed on separated threads because they are scheduled
+ # by the Job class.
+ @call_on_qt_thread
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode):
archive = VirtualFile()
archive.openStream(stream, "application/x-ufp", OpenMode.WriteOnly)
@@ -60,5 +66,50 @@ class UFPWriter(MeshWriter):
else:
Logger.log("d", "Thumbnail not created, cannot save it")
+ # Store the material.
+ application = Application.getInstance()
+ machine_manager = application.getMachineManager()
+ material_manager = application.getMaterialManager()
+ global_stack = machine_manager.activeMachine
+
+ material_extension = "xml.fdm_material"
+ material_mime_type = "application/x-ultimaker-material-profile"
+
+ try:
+ archive.addContentType(extension = material_extension, mime_type = material_mime_type)
+ except:
+ Logger.log("w", "The material extension: %s was already added", material_extension)
+
+ added_materials = []
+ for extruder_stack in global_stack.extruders.values():
+ material = extruder_stack.material
+ material_file_name = material.getMetaData()["base_file"] + ".xml.fdm_material"
+ material_file_name = "/Materials/" + material_file_name
+
+ #Same material cannot be added
+ if material_file_name in added_materials:
+ continue
+
+ material_root_id = material.getMetaDataEntry("base_file")
+ material_group = material_manager.getMaterialGroup(material_root_id)
+ if material_group is None:
+ Logger.log("e", "Cannot find material container with root id [%s]", material_root_id)
+ return False
+
+ material_container = material_group.root_material_node.getContainer()
+ try:
+ serialized_material = material_container.serialize()
+ except NotImplementedError:
+ Logger.log("e", "Unable serialize material container with root id: %s", material_root_id)
+ return False
+
+ material_file = archive.getStream(material_file_name)
+ material_file.write(serialized_material.encode("UTF-8"))
+ archive.addRelation(virtual_path = material_file_name,
+ relation_type = "http://schemas.ultimaker.org/package/2018/relationships/material",
+ origin = "/3D/model.gcode")
+
+ added_materials.append(material_file_name)
+
archive.close()
return True
diff --git a/plugins/UFPWriter/plugin.json b/plugins/UFPWriter/plugin.json
index 7d10b89ad4..ab590353e0 100644
--- a/plugins/UFPWriter/plugin.json
+++ b/plugins/UFPWriter/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides support for writing Ultimaker Format Packages.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
\ No newline at end of file
diff --git a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml
index 127b3c35bd..b5b80a3010 100644
--- a/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml
+++ b/plugins/UM3NetworkPrinting/DiscoverUM3Action.qml
@@ -364,7 +364,6 @@ Cura.MachineAction
{
id: addressField
width: parent.width
- maximumLength: 40
validator: RegExpValidator
{
regExp: /[a-zA-Z0-9\.\-\_]*/
diff --git a/plugins/UM3NetworkPrinting/plugin.json b/plugins/UM3NetworkPrinting/plugin.json
index e7b59fadd6..d415338374 100644
--- a/plugins/UM3NetworkPrinting/plugin.json
+++ b/plugins/UM3NetworkPrinting/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"description": "Manages network connections to Ultimaker 3 printers.",
"version": "1.0.0",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py
index 45b566fcab..4ceda52875 100644
--- a/plugins/USBPrinting/USBPrinterOutputDevice.py
+++ b/plugins/USBPrinting/USBPrinterOutputDevice.py
@@ -326,7 +326,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
if self._firmware_name is None:
self.sendCommand("M115")
- if (b"ok " in line and b"T:" in line) or b"ok T:" in line or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed
+ if (b"ok " in line and b"T:" in line) or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed
extruder_temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line)
# Update all temperature values
matched_extruder_nrs = []
diff --git a/plugins/USBPrinting/plugin.json b/plugins/USBPrinting/plugin.json
index 27e07c45b2..3484c8a48a 100644
--- a/plugins/USBPrinting/plugin.json
+++ b/plugins/USBPrinting/plugin.json
@@ -2,7 +2,7 @@
"name": "USB printing",
"author": "Ultimaker B.V.",
"version": "1.0.0",
- "api": 4,
+ "api": 5,
"description": "Accepts G-Code and sends them to a printer. Plugin can also update firmware.",
"i18n-catalog": "cura"
}
diff --git a/plugins/UltimakerMachineActions/plugin.json b/plugins/UltimakerMachineActions/plugin.json
index 57b3e6bc8f..b60c7df88e 100644
--- a/plugins/UltimakerMachineActions/plugin.json
+++ b/plugins/UltimakerMachineActions/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc.).",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/UserAgreement/plugin.json b/plugins/UserAgreement/plugin.json
index b10abc5640..50a2aa0441 100644
--- a/plugins/UserAgreement/plugin.json
+++ b/plugins/UserAgreement/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Ask the user once if he/she agrees with our license.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json b/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json
index 79115f931e..463fcdc941 100644
--- a/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 2.1 to Cura 2.2.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json b/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json
index d213042ad2..e7a0b1c559 100644
--- a/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 2.2 to Cura 2.4.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json b/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json
index 759b6368fd..3029539887 100644
--- a/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 2.5 to Cura 2.6.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json b/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json
index 3c3d7fff8c..225da67235 100644
--- a/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 2.6 to Cura 2.7.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json b/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json
index 3df84ff7e6..9a139851ec 100644
--- a/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade27to30/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 2.7 to Cura 3.0.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json b/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json
index d80b820976..cf42b3f6cd 100644
--- a/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 3.0 to Cura 3.1.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json b/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json
index fbce09c807..f9cc968dae 100644
--- a/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 3.2 to Cura 3.3.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json b/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json
index 164b79d504..f5ba7235d1 100644
--- a/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 3.3 to Cura 3.4.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/VersionUpgrade/VersionUpgrade34to40/plugin.json b/plugins/VersionUpgrade/VersionUpgrade34to40/plugin.json
index 1059ca3e57..c07ae31c0a 100644
--- a/plugins/VersionUpgrade/VersionUpgrade34to40/plugin.json
+++ b/plugins/VersionUpgrade/VersionUpgrade34to40/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Upgrades configurations from Cura 3.4 to Cura 4.0.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/X3DReader/plugin.json b/plugins/X3DReader/plugin.json
index f18c7f033d..9ee09e43df 100644
--- a/plugins/X3DReader/plugin.json
+++ b/plugins/X3DReader/plugin.json
@@ -3,6 +3,6 @@
"author": "Seva Alekseyev",
"version": "0.5.0",
"description": "Provides support for reading X3D files.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/XRayView/plugin.json b/plugins/XRayView/plugin.json
index 4e89690c13..576dec4656 100644
--- a/plugins/XRayView/plugin.json
+++ b/plugins/XRayView/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides the X-Ray view.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/plugins/XmlMaterialProfile/plugin.json b/plugins/XmlMaterialProfile/plugin.json
index 17056dcb3e..4b2901c375 100644
--- a/plugins/XmlMaterialProfile/plugin.json
+++ b/plugins/XmlMaterialProfile/plugin.json
@@ -3,6 +3,6 @@
"author": "Ultimaker B.V.",
"version": "1.0.0",
"description": "Provides capabilities to read and write XML-based material profiles.",
- "api": 4,
+ "api": 5,
"i18n-catalog": "cura"
}
diff --git a/resources/definitions/bq_hephestos_2.def.json b/resources/definitions/bq_hephestos_2.def.json
index ca0e66ada2..90a86433fb 100644
--- a/resources/definitions/bq_hephestos_2.def.json
+++ b/resources/definitions/bq_hephestos_2.def.json
@@ -17,8 +17,8 @@
"overrides": {
"machine_name": { "default_value": "BQ Hephestos 2" },
- "machine_start_gcode": { "default_value": "; -- START GCODE --\nM104 S{material_print_temperature} ; Heat up extruder while leveling\nM800 ; Custom GCODE to fire start print procedure\nM109 S{material_print_temperature} ; Makes sure the temperature is correct before printing\n; -- end of START GCODE --" },
- "machine_end_gcode": { "default_value": "; -- END GCODE --\nM801 ; Custom GCODE to fire end print procedure\n; -- end of END GCODE --" },
+ "machine_start_gcode": { "default_value": "; -- START GCODE --\nM104 S{material_print_temperature}\nG28 ; Zero-ing position\nG29 ; Auto bed-leveling\nG0 X4 Y297 Z15 F4000 ; Fast move to BQ's start position\nG90 ; Set to Absolute Positioning\nG92 E0 ; Reset extruder 0\nG1 F1800 ; Set default feedrate\nM109 S{material_print_temperature} ; Makes sure the temperature is correct before printing\n; -- end of START GCODE --" },
+ "machine_end_gcode": { "default_value": "; -- END GCODE --\nM801 ; Marlin G-CODE to fire end print procedure\n; -- end of END GCODE --" },
"machine_width": { "default_value": 210 },
"machine_depth": { "default_value": 297 },
"machine_height": { "default_value": 220 },
diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json
index 3eb7cb1c32..a85a251ac2 100644
--- a/resources/definitions/fdmprinter.def.json
+++ b/resources/definitions/fdmprinter.def.json
@@ -1819,9 +1819,9 @@
"unit": "mm",
"type": "float",
"default_value": 0.1,
- "minimum_value": "resolveOrValue('layer_height')",
+ "minimum_value": "resolveOrValue('layer_height') if infill_line_distance > 0 else -999999",
"maximum_value_warning": "0.75 * machine_nozzle_size",
- "maximum_value": "resolveOrValue('layer_height') * (1.45 if spaghetti_infill_enabled else 8)",
+ "maximum_value": "resolveOrValue('layer_height') * (1.45 if spaghetti_infill_enabled else 8) if infill_line_distance > 0 else 999999",
"value": "resolveOrValue('layer_height')",
"enabled": "infill_sparse_density > 0 and not spaghetti_infill_enabled",
"limit_to_extruder": "infill_extruder_nr",
@@ -3875,6 +3875,19 @@
}
}
},
+ "support_infill_angle":
+ {
+ "label": "Support Infill Line Direction",
+ "description": "Orientation of the infill pattern for supports. The support infill pattern is rotated in the horizontal plane.",
+ "unit": "°",
+ "type": "float",
+ "minimum_value": "-180",
+ "maximum_value": "180",
+ "default_value": 0,
+ "enabled": "support_enable and support_pattern != 'concentric' and support_infill_rate > 0",
+ "settable_per_mesh": false,
+ "settable_per_extruder": true
+ },
"support_z_distance":
{
"label": "Support Z Distance",
diff --git a/resources/definitions/peopoly_moai.def.json b/resources/definitions/peopoly_moai.def.json
index 5c03444d49..a578cc4240 100644
--- a/resources/definitions/peopoly_moai.def.json
+++ b/resources/definitions/peopoly_moai.def.json
@@ -4,13 +4,14 @@
"inherits": "fdmprinter",
"metadata": {
"visible": true,
- "author": "fieldOfView",
+ "author": "Peopoly",
"manufacturer": "Peopoly",
"file_formats": "text/x-gcode",
"has_machine_quality": true,
"has_materials": false,
- "machine_extruder_trains":
- {
+ "platform": "moai.obj",
+ "platform_texture": "moai.jpg",
+ "machine_extruder_trains": {
"0": "peopoly_moai_extruder_0"
}
},
@@ -46,7 +47,6 @@
"machine_end_gcode": {
"default_value": "M104 S0\nM140 S0\nG28 X0 Y0\nM84"
},
-
"line_width": {
"minimum_value_warning": "machine_nozzle_size"
},
@@ -75,7 +75,14 @@
"value": "0.1"
},
"top_bottom_thickness": {
- "minimum_value_warning": "0.1"
+ "minimum_value_warning": "0.1",
+ "value": "0.1"
+ },
+ "top_thickness": {
+ "minimum_value_warning": "resolveOrValue('layer_height')"
+ },
+ "bottom_thickness": {
+ "minimum_value_warning": "resolveOrValue('layer_height')"
},
"infill_sparse_thickness": {
"maximum_value_warning": "0.5"
@@ -102,24 +109,23 @@
"value": "speed_print"
},
"speed_travel": {
- "value": "300"
+ "value": 150
},
"speed_travel_layer_0": {
- "value": "300"
+ "value": 150
},
"speed_layer_0": {
- "value": "5"
+ "value": 5
},
"speed_slowdown_layers": {
- "value": "2"
+ "value": 3
},
"infill_overlap": {
- "value": "15"
+ "value": 15
},
"adhesion_type": {
- "value": "\"none\""
+ "value": "'none'"
},
-
"acceleration_enabled": {
"value": "False"
},
@@ -139,6 +145,10 @@
"enabled": false,
"value": "False"
},
+ "cool_fan_speed_min": {
+ "enabled": false,
+ "value": 0
+ },
"retraction_enable": {
"enabled": false,
"value": "False"
@@ -148,7 +158,8 @@
"value": "'off'"
},
"retract_at_layer_change": {
- "enabled": false
+ "enabled": false,
+ "value": false
},
"cool_min_layer_time_fan_speed_max": {
"enabled": false
@@ -158,6 +169,117 @@
},
"cool_fan_full_layer": {
"enabled": false
+ },
+ "minimum_polygon_circumference": {
+ "value": "0.1"
+ },
+ "meshfix_maximum_resolution": {
+ "value": "0.005"
+ },
+ "skin_outline_count": {
+ "value": 0
+ },
+ "travel_compensate_overlapping_walls_enabled": {
+ "value": "False"
+ },
+ "travel_compensate_overlapping_walls_0_enabled": {
+ "value": "False"
+ },
+ "travel_compensate_overlapping_walls_x_enabled": {
+ "value": "False"
+ },
+ "wall_0_wipe_dist": {
+ "value": "machine_nozzle_size / 3"
+ },
+ "wall_thickness": {
+ "value": 0.5
+ },
+ "infill_sparse_density": {
+ "value": 70
+ },
+ "infill_pattern": {
+ "value": "'lines'"
+ },
+ "infill_angles": {
+ "value": "[0,90]"
+ },
+ "cool_min_layer_time": {
+ "enabled": false,
+ "value": 0
+ },
+ "cool_min_speed": {
+ "enabled": false,
+ "value": 0
+ },
+ "cool_lift_head": {
+ "enabled": false,
+ "value": "False"
+ },
+ "material_flow": {
+ "enabled": false
+ },
+ "material_flow_layer_0": {
+ "enabled": false
+ },
+ "speed_equalize_flow_enabled": {
+ "enabled": false,
+ "value": "False"
+ },
+ "draft_shield_enabled": {
+ "enabled": false,
+ "value": "False"
+ },
+ "z_seam_corner": {
+ "value": "'z_seam_corner_none'"
+ },
+ "z_seam_type": {
+ "value": "'shortest'"
+ },
+ "skin_no_small_gaps_heuristic": {
+ "value": "False"
+ },
+ "ironing_enabled": {
+ "enabled": false,
+ "value": "False"
+ },
+ "skin_overlap": {
+ "value": 5
+ },
+ "infill_wipe_dist": {
+ "value": 0
+ },
+ "expand_skins_expand_distance": {
+ "value": "( wall_line_width_0 + (wall_line_count - 1) * wall_line_width_x ) / 2"
+ },
+ "max_feedrate_z_override": {
+ "value": 0,
+ "enabled": false
+ },
+ "flow_rate_max_extrusion_offset": {
+ "enabled": false
+ },
+ "flow_rate_extrusion_offset_factor": {
+ "enabled": false
+ },
+ "adaptive_layer_height_enabled": {
+ "value": "False",
+ "enabled": false
+ },
+ "bridge_settings_enabled": {
+ "value": "False",
+ "enabled": false
+ },
+ "acceleration_enabled": {
+ "value": "False",
+ "enabled": false
+ },
+ "relative_extrusion": {
+ "value": "False",
+ "enabled": false
+ },
+ "coasting_enable": {
+ "value": "False",
+ "enabled": false
}
}
}
diff --git a/resources/extruders/peopoly_moai_extruder_0.def.json b/resources/extruders/peopoly_moai_extruder_0.def.json
index 7940002926..bbffd4ac4d 100644
--- a/resources/extruders/peopoly_moai_extruder_0.def.json
+++ b/resources/extruders/peopoly_moai_extruder_0.def.json
@@ -11,6 +11,9 @@
"overrides": {
"extruder_nr": { "default_value": 0 },
"machine_nozzle_size": { "default_value": 0.067 },
- "material_diameter": { "default_value": 1.75 }
+ "material_diameter": {
+ "enabled": false,
+ "default_value": 1.75
+ }
}
}
diff --git a/resources/images/moai.jpg b/resources/images/moai.jpg
new file mode 100644
index 0000000000..54c6c7561e
Binary files /dev/null and b/resources/images/moai.jpg differ
diff --git a/resources/meshes/moai.obj b/resources/meshes/moai.obj
new file mode 100644
index 0000000000..f13f30d6f4
--- /dev/null
+++ b/resources/meshes/moai.obj
@@ -0,0 +1,32 @@
+# OBJ written from C:\Users\Flo\Desktop\Cura_FILES\moai.obj
+mtllib moai.mtl
+# Units millimeters
+
+g Mesh
+v 65 -65 0
+v -65 -65 0
+v -65 65 0
+v 65 65 0
+v 65 -65 0
+v -65 -65 0
+v -65 65 0
+v 65 65 0
+v -65 65 18.8383
+v 65 65 18.8383
+vn 0 0 1
+vn 1 0 0
+vn -1 0 0
+vt 0.0975501 1
+vt 1 1
+vt 1 0.0977239
+vt 0.0975501 0.0977239
+vt 0.0186426 0.870052
+vt 0.0736426 0.870052
+vt 0.0186426 0.815052
+vt 0.0214764 0.912057
+vt 0.0764764 0.967057
+vt 0.0214764 0.967057
+usemtl red
+f 1/1/1 4/2/1 3/3/1 2/4/1
+f 7/5/2 9/6/2 6/7/2
+f 5/8/3 10/9/3 8/10/3
diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml
index 21e6eebf58..db230ebca7 100644
--- a/resources/qml/Actions.qml
+++ b/resources/qml/Actions.qml
@@ -110,28 +110,28 @@ Item
Action
{
id: view3DCameraAction;
- text: catalog.i18nc("@action:inmenu menubar:view","&3D View");
+ text: catalog.i18nc("@action:inmenu menubar:view","3D View");
onTriggered: UM.Controller.rotateView("3d", 0);
}
Action
{
id: viewFrontCameraAction;
- text: catalog.i18nc("@action:inmenu menubar:view","&Front View");
+ text: catalog.i18nc("@action:inmenu menubar:view","Front View");
onTriggered: UM.Controller.rotateView("home", 0);
}
Action
{
id: viewTopCameraAction;
- text: catalog.i18nc("@action:inmenu menubar:view","&Top View");
+ text: catalog.i18nc("@action:inmenu menubar:view","Top View");
onTriggered: UM.Controller.rotateView("y", 90);
}
Action
{
id: viewLeftSideCameraAction;
- text: catalog.i18nc("@action:inmenu menubar:view","&Left Side View");
+ text: catalog.i18nc("@action:inmenu menubar:view","Left Side View");
onTriggered: UM.Controller.rotateView("x", 90);
}
@@ -229,23 +229,13 @@ Item
Action
{
id: deleteSelectionAction;
- text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete &Selected Model", "Delete &Selected Models", UM.Selection.selectionCount);
+ text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete Selected Model", "Delete Selected Models", UM.Selection.selectionCount);
enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection;
iconName: "edit-delete";
shortcut: StandardKey.Delete;
onTriggered: CuraActions.deleteSelection();
}
- Action //Also add backspace as the same function as delete because on Macintosh keyboards the button called "delete" is actually a backspace, and the user expects it to function as a delete.
- {
- id: backspaceSelectionAction
- text: catalog.i18ncp("@action:inmenu menubar:edit", "Delete &Selected Model", "Delete &Selected Models", UM.Selection.selectionCount)
- enabled: UM.Controller.toolsEnabled && UM.Selection.hasSelection
- iconName: "edit-delete"
- shortcut: StandardKey.Backspace
- onTriggered: CuraActions.deleteSelection()
- }
-
Action
{
id: centerSelectionAction;
@@ -328,7 +318,7 @@ Item
Action
{
id: selectAllAction;
- text: catalog.i18nc("@action:inmenu menubar:edit","&Select All Models");
+ text: catalog.i18nc("@action:inmenu menubar:edit","Select All Models");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-select-all";
shortcut: "Ctrl+A";
@@ -338,7 +328,7 @@ Item
Action
{
id: deleteAllAction;
- text: catalog.i18nc("@action:inmenu menubar:edit","&Clear Build Plate");
+ text: catalog.i18nc("@action:inmenu menubar:edit","Clear Build Plate");
enabled: UM.Controller.toolsEnabled;
iconName: "edit-delete";
shortcut: "Ctrl+D";
@@ -348,7 +338,7 @@ Item
Action
{
id: reloadAllAction;
- text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Models");
+ text: catalog.i18nc("@action:inmenu menubar:file","Reload All Models");
iconName: "document-revert";
shortcut: "F5"
onTriggered: CuraApplication.reloadAll();
diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml
index cd8a122bd2..97742de57a 100644
--- a/resources/qml/Cura.qml
+++ b/resources/qml/Cura.qml
@@ -120,7 +120,7 @@ UM.MainWindow
text: catalog.i18nc("@title:menu menubar:file","&Save...")
onTriggered:
{
- var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/x-curaproject+xml" };
+ var args = { "filter_by_machine": false, "file_type": "workspace", "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml" };
if(UM.Preferences.getValue("cura/dialog_on_project_save"))
{
saveWorkspaceDialog.args = args;
diff --git a/resources/qml/Menus/MaterialMenu.qml b/resources/qml/Menus/MaterialMenu.qml
index 186c5d1d2a..f9e343d2dd 100644
--- a/resources/qml/Menus/MaterialMenu.qml
+++ b/resources/qml/Menus/MaterialMenu.qml
@@ -10,7 +10,7 @@ import Cura 1.0 as Cura
Menu
{
id: menu
- title: "Material"
+ title: catalog.i18nc("@label:category menu label", "Material")
property int extruderIndex: 0
@@ -32,6 +32,12 @@ Menu
extruderPosition: menu.extruderIndex
}
+ MenuItem
+ {
+ text: catalog.i18nc("@label:category menu label", "Favorites")
+ enabled: false
+ visible: favoriteMaterialsModel.items.length > 0
+ }
Instantiator
{
model: favoriteMaterialsModel
@@ -52,7 +58,7 @@ Menu
Menu
{
id: genericMenu
- title: "Generic"
+ title: catalog.i18nc("@label:category menu label", "Generic")
Instantiator
{
diff --git a/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg
new file mode 100644
index 0000000000..ac4f9ee81d
--- /dev/null
+++ b/resources/quality/peopoly_moai/peopoly_moai_coarse.inst.cfg
@@ -0,0 +1,17 @@
+[general]
+version = 4
+name = Coarse
+definition = peopoly_moai
+
+[metadata]
+setting_version = 5
+type = quality
+quality_type = coarse
+weight = 3
+
+[values]
+layer_height = 0.08
+speed_print = 90
+speed_travel = 120
+speed_travel_layer_0 = 100
+speed_wall = 90
diff --git a/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg
new file mode 100644
index 0000000000..2d21b1f7e0
--- /dev/null
+++ b/resources/quality/peopoly_moai/peopoly_moai_draft.inst.cfg
@@ -0,0 +1,18 @@
+[general]
+version = 4
+name = Draft
+definition = peopoly_moai
+
+[metadata]
+setting_version = 5
+type = quality
+quality_type = draft
+weight = 4
+
+[values]
+layer_height = 0.1
+speed_print = 85
+speed_travel = 120
+speed_travel_layer_0 = 100
+speed_wall = 85
+speed_slowdown_layers = 2
diff --git a/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg
new file mode 100644
index 0000000000..796c2cff3c
--- /dev/null
+++ b/resources/quality/peopoly_moai/peopoly_moai_extra_high.inst.cfg
@@ -0,0 +1,18 @@
+[general]
+version = 4
+name = Extra High
+definition = peopoly_moai
+
+[metadata]
+setting_version = 5
+type = quality
+quality_type = extra_high
+weight = 0
+
+[values]
+layer_height = 0.02
+speed_print = 185
+speed_travel = 185
+speed_travel_layer_0 = 100
+speed_wall = 185
+speed_slowdown_layers = 5
diff --git a/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg
index 36b5f21ff8..b36163d9f1 100644
--- a/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg
+++ b/resources/quality/peopoly_moai/peopoly_moai_high.inst.cfg
@@ -1,6 +1,6 @@
[general]
version = 4
-name = Extra Fine
+name = High
definition = peopoly_moai
[metadata]
@@ -10,8 +10,9 @@ quality_type = high
weight = 1
[values]
-infill_sparse_density = 70
-layer_height = 0.05
-top_bottom_thickness = 0.4
-wall_thickness = 0.4
-speed_print = 150
+layer_height = 0.04
+speed_print = 140
+speed_travel = 140
+speed_travel_layer_0 = 100
+speed_wall = 140
+speed_slowdown_layers = 4
diff --git a/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg
deleted file mode 100644
index 48ffd07f33..0000000000
--- a/resources/quality/peopoly_moai/peopoly_moai_max.inst.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
-[general]
-version = 4
-name = Maximum Quality
-definition = peopoly_moai
-
-[metadata]
-setting_version = 5
-type = quality
-quality_type = extra_high
-weight = 2
-
-[values]
-infill_sparse_density = 70
-layer_height = 0.025
-top_bottom_thickness = 0.4
-wall_thickness = 0.4
-speed_print = 200
diff --git a/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg b/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg
index f5fe799ac3..cf67591ab2 100644
--- a/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg
+++ b/resources/quality/peopoly_moai/peopoly_moai_normal.inst.cfg
@@ -1,17 +1,17 @@
[general]
version = 4
-name = Fine
+name = Normal
definition = peopoly_moai
[metadata]
setting_version = 5
type = quality
quality_type = normal
-weight = 0
+weight = 2
[values]
-infill_sparse_density = 70
-layer_height = 0.1
-top_bottom_thickness = 0.4
-wall_thickness = 0.4
-speed_print = 100
+layer_height = 0.06
+speed_print = 120
+speed_travel = 120
+speed_travel_layer_0 = 100
+speed_wall = 120
diff --git a/resources/variants/ultimaker2_plus_0.4.inst.cfg b/resources/variants/ultimaker2_plus_0.4.inst.cfg
index 544728f8a4..d9d982ef11 100644
--- a/resources/variants/ultimaker2_plus_0.4.inst.cfg
+++ b/resources/variants/ultimaker2_plus_0.4.inst.cfg
@@ -12,5 +12,5 @@ hardware_type = nozzle
machine_nozzle_size = 0.4
machine_nozzle_tip_outer_diameter = 1.05
speed_wall = =round(speed_print / 1.25, 1)
-speed_wall_0 = =1 if speed_wall < 10 else (speed_wall - 10)
+speed_wall_0 = =min(speed_wall - 10, 1)
speed_topbottom = =round(speed_print / 2.25, 1)