Merge branch 'Ultimaker:main' into master

This commit is contained in:
3d-hctech 2022-06-09 15:09:40 +08:00 committed by GitHub
commit 9437de8266
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
228 changed files with 1123 additions and 996 deletions

View File

@ -1,6 +1,6 @@
name: Bug Report name: Bug Report
description: Create a report to help us fix issues. description: Create a report to help us fix issues.
labels: "Type: Bug" labels: ["Type: Bug", "Status: Triage"]
body: body:
- type: markdown - type: markdown
attributes: attributes:
@ -14,7 +14,7 @@ body:
attributes: attributes:
label: Application Version label: Application Version
description: The version of Cura this issue occurs with. description: The version of Cura this issue occurs with.
placeholder: 4.9.0 placeholder: 5.0.0
validations: validations:
required: true required: true
- type: input - type: input

1
.gitignore vendored
View File

@ -65,6 +65,7 @@ plugins/CuraRemoteSupport
plugins/ModelCutter plugins/ModelCutter
plugins/PrintProfileCreator plugins/PrintProfileCreator
plugins/MultiPrintPlugin plugins/MultiPrintPlugin
plugins/CuraOrientationPlugin
#Build stuff #Build stuff
CMakeCache.txt CMakeCache.txt

View File

@ -25,9 +25,10 @@
</description> </description>
<screenshots> <screenshots>
<screenshot type="default"> <screenshot type="default">
<image>https://raw.githubusercontent.com/Ultimaker/Cura/master/screenshot.png</image> <image>https://raw.githubusercontent.com/Ultimaker/Cura/main/cura-logo.PNG</image>
</screenshot> </screenshot>
</screenshots> </screenshots>
<url type="homepage">https://ultimaker.com/software/ultimaker-cura?utm_source=cura&amp;utm_medium=software&amp;utm_campaign=cura-update-linux</url> <url type="homepage">https://ultimaker.com/software/ultimaker-cura?utm_source=cura&amp;utm_medium=software&amp;utm_campaign=cura-update-linux</url>
<translation type="gettext">Cura</translation> <translation type="gettext">Cura</translation>
<content_rating type="oars-1.1" />
</component> </component>

View File

@ -261,7 +261,7 @@ class CrashHandler:
opengl_instance = OpenGL.getInstance() opengl_instance = OpenGL.getInstance()
if not opengl_instance: if not opengl_instance:
self.data["opengl"] = {"version": "n/a", "vendor": "n/a", "type": "n/a"} self.data["opengl"] = {"version": "n/a", "vendor": "n/a", "type": "n/a"}
return catalog.i18nc("@label", "Not yet initialized<br/>") return catalog.i18nc("@label", "Not yet initialized") + "<br />"
info = "<ul>" info = "<ul>"
info += catalog.i18nc("@label OpenGL version", "<li>OpenGL Version: {version}</li>").format(version = opengl_instance.getOpenGLVersion()) info += catalog.i18nc("@label OpenGL version", "<li>OpenGL Version: {version}</li>").format(version = opengl_instance.getOpenGLVersion())
@ -291,6 +291,7 @@ class CrashHandler:
if with_sentry_sdk: if with_sentry_sdk:
with configure_scope() as scope: with configure_scope() as scope:
scope.set_tag("opengl_version", opengl_instance.getOpenGLVersion()) scope.set_tag("opengl_version", opengl_instance.getOpenGLVersion())
scope.set_tag("opengl_version_short", opengl_instance.getOpenGLVersionShort())
scope.set_tag("gpu_vendor", opengl_instance.getGPUVendorName()) scope.set_tag("gpu_vendor", opengl_instance.getGPUVendorName())
scope.set_tag("gpu_type", opengl_instance.getGPUType()) scope.set_tag("gpu_type", opengl_instance.getGPUType())
scope.set_tag("active_machine", active_machine_definition_id) scope.set_tag("active_machine", active_machine_definition_id)

View File

@ -257,6 +257,7 @@ class CuraApplication(QtApplication):
from UM.CentralFileStorage import CentralFileStorage from UM.CentralFileStorage import CentralFileStorage
CentralFileStorage.setIsEnterprise(ApplicationMetadata.IsEnterpriseVersion) CentralFileStorage.setIsEnterprise(ApplicationMetadata.IsEnterpriseVersion)
Resources.setIsEnterprise(ApplicationMetadata.IsEnterpriseVersion)
@pyqtProperty(str, constant=True) @pyqtProperty(str, constant=True)
def ultimakerCloudApiRootUrl(self) -> str: def ultimakerCloudApiRootUrl(self) -> str:
@ -315,7 +316,7 @@ class CuraApplication(QtApplication):
def initialize(self) -> None: def initialize(self) -> None:
self.__addExpectedResourceDirsAndSearchPaths() # Must be added before init of super self.__addExpectedResourceDirsAndSearchPaths() # Must be added before init of super
super().initialize() super().initialize(ApplicationMetadata.IsEnterpriseVersion)
self._preferences.addPreference("cura/single_instance", False) self._preferences.addPreference("cura/single_instance", False)
self._use_single_instance = self._preferences.getValue("cura/single_instance") or self._cli_args.single_instance self._use_single_instance = self._preferences.getValue("cura/single_instance") or self._cli_args.single_instance
@ -348,12 +349,12 @@ class CuraApplication(QtApplication):
Resources.addExpectedDirNameInData(dir_name) Resources.addExpectedDirNameInData(dir_name)
app_root = os.path.abspath(os.path.join(os.path.dirname(sys.executable))) app_root = os.path.abspath(os.path.join(os.path.dirname(sys.executable)))
Resources.addSearchPath(os.path.join(app_root, "share", "cura", "resources")) Resources.addSecureSearchPath(os.path.join(app_root, "share", "cura", "resources"))
Resources.addSearchPath(os.path.join(self._app_install_dir, "share", "cura", "resources")) Resources.addSecureSearchPath(os.path.join(self._app_install_dir, "share", "cura", "resources"))
if not hasattr(sys, "frozen"): if not hasattr(sys, "frozen"):
resource_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources") resource_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources")
Resources.addSearchPath(resource_path) Resources.addSecureSearchPath(resource_path)
@classmethod @classmethod
def _initializeSettingDefinitions(cls): def _initializeSettingDefinitions(cls):
@ -942,6 +943,7 @@ class CuraApplication(QtApplication):
self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles)) self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles))
self._setLoadingHint(self._i18n_catalog.i18nc("@info:progress", "Initializing engine...")) self._setLoadingHint(self._i18n_catalog.i18nc("@info:progress", "Initializing engine..."))
self.initializeEngine() self.initializeEngine()
self.getTheme().setCheckIfTrusted(ApplicationMetadata.IsEnterpriseVersion)
# Initialize UI state # Initialize UI state
controller.setActiveStage("PrepareStage") controller.setActiveStage("PrepareStage")

View File

@ -1,14 +1,18 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import os
from typing import Any, cast, Dict, List, Set, Tuple, TYPE_CHECKING, Optional from typing import Any, cast, Dict, List, Set, Tuple, TYPE_CHECKING, Optional
from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry
from cura.CuraApplication import CuraApplication # To find some resource types. from cura.CuraApplication import CuraApplication # To find some resource types.
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
from UM.PackageManager import PackageManager # The class we're extending. from UM.PackageManager import PackageManager # The class we're extending.
from UM.Resources import Resources # To find storage paths for some resource types. from UM.Resources import Resources # To find storage paths for some resource types.
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
if TYPE_CHECKING: if TYPE_CHECKING:
@ -51,6 +55,27 @@ class CuraPackageManager(PackageManager):
super().initialize() super().initialize()
def getMaterialFilePackageId(self, file_name: str, guid: str) -> str:
"""Get the id of the installed material package that contains file_name"""
for material_package in [f for f in os.scandir(self._installation_dirs_dict["materials"]) if f.is_dir()]:
package_id = material_package.name
for root, _, file_names in os.walk(material_package.path):
if file_name not in file_names:
# File with the name we are looking for is not in this directory
continue
with open(root + "/" + file_name, encoding="utf-8") as f:
# Make sure the file we found has the same guid as our material
# Parsing this xml would be better but the namespace is needed to search it.
parsed_guid = PluginRegistry.getInstance().getPluginObject("XmlMaterialProfile").getMetadataFromSerialized(
f.read(), "GUID")
if guid == parsed_guid:
return package_id
Logger.error("Could not find package_id for file: {} with GUID: {} ".format(file_name, guid))
return ""
def getMachinesUsingPackage(self, package_id: str) -> Tuple[List[Tuple[GlobalStack, str, str]], List[Tuple[GlobalStack, str, str]]]: def getMachinesUsingPackage(self, package_id: str) -> Tuple[List[Tuple[GlobalStack, str, str]], List[Tuple[GlobalStack, str, str]]]:
"""Returns a list of where the package is used """Returns a list of where the package is used

View File

@ -111,7 +111,7 @@ class IntentCategoryModel(ListModel):
except ValueError: except ValueError:
weight = 99 weight = 99
result.append({ result.append({
"name": IntentCategoryModel.translation(category, "name", category), "name": IntentCategoryModel.translation(category, "name", category.title()),
"description": IntentCategoryModel.translation(category, "description", None), "description": IntentCategoryModel.translation(category, "description", None),
"intent_category": category, "intent_category": category,
"weight": weight, "weight": weight,

View File

@ -45,8 +45,7 @@ class MaterialManagementModel(QObject):
for package_id, package_data in application.getPackageManager().getPackagesInstalledOnStartup().items(): for package_id, package_data in application.getPackageManager().getPackagesInstalledOnStartup().items():
if package_data["package_info"]["package_type"] == "material": if package_data["package_info"]["package_type"] == "material":
# At least one new material was installed # At least one new material was installed
# TODO: This should be enabled again once CURA-8609 is merged self._showSyncNewMaterialsMessage()
#self._showSyncNewMaterialsMessage()
break break
def _showSyncNewMaterialsMessage(self) -> None: def _showSyncNewMaterialsMessage(self) -> None:

View File

@ -358,8 +358,9 @@ class QualityManagementModel(ListModel):
"quality_type": quality_type, "quality_type": quality_type,
"quality_changes_group": None, "quality_changes_group": None,
"intent_category": intent_category, "intent_category": intent_category,
"section_name": catalog.i18nc("@label", intent_translations.get(intent_category, {}).get("name", catalog.i18nc("@label", "Unknown"))), "section_name": catalog.i18nc("@label", intent_translations.get(intent_category, {}).get("name", catalog.i18nc("@label", intent_category.title()))),
}) })
# Sort by quality_type for each intent category # Sort by quality_type for each intent category
intent_translations_list = list(intent_translations) intent_translations_list = list(intent_translations)

View File

@ -114,7 +114,7 @@ class ContainerManager(QObject):
for _ in range(len(entries)): for _ in range(len(entries)):
item = item.get(entries.pop(0), {}) item = item.get(entries.pop(0), {})
if item[entry_name] != entry_value: if entry_name not in item or item[entry_name] != entry_value:
sub_item_changed = True sub_item_changed = True
item[entry_name] = entry_value item[entry_name] = entry_value

View File

@ -1,4 +1,4 @@
# Copyright (c) 2020 Ultimaker B.V. # Copyright (c) 2022 Ultimaker B.V.
# 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.
@ -382,7 +382,10 @@ class ExtruderManager(QObject):
# "fdmextruder". We need to check a machine here so its extruder definition is correct according to this. # "fdmextruder". We need to check a machine here so its extruder definition is correct according to this.
def fixSingleExtrusionMachineExtruderDefinition(self, global_stack: "GlobalStack") -> None: def fixSingleExtrusionMachineExtruderDefinition(self, global_stack: "GlobalStack") -> None:
container_registry = ContainerRegistry.getInstance() container_registry = ContainerRegistry.getInstance()
expected_extruder_definition_0_id = global_stack.getMetaDataEntry("machine_extruder_trains")["0"] expected_extruder_stack = global_stack.getMetaDataEntry("machine_extruder_trains")
if expected_extruder_stack is None:
return
expected_extruder_definition_0_id = expected_extruder_stack["0"]
try: try:
extruder_stack_0 = global_stack.extruderList[0] extruder_stack_0 = global_stack.extruderList[0]
except IndexError: except IndexError:

View File

@ -1611,7 +1611,7 @@ class MachineManager(QObject):
if intent_category != "default": if intent_category != "default":
intent_display_name = IntentCategoryModel.translation(intent_category, intent_display_name = IntentCategoryModel.translation(intent_category,
"name", "name",
catalog.i18nc("@label", "Unknown")) intent_category.title())
display_name = "{intent_name} - {the_rest}".format(intent_name = intent_display_name, display_name = "{intent_name} - {the_rest}".format(intent_name = intent_display_name,
the_rest = display_name) the_rest = display_name)

View File

@ -23,6 +23,7 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
from UM.Job import Job from UM.Job import Job
from UM.Preferences import Preferences from UM.Preferences import Preferences
from cura.CuraPackageManager import CuraPackageManager
from cura.Machines.ContainerTree import ContainerTree from cura.Machines.ContainerTree import ContainerTree
from cura.Settings.CuraStackBuilder import CuraStackBuilder from cura.Settings.CuraStackBuilder import CuraStackBuilder
@ -579,6 +580,10 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
is_printer_group = True is_printer_group = True
machine_name = group_name machine_name = group_name
# Getting missing required package ids
package_metadata = self._parse_packages_metadata(archive)
missing_package_metadata = self._filter_missing_package_metadata(package_metadata)
# Show the dialog, informing the user what is about to happen. # Show the dialog, informing the user what is about to happen.
self._dialog.setMachineConflict(machine_conflict) self._dialog.setMachineConflict(machine_conflict)
self._dialog.setIsPrinterGroup(is_printer_group) self._dialog.setIsPrinterGroup(is_printer_group)
@ -599,6 +604,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._dialog.setExtruders(extruders) self._dialog.setExtruders(extruders)
self._dialog.setVariantType(variant_type_name) self._dialog.setVariantType(variant_type_name)
self._dialog.setHasObjectsOnPlate(Application.getInstance().platformActivity) self._dialog.setHasObjectsOnPlate(Application.getInstance().platformActivity)
self._dialog.setMissingPackagesMetadata(missing_package_metadata)
self._dialog.show() self._dialog.show()
# Block until the dialog is closed. # Block until the dialog is closed.
@ -1243,3 +1249,29 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
metadata = data.iterfind("./um:metadata/um:name/um:label", {"um": "http://www.ultimaker.com/material"}) metadata = data.iterfind("./um:metadata/um:name/um:label", {"um": "http://www.ultimaker.com/material"})
for entry in metadata: for entry in metadata:
return entry.text return entry.text
@staticmethod
def _parse_packages_metadata(archive: zipfile.ZipFile) -> List[Dict[str, str]]:
try:
package_metadata = json.loads(archive.open("Metadata/packages.json").read().decode("utf-8"))
return package_metadata["packages"]
except KeyError:
Logger.warning("No package metadata was found in .3mf file.")
except Exception:
Logger.error("Failed to load packes metadata from .3mf file")
return []
@staticmethod
def _filter_missing_package_metadata(package_metadata: List[Dict[str, str]]) -> List[Dict[str, str]]:
"""Filters out installed packages from package_metadata"""
missing_packages = []
package_manager = cast(CuraPackageManager, CuraApplication.getInstance().getPackageManager())
for package in package_metadata:
package_id = package["id"]
if not package_manager.isPackageInstalled(package_id):
missing_packages.append(package)
return missing_packages

View File

@ -1,14 +1,19 @@
# Copyright (c) 2020 Ultimaker B.V. # Copyright (c) 2022 Ultimaker B.V.
# 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, QObject, pyqtProperty, QCoreApplication, QUrl
from PyQt6.QtGui import QDesktopServices
from typing import List, Optional, Dict, cast from typing import List, Optional, Dict, cast
from PyQt6.QtCore import pyqtSignal, QObject, pyqtProperty, QCoreApplication
from UM.FlameProfiler import pyqtSlot
from UM.PluginRegistry import PluginRegistry
from UM.Application import Application
from UM.i18n import i18nCatalog
from UM.Settings.ContainerRegistry import ContainerRegistry
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
from UM.Application import Application
from UM.FlameProfiler import pyqtSlot
from UM.i18n import i18nCatalog
from UM.Logger import Logger
from UM.Message import Message
from UM.PluginRegistry import PluginRegistry
from UM.Settings.ContainerRegistry import ContainerRegistry
from .UpdatableMachinesModel import UpdatableMachinesModel from .UpdatableMachinesModel import UpdatableMachinesModel
import os import os
@ -23,7 +28,7 @@ i18n_catalog = i18nCatalog("cura")
class WorkspaceDialog(QObject): class WorkspaceDialog(QObject):
showDialogSignal = pyqtSignal() showDialogSignal = pyqtSignal()
def __init__(self, parent = None): def __init__(self, parent = None) -> None:
super().__init__(parent) super().__init__(parent)
self._component = None self._component = None
self._context = None self._context = None
@ -59,6 +64,9 @@ class WorkspaceDialog(QObject):
self._objects_on_plate = False self._objects_on_plate = False
self._is_printer_group = False self._is_printer_group = False
self._updatable_machines_model = UpdatableMachinesModel(self) self._updatable_machines_model = UpdatableMachinesModel(self)
self._missing_package_metadata: List[Dict[str, str]] = []
self._plugin_registry: PluginRegistry = CuraApplication.getInstance().getPluginRegistry()
self._install_missing_package_dialog: Optional[QObject] = None
machineConflictChanged = pyqtSignal() machineConflictChanged = pyqtSignal()
qualityChangesConflictChanged = pyqtSignal() qualityChangesConflictChanged = pyqtSignal()
@ -79,6 +87,7 @@ class WorkspaceDialog(QObject):
variantTypeChanged = pyqtSignal() variantTypeChanged = pyqtSignal()
extrudersChanged = pyqtSignal() extrudersChanged = pyqtSignal()
isPrinterGroupChanged = pyqtSignal() isPrinterGroupChanged = pyqtSignal()
missingPackagesChanged = pyqtSignal()
@pyqtProperty(bool, notify = isPrinterGroupChanged) @pyqtProperty(bool, notify = isPrinterGroupChanged)
def isPrinterGroup(self) -> bool: def isPrinterGroup(self) -> bool:
@ -274,6 +283,21 @@ class WorkspaceDialog(QObject):
self._has_quality_changes_conflict = quality_changes_conflict self._has_quality_changes_conflict = quality_changes_conflict
self.qualityChangesConflictChanged.emit() self.qualityChangesConflictChanged.emit()
def setMissingPackagesMetadata(self, missing_package_metadata: List[Dict[str, str]]) -> None:
self._missing_package_metadata = missing_package_metadata
self.missingPackagesChanged.emit()
@pyqtProperty("QVariantList", notify=missingPackagesChanged)
def missingPackages(self) -> List[Dict[str, str]]:
return self._missing_package_metadata
@pyqtSlot()
def installMissingPackages(self) -> None:
marketplace_plugin = PluginRegistry.getInstance().getPluginObject("Marketplace")
if not marketplace_plugin:
Logger.warning("Could not show dialog to install missing plug-ins. Is Marketplace plug-in not available?")
marketplace_plugin.showInstallMissingPackageDialog(self._missing_package_metadata, self.showMissingMaterialsWarning) # type: ignore
def getResult(self) -> Dict[str, Optional[str]]: def getResult(self) -> Dict[str, Optional[str]]:
if "machine" in self._result and self.updatableMachinesModel.count <= 1: if "machine" in self._result and self.updatableMachinesModel.count <= 1:
self._result["machine"] = None self._result["machine"] = None
@ -360,6 +384,41 @@ class WorkspaceDialog(QObject):
time.sleep(1 / 50) time.sleep(1 / 50)
QCoreApplication.processEvents() # Ensure that the GUI does not freeze. QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
@pyqtSlot()
def showMissingMaterialsWarning(self) -> None:
result_message = Message(
i18n_catalog.i18nc("@info:status", "The material used in this project relies on some material definitions not available in Cura, this might produce undesirable print results. We highly recommend installing the full material package from the Marketplace."),
lifetime=0,
title=i18n_catalog.i18nc("@info:title", "Material profiles not installed"),
message_type=Message.MessageType.WARNING
)
result_message.addAction(
"learn_more",
name=i18n_catalog.i18nc("@action:button", "Learn more"),
icon="",
description="Learn more about project materials.",
button_align=Message.ActionButtonAlignment.ALIGN_LEFT,
button_style=Message.ActionButtonStyle.LINK
)
result_message.addAction(
"install_materials",
name=i18n_catalog.i18nc("@action:button", "Install Materials"),
icon="",
description="Install missing materials from project file.",
button_align=Message.ActionButtonAlignment.ALIGN_RIGHT,
button_style=Message.ActionButtonStyle.DEFAULT
)
result_message.actionTriggered.connect(self._onMessageActionTriggered)
result_message.show()
def _onMessageActionTriggered(self, message: Message, sync_message_action: str) -> None:
if sync_message_action == "install_materials":
self.installMissingPackages()
message.hide()
elif sync_message_action == "learn_more":
QDesktopServices.openUrl(QUrl("https://support.ultimaker.com/hc/en-us/articles/360011968360-Using-the-Ultimaker-Marketplace"))
def __show(self) -> None: def __show(self) -> None:
if self._view is None: if self._view is None:
self._createViewFromQML() self._createViewFromQML()

View File

@ -17,7 +17,7 @@ UM.Dialog
minimumWidth: UM.Theme.getSize("popup_dialog").width minimumWidth: UM.Theme.getSize("popup_dialog").width
minimumHeight: UM.Theme.getSize("popup_dialog").height minimumHeight: UM.Theme.getSize("popup_dialog").height
width: minimumWidth width: minimumWidth
margin: UM.Theme.getSize("default_margin").width
property int comboboxHeight: UM.Theme.getSize("default_margin").height property int comboboxHeight: UM.Theme.getSize("default_margin").height
onClosing: manager.notifyClosed() onClosing: manager.notifyClosed()
@ -31,10 +31,18 @@ UM.Dialog
} }
} }
Flickable
{
clip: true
width: parent.width
height: parent.height
contentHeight: dialogSummaryItem.height
ScrollBar.vertical: UM.ScrollBar { id: verticalScrollBar }
Item Item
{ {
id: dialogSummaryItem id: dialogSummaryItem
width: parent.width width: verticalScrollBar.visible ? parent.width - verticalScrollBar.width - UM.Theme.getSize("default_margin").width : parent.width
height: childrenRect.height height: childrenRect.height
anchors.margins: 10 * screenScaleFactor anchors.margins: 10 * screenScaleFactor
@ -441,19 +449,85 @@ UM.Dialog
} }
} }
} }
}
property bool warning: manager.missingPackages.length > 0
footerComponent: Rectangle
{
color: warning ? UM.Theme.getColor("warning") : "transparent"
anchors.bottom: parent.bottom
width: parent.width
height: childrenRect.height + 2 * base.margin
Column
{
height: childrenRect.height
spacing: base.margin
anchors.margins: base.margin
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
RowLayout
{
id: warningRow
height: childrenRect.height
visible: warning
spacing: base.margin
UM.ColorImage
{
width: UM.Theme.getSize("extruder_icon").width
height: UM.Theme.getSize("extruder_icon").height
source: UM.Theme.getIcon("Warning")
}
UM.Label
{
id: warningText
text: "The material used in this project is currently not installed in Cura.<br/>Install the material profile and reopen the project."
}
}
Loader
{
width: parent.width
height: childrenRect.height
sourceComponent: buttonRow
}
}
}
buttonSpacing: UM.Theme.getSize("default_margin").width buttonSpacing: UM.Theme.getSize("default_margin").width
rightButtons: [ rightButtons: [
Cura.TertiaryButton Cura.TertiaryButton
{ {
visible: !warning
text: catalog.i18nc("@action:button", "Cancel") text: catalog.i18nc("@action:button", "Cancel")
onClicked: reject() onClicked: reject()
}, },
Cura.PrimaryButton Cura.PrimaryButton
{ {
visible: !warning
text: catalog.i18nc("@action:button", "Open") text: catalog.i18nc("@action:button", "Open")
onClicked: accept() onClicked: accept()
},
Cura.TertiaryButton
{
visible: warning
text: catalog.i18nc("@action:button", "Open project anyway")
onClicked: {
manager.showMissingMaterialsWarning();
accept();
}
},
Cura.PrimaryButton
{
visible: warning
text: catalog.i18nc("@action:button", "Install missing material")
onClicked: manager.installMissingPackages()
} }
] ]

View File

@ -1,15 +1,19 @@
# Copyright (c) 2015-2022 Ultimaker B.V. # Copyright (c) 2015-2022 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional import json
from typing import Optional, cast, List, Dict
from UM.Mesh.MeshWriter import MeshWriter from UM.Mesh.MeshWriter import MeshWriter
from UM.Math.Vector import Vector from UM.Math.Vector import Vector
from UM.Logger import Logger from UM.Logger import Logger
from UM.Math.Matrix import Matrix from UM.Math.Matrix import Matrix
from UM.Application import Application from UM.Application import Application
from UM.Message import Message
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.CuraPackageManager import CuraPackageManager
from cura.Utils.Threading import call_on_qt_thread from cura.Utils.Threading import call_on_qt_thread
from cura.Snapshot import Snapshot from cura.Snapshot import Snapshot
@ -34,6 +38,9 @@ import UM.Application
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
THUMBNAIL_PATH = "Metadata/thumbnail.png"
MODEL_PATH = "3D/3dmodel.model"
PACKAGE_METADATA_PATH = "Metadata/packages.json"
class ThreeMFWriter(MeshWriter): class ThreeMFWriter(MeshWriter):
def __init__(self): def __init__(self):
@ -46,7 +53,7 @@ class ThreeMFWriter(MeshWriter):
} }
self._unit_matrix_string = self._convertMatrixToString(Matrix()) self._unit_matrix_string = self._convertMatrixToString(Matrix())
self._archive = None # type: Optional[zipfile.ZipFile] self._archive: Optional[zipfile.ZipFile] = None
self._store_archive = False self._store_archive = False
def _convertMatrixToString(self, matrix): def _convertMatrixToString(self, matrix):
@ -132,11 +139,11 @@ class ThreeMFWriter(MeshWriter):
def getArchive(self): def getArchive(self):
return self._archive return self._archive
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode): def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode) -> bool:
self._archive = None # Reset archive self._archive = None # Reset archive
archive = zipfile.ZipFile(stream, "w", compression = zipfile.ZIP_DEFLATED) archive = zipfile.ZipFile(stream, "w", compression = zipfile.ZIP_DEFLATED)
try: try:
model_file = zipfile.ZipInfo("3D/3dmodel.model") model_file = zipfile.ZipInfo(MODEL_PATH)
# Because zipfile is stupid and ignores archive-level compression settings when writing with ZipInfo. # Because zipfile is stupid and ignores archive-level compression settings when writing with ZipInfo.
model_file.compress_type = zipfile.ZIP_DEFLATED model_file.compress_type = zipfile.ZIP_DEFLATED
@ -151,7 +158,7 @@ class ThreeMFWriter(MeshWriter):
relations_file = zipfile.ZipInfo("_rels/.rels") relations_file = zipfile.ZipInfo("_rels/.rels")
relations_file.compress_type = zipfile.ZIP_DEFLATED relations_file.compress_type = zipfile.ZIP_DEFLATED
relations_element = ET.Element("Relationships", xmlns = self._namespaces["relationships"]) relations_element = ET.Element("Relationships", xmlns = self._namespaces["relationships"])
model_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/3D/3dmodel.model", Id = "rel0", Type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel") model_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/" + MODEL_PATH, Id = "rel0", Type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel")
# Attempt to add a thumbnail # Attempt to add a thumbnail
snapshot = self._createSnapshot() snapshot = self._createSnapshot()
@ -160,28 +167,32 @@ class ThreeMFWriter(MeshWriter):
thumbnail_buffer.open(QBuffer.OpenModeFlag.ReadWrite) thumbnail_buffer.open(QBuffer.OpenModeFlag.ReadWrite)
snapshot.save(thumbnail_buffer, "PNG") snapshot.save(thumbnail_buffer, "PNG")
thumbnail_file = zipfile.ZipInfo("Metadata/thumbnail.png") thumbnail_file = zipfile.ZipInfo(THUMBNAIL_PATH)
# Don't try to compress snapshot file, because the PNG is pretty much as compact as it will get # Don't try to compress snapshot file, because the PNG is pretty much as compact as it will get
archive.writestr(thumbnail_file, thumbnail_buffer.data()) archive.writestr(thumbnail_file, thumbnail_buffer.data())
# Add PNG to content types file # Add PNG to content types file
thumbnail_type = ET.SubElement(content_types, "Default", Extension = "png", ContentType = "image/png") thumbnail_type = ET.SubElement(content_types, "Default", Extension = "png", ContentType = "image/png")
# Add thumbnail relation to _rels/.rels file # Add thumbnail relation to _rels/.rels file
thumbnail_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/Metadata/thumbnail.png", Id = "rel1", Type = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail") thumbnail_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/" + THUMBNAIL_PATH, Id = "rel1", Type = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail")
# Write material metadata
material_metadata = self._getMaterialPackageMetadata()
self._storeMetadataJson({"packages": material_metadata}, archive, PACKAGE_METADATA_PATH)
savitar_scene = Savitar.Scene() savitar_scene = Savitar.Scene()
metadata_to_store = CuraApplication.getInstance().getController().getScene().getMetaData() scene_metadata = CuraApplication.getInstance().getController().getScene().getMetaData()
for key, value in metadata_to_store.items(): for key, value in scene_metadata.items():
savitar_scene.setMetaDataEntry(key, value) savitar_scene.setMetaDataEntry(key, value)
current_time_string = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") current_time_string = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if "Application" not in metadata_to_store: if "Application" not in scene_metadata:
# This might sound a bit strange, but this field should store the original application that created # This might sound a bit strange, but this field should store the original application that created
# the 3mf. So if it was already set, leave it to whatever it was. # the 3mf. So if it was already set, leave it to whatever it was.
savitar_scene.setMetaDataEntry("Application", CuraApplication.getInstance().getApplicationDisplayName()) savitar_scene.setMetaDataEntry("Application", CuraApplication.getInstance().getApplicationDisplayName())
if "CreationDate" not in metadata_to_store: if "CreationDate" not in scene_metadata:
savitar_scene.setMetaDataEntry("CreationDate", current_time_string) savitar_scene.setMetaDataEntry("CreationDate", current_time_string)
savitar_scene.setMetaDataEntry("ModificationDate", current_time_string) savitar_scene.setMetaDataEntry("ModificationDate", current_time_string)
@ -233,6 +244,53 @@ class ThreeMFWriter(MeshWriter):
return True return True
@staticmethod
def _storeMetadataJson(metadata: Dict[str, List[Dict[str, str]]], archive: zipfile.ZipFile, path: str) -> None:
"""Stores metadata inside archive path as json file"""
metadata_file = zipfile.ZipInfo(path)
# We have to set the compress type of each file as well (it doesn't keep the type of the entire archive)
metadata_file.compress_type = zipfile.ZIP_DEFLATED
archive.writestr(metadata_file, json.dumps(metadata, separators=(", ", ": "), indent=4, skipkeys=True, ensure_ascii=False))
@staticmethod
def _getMaterialPackageMetadata() -> List[Dict[str, str]]:
"""Get metadata for installed materials in active extruder stack, this does not include bundled materials.
:return: List of material metadata dictionaries.
"""
metadata = {}
package_manager = cast(CuraPackageManager, CuraApplication.getInstance().getPackageManager())
for extruder in CuraApplication.getInstance().getExtruderManager().getActiveExtruderStacks():
if not extruder.isEnabled:
# Don't export materials not in use
continue
package_id = package_manager.getMaterialFilePackageId(extruder.material.getFileName(), extruder.material.getMetaDataEntry("GUID"))
package_data = package_manager.getInstalledPackageInfo(package_id)
if not package_data:
message = Message(catalog.i18nc("@error:material",
"It was not possible to store material package information in project file: {material}. This project may not open correctly on other systems.".format(material=extruder.getName())),
title=catalog.i18nc("@info:title", "Failed to save material package information"),
message_type=Message.MessageType.WARNING)
message.show()
continue
if package_data.get("is_bundled"):
continue
material_metadata = {"id": package_id,
"display_name": package_data.get("display_name") if package_data.get("display_name") else "",
"package_version": package_data.get("package_version") if package_data.get("package_version") else "",
"sdk_version_semver": package_data.get("sdk_version_semver") if package_data.get("sdk_version_semver") else ""}
metadata[package_id] = material_metadata
# Storing in a dict and fetching values to avoid duplicates
return list(metadata.values())
@call_on_qt_thread # must be called from the main thread because of OpenGL @call_on_qt_thread # must be called from the main thread because of OpenGL
def _createSnapshot(self): def _createSnapshot(self):
Logger.log("d", "Creating thumbnail image...") Logger.log("d", "Creating thumbnail image...")

View File

@ -60,7 +60,7 @@ class CuraEngineBackend(QObject, Backend):
executable_name = "CuraEngine" executable_name = "CuraEngine"
if Platform.isWindows(): if Platform.isWindows():
executable_name += ".exe" executable_name += ".exe"
default_engine_location = executable_name self._default_engine_location = executable_name
search_path = [ search_path = [
os.path.abspath(os.path.dirname(sys.executable)), os.path.abspath(os.path.dirname(sys.executable)),
@ -74,29 +74,29 @@ class CuraEngineBackend(QObject, Backend):
for path in search_path: for path in search_path:
engine_path = os.path.join(path, executable_name) engine_path = os.path.join(path, executable_name)
if os.path.isfile(engine_path): if os.path.isfile(engine_path):
default_engine_location = engine_path self._default_engine_location = engine_path
break break
if Platform.isLinux() and not default_engine_location: if Platform.isLinux() and not self._default_engine_location:
if not os.getenv("PATH"): if not os.getenv("PATH"):
raise OSError("There is something wrong with your Linux installation.") raise OSError("There is something wrong with your Linux installation.")
for pathdir in cast(str, os.getenv("PATH")).split(os.pathsep): for pathdir in cast(str, os.getenv("PATH")).split(os.pathsep):
execpath = os.path.join(pathdir, executable_name) execpath = os.path.join(pathdir, executable_name)
if os.path.exists(execpath): if os.path.exists(execpath):
default_engine_location = execpath self._default_engine_location = execpath
break break
application = CuraApplication.getInstance() #type: CuraApplication application = CuraApplication.getInstance() #type: CuraApplication
self._multi_build_plate_model = None #type: Optional[MultiBuildPlateModel] self._multi_build_plate_model = None #type: Optional[MultiBuildPlateModel]
self._machine_error_checker = None #type: Optional[MachineErrorChecker] self._machine_error_checker = None #type: Optional[MachineErrorChecker]
if not default_engine_location: if not self._default_engine_location:
raise EnvironmentError("Could not find CuraEngine") raise EnvironmentError("Could not find CuraEngine")
Logger.log("i", "Found CuraEngine at: %s", default_engine_location) Logger.log("i", "Found CuraEngine at: %s", self._default_engine_location)
default_engine_location = os.path.abspath(default_engine_location) self._default_engine_location = os.path.abspath(self._default_engine_location)
application.getPreferences().addPreference("backend/location", default_engine_location) application.getPreferences().addPreference("backend/location", self._default_engine_location)
# Workaround to disable layer view processing if layer view is not active. # Workaround to disable layer view processing if layer view is not active.
self._layer_view_active = False #type: bool self._layer_view_active = False #type: bool
@ -215,7 +215,12 @@ class CuraEngineBackend(QObject, Backend):
This is useful for debugging and used to actually start the engine. This is useful for debugging and used to actually start the engine.
:return: list of commands and args / parameters. :return: list of commands and args / parameters.
""" """
command = [CuraApplication.getInstance().getPreferences().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), ""] from cura import ApplicationMetadata
if ApplicationMetadata.IsEnterpriseVersion:
command = [self._default_engine_location]
else:
command = [CuraApplication.getInstance().getPreferences().getValue("backend/location")]
command += ["connect", "127.0.0.1:{0}".format(self._port), ""]
parser = argparse.ArgumentParser(prog = "cura", add_help = False) parser = argparse.ArgumentParser(prog = "cura", add_help = False)
parser.add_argument("--debug", action = "store_true", default = False, help = "Turn on the debug mode by setting this option.") parser.add_argument("--debug", action = "store_true", default = False, help = "Turn on the debug mode by setting this option.")

View File

@ -0,0 +1,67 @@
# Copyright (c) 2022 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import os
from PyQt6.QtCore import QObject, pyqtSignal, pyqtProperty
from typing import Optional, List, Dict, cast, Callable
from cura.CuraApplication import CuraApplication
from UM.PluginRegistry import PluginRegistry
from cura.CuraPackageManager import CuraPackageManager
from UM.i18n import i18nCatalog
from UM.FlameProfiler import pyqtSlot
from .MissingPackageList import MissingPackageList
i18n_catalog = i18nCatalog("cura")
class InstallMissingPackageDialog(QObject):
"""Dialog used to display packages that need to be installed to load 3mf file materials"""
def __init__(self, packages_metadata: List[Dict[str, str]], show_missing_materials_warning: Callable[[], None]) -> None:
"""Initialize
:param packages_metadata: List of dictionaries containing information about missing packages.
"""
super().__init__()
self._plugin_registry: PluginRegistry = CuraApplication.getInstance().getPluginRegistry()
self._package_manager: CuraPackageManager = cast(CuraPackageManager, CuraApplication.getInstance().getPackageManager())
self._package_manager.installedPackagesChanged.connect(self.checkIfRestartNeeded)
self._dialog: Optional[QObject] = None
self._restart_needed = False
self._package_metadata: List[Dict[str, str]] = packages_metadata
self._package_model: MissingPackageList = MissingPackageList(packages_metadata)
self._show_missing_materials_warning = show_missing_materials_warning
def show(self) -> None:
plugin_path = self._plugin_registry.getPluginPath("Marketplace")
if plugin_path is None:
plugin_path = os.path.dirname(__file__)
# create a QML component for the license dialog
license_dialog_component_path = os.path.join(plugin_path, "resources", "qml", "InstallMissingPackagesDialog.qml")
self._dialog = CuraApplication.getInstance().createQmlComponent(license_dialog_component_path, {"manager": self})
self._dialog.show()
def checkIfRestartNeeded(self) -> None:
if self._dialog is None:
return
self._restart_needed = self._package_manager.hasPackagesToRemoveOrInstall
self.showRestartChanged.emit()
showRestartChanged = pyqtSignal()
@pyqtProperty(bool, notify=showRestartChanged)
def showRestartNotification(self) -> bool:
return self._restart_needed
@pyqtProperty(QObject)
def model(self) -> MissingPackageList:
return self._package_model
@pyqtSlot()
def showMissingMaterialsWarning(self) -> None:
self._show_missing_materials_warning()

View File

@ -3,15 +3,15 @@
import os.path import os.path
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from typing import Optional, cast from typing import Callable, cast, Dict, List, Optional
from cura.CuraApplication import CuraApplication # Creating QML objects and managing packages. from cura.CuraApplication import CuraApplication # Creating QML objects and managing packages.
from UM.Extension import Extension # We are implementing the main object of an extension here. from UM.Extension import Extension # We are implementing the main object of an extension here.
from UM.PluginRegistry import PluginRegistry # To find out where we are stored (the proper way). from UM.PluginRegistry import PluginRegistry # To find out where we are stored (the proper way).
from .RemotePackageList import RemotePackageList # To register this type with QML. from .InstallMissingPackagesDialog import InstallMissingPackageDialog # To allow creating this dialogue from outside of the plug-in.
from .LocalPackageList import LocalPackageList # To register this type with QML. from .LocalPackageList import LocalPackageList # To register this type with QML.
from .RemotePackageList import RemotePackageList # To register this type with QML.
class Marketplace(Extension, QObject): class Marketplace(Extension, QObject):
@ -41,6 +41,7 @@ class Marketplace(Extension, QObject):
self._tab_shown: int = 0 self._tab_shown: int = 0
self._restart_needed = False self._restart_needed = False
self.missingPackageDialog = None
def getTabShown(self) -> int: def getTabShown(self) -> int:
return self._tab_shown return self._tab_shown
@ -103,6 +104,9 @@ class Marketplace(Extension, QObject):
self.setTabShown(1) self.setTabShown(1)
def checkIfRestartNeeded(self) -> None: def checkIfRestartNeeded(self) -> None:
if self._window is None:
return
if self._package_manager.hasPackagesToRemoveOrInstall or \ if self._package_manager.hasPackagesToRemoveOrInstall or \
cast(PluginRegistry, self._plugin_registry).getCurrentSessionActivationChangedPlugins(): cast(PluginRegistry, self._plugin_registry).getCurrentSessionActivationChangedPlugins():
self._restart_needed = True self._restart_needed = True
@ -115,3 +119,15 @@ class Marketplace(Extension, QObject):
@pyqtProperty(bool, notify=showRestartNotificationChanged) @pyqtProperty(bool, notify=showRestartNotificationChanged)
def showRestartNotification(self) -> bool: def showRestartNotification(self) -> bool:
return self._restart_needed return self._restart_needed
def showInstallMissingPackageDialog(self, packages_metadata: List[Dict[str, str]], ignore_warning_callback: Callable[[], None]) -> None:
"""
Show a dialog that prompts the user to install certain packages.
The dialog is worded for packages that are missing and required for a certain operation.
:param packages_metadata: The metadata of the packages that are missing.
:param ignore_warning_callback: A callback that gets executed when the user ignores the pop-up, to show them a
warning.
"""
self.missingPackageDialog = InstallMissingPackageDialog(packages_metadata, ignore_warning_callback)
self.missingPackageDialog.show()

View File

@ -0,0 +1,46 @@
# Copyright (c) 2022 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional, TYPE_CHECKING, Dict, List
from .Constants import PACKAGES_URL
from .PackageModel import PackageModel
from .RemotePackageList import RemotePackageList
from PyQt6.QtCore import pyqtSignal, QObject, pyqtProperty, QCoreApplication
from UM.TaskManagement.HttpRequestManager import HttpRequestManager # To request the package list from the API.
from UM.i18n import i18nCatalog
if TYPE_CHECKING:
from PyQt6.QtCore import QObject, pyqtProperty, pyqtSignal
catalog = i18nCatalog("cura")
class MissingPackageList(RemotePackageList):
def __init__(self, packages_metadata: List[Dict[str, str]], parent: Optional["QObject"] = None) -> None:
super().__init__(parent)
self._packages_metadata: List[Dict[str, str]] = packages_metadata
self._package_type_filter = "material"
self._search_type = "package_ids"
self._requested_search_string = ",".join(map(lambda package: package["id"], packages_metadata))
def _parseResponse(self, reply: "QNetworkReply") -> None:
super()._parseResponse(reply)
# At the end of the list we want to show some information about packages the user is missing that can't be found
# This will add cards with some information about the missing packages
if not self.hasMore:
self._addPackagesMissingFromRequest()
def _addPackagesMissingFromRequest(self) -> None:
"""Create cards for packages the user needs to install that could not be found"""
returned_packages_ids = [item["package"].packageId for item in self._items]
for package_metadata in self._packages_metadata:
if package_metadata["id"] not in returned_packages_ids:
package = PackageModel.fromIncompletePackageInformation(package_metadata["display_name"], package_metadata["package_version"], self._package_type_filter)
self.appendItem({"package": package})
self.itemsChanged.emit()

View File

@ -244,7 +244,10 @@ class PackageList(ListModel):
def _downloadError(self, package_id: str, update: bool = False, reply: Optional["QNetworkReply"] = None, error: Optional["QNetworkReply.NetworkError"] = None) -> None: def _downloadError(self, package_id: str, update: bool = False, reply: Optional["QNetworkReply"] = None, error: Optional["QNetworkReply.NetworkError"] = None) -> None:
if reply: if reply:
try:
reply_string = bytes(reply.readAll()).decode() reply_string = bytes(reply.readAll()).decode()
except UnicodeDecodeError:
reply_string = "<error message is corrupt too>"
Logger.error(f"Failed to download package: {package_id} due to {reply_string}") Logger.error(f"Failed to download package: {package_id} due to {reply_string}")
self._package_manager.packageInstallingFailed.emit(package_id) self._package_manager.packageInstallingFailed.emit(package_id)

View File

@ -84,6 +84,20 @@ class PackageModel(QObject):
self._is_busy = False self._is_busy = False
self._is_missing_package_information = False
@classmethod
def fromIncompletePackageInformation(cls, display_name: str, package_version: str, package_type: str) -> "PackageModel":
package_data = {
"display_name": display_name,
"package_version": package_version,
"package_type": package_type,
"description": "The material package associated with the Cura project could not be found on the Ultimaker marketplace. Use the partial material profile definition stored in the Cura project file at your own risk."
}
package_model = cls(package_data)
package_model.setIsMissingPackageInformation(True)
return package_model
@pyqtSlot() @pyqtSlot()
def _processUpdatedPackages(self): def _processUpdatedPackages(self):
self.setCanUpdate(self._package_manager.checkIfPackageCanUpdate(self._package_id)) self.setCanUpdate(self._package_manager.checkIfPackageCanUpdate(self._package_id))
@ -385,3 +399,14 @@ class PackageModel(QObject):
def canUpdate(self) -> bool: def canUpdate(self) -> bool:
"""Flag indicating if the package can be updated""" """Flag indicating if the package can be updated"""
return self._can_update return self._can_update
isMissingPackageInformationChanged = pyqtSignal()
def setIsMissingPackageInformation(self, isMissingPackageInformation: bool) -> None:
self._is_missing_package_information = isMissingPackageInformation
self.isMissingPackageInformationChanged.emit()
@pyqtProperty(bool, notify=isMissingPackageInformationChanged)
def isMissingPackageInformation(self) -> bool:
"""Flag indicating if the package can be updated"""
return self._is_missing_package_information

View File

@ -28,6 +28,7 @@ class RemotePackageList(PackageList):
self._package_type_filter = "" self._package_type_filter = ""
self._requested_search_string = "" self._requested_search_string = ""
self._current_search_string = "" self._current_search_string = ""
self._search_type = "search"
self._request_url = self._initialRequestUrl() self._request_url = self._initialRequestUrl()
self._ongoing_requests["get_packages"] = None self._ongoing_requests["get_packages"] = None
self.isLoadingChanged.connect(self._onLoadingChanged) self.isLoadingChanged.connect(self._onLoadingChanged)
@ -100,7 +101,7 @@ class RemotePackageList(PackageList):
if self._package_type_filter != "": if self._package_type_filter != "":
request_url += f"&package_type={self._package_type_filter}" request_url += f"&package_type={self._package_type_filter}"
if self._current_search_string != "": if self._current_search_string != "":
request_url += f"&search={self._current_search_string}" request_url += f"&{self._search_type}={self._current_search_string}"
return request_url return request_url
def _parseResponse(self, reply: "QNetworkReply") -> None: def _parseResponse(self, reply: "QNetworkReply") -> None:

View File

@ -14,4 +14,4 @@ def register(app):
""" """
Register the plug-in object with Uranium. Register the plug-in object with Uranium.
""" """
return { "extension": [Marketplace(), SyncOrchestrator(app)] } return { "extension": [SyncOrchestrator(app), Marketplace()] }

View File

@ -0,0 +1,21 @@
// Copyright (c) 2021 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.2
import UM 1.5 as UM
import Cura 1.6 as Cura
Marketplace
{
modality: Qt.ApplicationModal
title: catalog.i18nc("@title", "Install missing Materials")
pageContentsSource: "MissingPackages.qml"
showSearchHeader: false
showOnboadBanner: false
onClosing: manager.showMissingMaterialsWarning()
}

View File

@ -16,6 +16,10 @@ Window
signal searchStringChanged(string new_search) signal searchStringChanged(string new_search)
property alias showOnboadBanner: onBoardBanner.visible
property alias showSearchHeader: searchHeader.visible
property alias pageContentsSource: content.source
minimumWidth: UM.Theme.getSize("modal_window_minimum").width minimumWidth: UM.Theme.getSize("modal_window_minimum").width
minimumHeight: UM.Theme.getSize("modal_window_minimum").height minimumHeight: UM.Theme.getSize("modal_window_minimum").height
width: minimumWidth width: minimumWidth
@ -86,6 +90,7 @@ Window
OnboardBanner OnboardBanner
{ {
id: onBoardBanner
visible: content.item && content.item.bannerVisible visible: content.item && content.item.bannerVisible
text: content.item && content.item.bannerText text: content.item && content.item.bannerText
icon: content.item && content.item.bannerIcon icon: content.item && content.item.bannerIcon
@ -100,6 +105,7 @@ Window
// Search & Top-Level Tabs // Search & Top-Level Tabs
Item Item
{ {
id: searchHeader
implicitHeight: childrenRect.height implicitHeight: childrenRect.height
implicitWidth: parent.width - 2 * UM.Theme.getSize("default_margin").width implicitWidth: parent.width - 2 * UM.Theme.getSize("default_margin").width
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
@ -186,7 +192,7 @@ Window
{ {
text: catalog.i18nc("@info", "Search in the browser") text: catalog.i18nc("@info", "Search in the browser")
iconSource: UM.Theme.getIcon("LinkExternal") iconSource: UM.Theme.getIcon("LinkExternal")
visible: pageSelectionTabBar.currentItem.hasSearch visible: pageSelectionTabBar.currentItem.hasSearch && searchHeader.visible
isIconOnRightSide: true isIconOnRightSide: true
height: fontMetrics.height height: fontMetrics.height
textFont: fontMetrics.font textFont: fontMetrics.font

View File

@ -0,0 +1,15 @@
// Copyright (c) 2021 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import UM 1.4 as UM
Packages
{
pageTitle: catalog.i18nc("@header", "Install Materials")
bannerVisible: false
showUpdateButton: false
showInstallButton: true
model: manager.model
}

View File

@ -18,6 +18,8 @@ Rectangle
height: childrenRect.height height: childrenRect.height
color: UM.Theme.getColor("main_background") color: UM.Theme.getColor("main_background")
radius: UM.Theme.getSize("default_radius").width radius: UM.Theme.getSize("default_radius").width
border.color: packageData.isMissingPackageInformation ? UM.Theme.getColor("warning") : "transparent"
border.width: packageData.isMissingPackageInformation ? UM.Theme.getSize("default_lining").width : 0
PackageCardHeader PackageCardHeader
{ {

View File

@ -19,6 +19,8 @@ Item
property bool showInstallButton: false property bool showInstallButton: false
property bool showUpdateButton: false property bool showUpdateButton: false
property string missingPackageReadMoreUrl: "https://ultimaker.atlassian.net/wiki/spaces/SD/pages/1231916580/Campaign+links+from+Cura+to+the+Ultimaker+domain"
width: parent.width width: parent.width
height: UM.Theme.getSize("card").height height: UM.Theme.getSize("card").height
@ -87,6 +89,14 @@ Item
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
Layout.preferredHeight: childrenRect.height Layout.preferredHeight: childrenRect.height
UM.StatusIcon
{
width: UM.Theme.getSize("section_icon").width + UM.Theme.getSize("narrow_margin").width
height: UM.Theme.getSize("section_icon").height
status: UM.StatusIcon.Status.WARNING
visible: packageData.isMissingPackageInformation
}
UM.Label UM.Label
{ {
text: packageData.displayName text: packageData.displayName
@ -109,6 +119,7 @@ Item
Button Button
{ {
id: externalLinkButton id: externalLinkButton
visible: !packageData.isMissingPackageInformation
// For some reason if i set padding, they don't match up. If i set all of them explicitly, it does work? // For some reason if i set padding, they don't match up. If i set all of them explicitly, it does work?
leftPadding: UM.Theme.getSize("narrow_margin").width leftPadding: UM.Theme.getSize("narrow_margin").width
@ -155,6 +166,7 @@ Item
UM.Label UM.Label
{ {
id: authorBy id: authorBy
visible: !packageData.isMissingPackageInformation
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
text: catalog.i18nc("@label Is followed by the name of an author", "By") text: catalog.i18nc("@label Is followed by the name of an author", "By")
@ -165,6 +177,7 @@ Item
// clickable author name // clickable author name
Item Item
{ {
visible: !packageData.isMissingPackageInformation
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: authorBy.height implicitHeight: authorBy.height
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
@ -182,10 +195,29 @@ Item
} }
} }
Item
{
visible: packageData.isMissingPackageInformation
Layout.fillWidth: true
implicitHeight: readMoreButton.height
Layout.alignment: Qt.AlignTop
Cura.TertiaryButton
{
id: readMoreButton
text: catalog.i18nc("@button:label", "Learn More")
leftPadding: 0
rightPadding: 0
iconSource: UM.Theme.getIcon("LinkExternal")
isIconOnRightSide: true
onClicked: Qt.openUrlExternally(missingPackageReadMoreUrl)
}
}
ManageButton ManageButton
{ {
id: enableManageButton id: enableManageButton
visible: showDisableButton && packageData.isInstalled && !packageData.isToBeInstalled && packageData.packageType != "material" visible: showDisableButton && packageData.isInstalled && !packageData.isToBeInstalled && packageData.packageType != "material" && !packageData.isMissingPackageInformation
enabled: !packageData.busy enabled: !packageData.busy
button_style: !packageData.isActive button_style: !packageData.isActive
@ -199,7 +231,7 @@ Item
ManageButton ManageButton
{ {
id: installManageButton id: installManageButton
visible: showInstallButton && (packageData.canDowngrade || !packageData.isBundled) visible: showInstallButton && (packageData.canDowngrade || !packageData.isBundled) && !packageData.isMissingPackageInformation
enabled: !packageData.busy enabled: !packageData.busy
busy: packageData.busy busy: packageData.busy
button_style: !(packageData.isInstalled || packageData.isToBeInstalled) button_style: !(packageData.isInstalled || packageData.isToBeInstalled)
@ -229,7 +261,7 @@ Item
ManageButton ManageButton
{ {
id: updateManageButton id: updateManageButton
visible: showUpdateButton && packageData.canUpdate visible: showUpdateButton && packageData.canUpdate && !packageData.isMissingPackageInformation
enabled: !packageData.busy enabled: !packageData.busy
busy: packageData.busy busy: packageData.busy
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop

View File

@ -61,10 +61,13 @@ ListView
hoverEnabled: true hoverEnabled: true
onClicked: onClicked:
{
if (!model.package.isMissingPackageInformation)
{ {
packages.selectedPackage = model.package; packages.selectedPackage = model.package;
contextStack.push(packageDetailsComponent); contextStack.push(packageDetailsComponent);
} }
}
PackageCard PackageCard
{ {

View File

@ -122,6 +122,7 @@ Rectangle
} }
visible: !isNetworkConfigured && isNetworkConfigurable visible: !isNetworkConfigured && isNetworkConfigurable
width: childrenRect.width width: childrenRect.width
height: childrenRect.height
UM.ColorImage UM.ColorImage
{ {

View File

@ -169,7 +169,10 @@ class ClusterApiClient:
""" """
def parse() -> None: def parse() -> None:
try:
self._anti_gc_callbacks.remove(parse) self._anti_gc_callbacks.remove(parse)
except ValueError: # Already removed asynchronously.
return # Then the rest of the function is also already executed.
# Don't try to parse the reply if we didn't get one # Don't try to parse the reply if we didn't get one
if reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) is None: if reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) is None:

View File

@ -343,6 +343,9 @@ class XmlMaterialProfile(InstanceContainer):
return stream.getvalue().decode("utf-8") return stream.getvalue().decode("utf-8")
def getFileName(self) -> str:
return (self.getMetaDataEntry("base_file") + ".xml.fdm_material").replace(" ", "+")
# Recursively resolve loading inherited files # Recursively resolve loading inherited files
def _resolveInheritance(self, file_name): def _resolveInheritance(self, file_name):
xml = self._loadFile(file_name) xml = self._loadFile(file_name)
@ -477,6 +480,15 @@ class XmlMaterialProfile(InstanceContainer):
return version * 1000000 + setting_version return version * 1000000 + setting_version
@classmethod
def getMetadataFromSerialized(cls, serialized: str, property_name: str) -> str:
data = ET.fromstring(serialized)
metadata = data.find("./um:metadata", cls.__namespaces)
property = metadata.find("./um:" + property_name, cls.__namespaces)
# This is a necessary property != None check, xml library overrides __bool__ to return False in cases when Element is not None.
return property.text if property != None else ""
def deserialize(self, serialized, file_name = None): def deserialize(self, serialized, file_name = None):
"""Overridden from InstanceContainer""" """Overridden from InstanceContainer"""

View File

@ -44,7 +44,6 @@
"machine_max_jerk_xy": { "value": 8 }, "machine_max_jerk_xy": { "value": 8 },
"machine_max_jerk_z": { "value": 0.4 }, "machine_max_jerk_z": { "value": 0.4 },
"machine_max_jerk_e": { "value": 5 }, "machine_max_jerk_e": { "value": 5 },
"machine_heated_bed": { "default_value": true },
"material_diameter": { "default_value": 1.75 }, "material_diameter": { "default_value": 1.75 },
"infill_overlap": { "default_value": 15 }, "infill_overlap": { "default_value": 15 },
"acceleration_print": { "value": 500 }, "acceleration_print": { "value": 500 },

View File

@ -2256,7 +2256,7 @@
"maximum_value": "machine_height", "maximum_value": "machine_height",
"maximum_value_warning": "resolveOrValue('infill_sparse_thickness') * 10", "maximum_value_warning": "resolveOrValue('infill_sparse_thickness') * 10",
"type": "float", "type": "float",
"value": "0 if infill_sparse_density > 0 else 0", "value": "0",
"limit_to_extruder": "infill_extruder_nr", "limit_to_extruder": "infill_extruder_nr",
"enabled": "infill_sparse_density > 0", "enabled": "infill_sparse_density > 0",
"settable_per_mesh": true, "settable_per_mesh": true,

View File

@ -50,23 +50,29 @@
"wall_thickness": { "wall_thickness": {
"value": "wall_line_width_0 + wall_line_width_x" "value": "wall_line_width_0 + wall_line_width_x"
}, },
"infill_before_walls": {
"value": "False"
},
"infill_material_flow": { "infill_material_flow": {
"value": "(1.95-infill_sparse_density / 100 if infill_sparse_density > 95 else 1) * material_flow" "value": "(1.95-infill_sparse_density / 100 if infill_sparse_density > 95 else 1) * material_flow"
}, },
"retraction_combing": { "retraction_combing": {
"value": "'no_outer_surfaces'" "value": "'no_outer_surfaces'"
}, },
"retraction_count_max": {
"value": 25
},
"retraction_extrusion_window": {
"value": 1
},
"roofing_layer_count": { "roofing_layer_count": {
"value": "0" "value": "1"
}, },
"roofing_material_flow": { "roofing_material_flow": {
"value": "material_flow" "value": "material_flow"
}, },
"skin_material_flow": { "skin_material_flow": {
"value": "0.97 * material_flow" "value": "0.95 * material_flow"
},
"support_interface_material_flow": {
"value": "skin_material_flow"
}, },
"skin_monotonic" : { "skin_monotonic" : {
"value": true "value": true
@ -89,11 +95,124 @@
"meshfix_maximum_deviation": { "meshfix_maximum_deviation": {
"value": "machine_nozzle_size / 10" "value": "machine_nozzle_size / 10"
}, },
"jerk_travel": { "jerk_travel_enabled": {
"value": "jerk_print" "value": false
},
"acceleration_travel_enabled": {
"value": false
}, },
"acceleration_travel": { "acceleration_travel": {
"value": "acceleration_wall" "value": "acceleration_wall"
},
"skin_edge_support_thickness": {
"value": "4 * layer_height if infill_sparse_density < 30 else 0"
},
"bridge_settings_enabled": {
"value": false
},
"bridge_wall_min_length": {
"value": 0
},
"bridge_skin_support_threshold": {
"value": 50
},
"bridge_sparse_infill_max_density": {
"value": 0
},
"bridge_wall_coast": {
"value": 0
},
"bridge_wall_speed": {
"value": "speed_wall"
},
"bridge_wall_material_flow": {
"value": "wall_material_flow"
},
"bridge_skin_speed": {
"value": "speed_topbottom"
},
"bridge_skin_material_flow": {
"value": "skin_material_flow"
},
"bridge_skin_density": {
"value": "80"
},
"bridge_fan_speed": {
"value": "cool_fan_speed_max"
},
"bridge_enable_more_layers": {
"value": false
},
"bridge_skin_speed_2": {
"value": "speed_topbottom"
},
"bridge_skin_material_flow_2": {
"value": "skin_material_flow"
},
"bridge_skin_density_2": {
"value": 100
},
"bridge_fan_speed_2": {
"value": "cool_fan_speed_min"
},
"bridge_skin_speed_3": {
"value": "speed_topbottom"
},
"bridge_skin_material_flow_3": {
"value": "skin_material_flow"
},
"bridge_skin_density_3": {
"value": 100
},
"bridge_fan_speed_3": {
"value": "cool_fan_speed_min"
},
"jerk_print": {
"value": "20",
"minimum_value_warning": 20
},
"jerk_infill": {
"minimum_value_warning": 20
},
"jerk_wall": {
"minimum_value_warning": 20
},
"jerk_wall_0": {
"minimum_value_warning": 20
},
"jerk_roofing": {
"minimum_value_warning": 20
},
"jerk_topbottom": {
"minimum_value_warning": 20
},
"jerk_support": {
"minimum_value_warning": 20
},
"jerk_support_infill": {
"minimum_value_warning": 20
},
"jerk_support_interface": {
"minimum_value_warning": 20
},
"jerk_prime_tower": {
"minimum_value_warning": 20
},
"jerk_layer_0": {
"minimum_value_warning": 20
},
"jerk_print_layer_0": {
"minimum_value_warning": 20
},
"jerk_travel": {
"value": "jerk_print",
"minimum_value_warning": 20
},
"jerk_travel_layer_0": {
"minimum_value_warning": 20
},
"jerk_skirt_brim": {
"minimum_value_warning": 20
} }
} }
} }

View File

@ -101,20 +101,6 @@
"infill_wipe_dist": { "value": "0" }, "infill_wipe_dist": { "value": "0" },
"initial_layer_line_width_factor": { "value": "120" }, "initial_layer_line_width_factor": { "value": "120" },
"jerk_enabled": { "value": "True" }, "jerk_enabled": { "value": "True" },
"jerk_print": { "value": "20", "minimum_value_warning": 20 },
"jerk_infill": {"minimum_value_warning": 20 },
"jerk_wall": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_wall_0": { "value": "jerk_wall", "minimum_value_warning": 20 },
"jerk_roofing": {"minimum_value_warning": 20 },
"jerk_topbottom": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_support": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_support_infill": {"minimum_value_warning": 20 },
"jerk_support_interface": { "value": "math.ceil(jerk_print * 5 / 20)"},
"jerk_prime_tower": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_layer_0": { "value": "jerk_topbottom", "minimum_value_warning": 20},
"jerk_print_layer_0": {"minimum_value_warning": 20 },
"jerk_travel_layer_0": {"minimum_value_warning": 20 },
"jerk_skirt_brim": {"minimum_value_warning": 20 },
"layer_height_0": { "value": "round(machine_nozzle_size / 1.5, 2)" }, "layer_height_0": { "value": "round(machine_nozzle_size / 1.5, 2)" },
"layer_start_x": { "value": "sum(extruderValues('machine_extruder_start_pos_x')) / len(extruderValues('machine_extruder_start_pos_x'))" }, "layer_start_x": { "value": "sum(extruderValues('machine_extruder_start_pos_x')) / len(extruderValues('machine_extruder_start_pos_x'))" },
"layer_start_y": { "value": "sum(extruderValues('machine_extruder_start_pos_y')) / len(extruderValues('machine_extruder_start_pos_y'))" }, "layer_start_y": { "value": "sum(extruderValues('machine_extruder_start_pos_y')) / len(extruderValues('machine_extruder_start_pos_y'))" },
@ -136,8 +122,6 @@
"raft_margin": { "value": "10" }, "raft_margin": { "value": "10" },
"raft_surface_layers": { "value": "1" }, "raft_surface_layers": { "value": "1" },
"retraction_amount": { "value": "6.5" }, "retraction_amount": { "value": "6.5" },
"retraction_count_max": { "value": "10" },
"retraction_extrusion_window": { "value": "1" },
"retraction_hop": { "value": "2" }, "retraction_hop": { "value": "2" },
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" }, "retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
"retraction_hop_only_when_collides": { "value": "True" }, "retraction_hop_only_when_collides": { "value": "True" },

View File

@ -93,20 +93,6 @@
"infill_pattern": { "value": "'zigzag' if infill_sparse_density > 80 else 'triangles'" }, "infill_pattern": { "value": "'zigzag' if infill_sparse_density > 80 else 'triangles'" },
"infill_wipe_dist": { "value": "0" }, "infill_wipe_dist": { "value": "0" },
"jerk_enabled": { "value": "True" }, "jerk_enabled": { "value": "True" },
"jerk_print": { "value": "20", "minimum_value_warning": 20 },
"jerk_infill": {"minimum_value_warning": 20 },
"jerk_wall": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_wall_0": { "value": "jerk_wall", "minimum_value_warning": 20 },
"jerk_roofing": {"minimum_value_warning": 20 },
"jerk_topbottom": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_support": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_support_infill": {"minimum_value_warning": 20 },
"jerk_support_interface": { "value": "math.ceil(jerk_print * 5 / 20)"},
"jerk_prime_tower": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_layer_0": { "value": "jerk_topbottom", "minimum_value_warning": 20},
"jerk_print_layer_0": {"minimum_value_warning": 20 },
"jerk_travel_layer_0": {"minimum_value_warning": 20 },
"jerk_skirt_brim": {"minimum_value_warning": 20 },
"layer_height_0": { "value": "round(machine_nozzle_size / 1.5, 2)" }, "layer_height_0": { "value": "round(machine_nozzle_size / 1.5, 2)" },
"layer_start_x": { "value": "sum(extruderValues('machine_extruder_start_pos_x')) / len(extruderValues('machine_extruder_start_pos_x'))" }, "layer_start_x": { "value": "sum(extruderValues('machine_extruder_start_pos_x')) / len(extruderValues('machine_extruder_start_pos_x'))" },
"layer_start_y": { "value": "sum(extruderValues('machine_extruder_start_pos_y')) / len(extruderValues('machine_extruder_start_pos_y'))" }, "layer_start_y": { "value": "sum(extruderValues('machine_extruder_start_pos_y')) / len(extruderValues('machine_extruder_start_pos_y'))" },
@ -128,8 +114,6 @@
"raft_speed": { "value": "25" }, "raft_speed": { "value": "25" },
"raft_surface_layers": { "value": "1" }, "raft_surface_layers": { "value": "1" },
"retraction_amount": { "value": "6.5" }, "retraction_amount": { "value": "6.5" },
"retraction_count_max": { "value": "10" },
"retraction_extrusion_window": { "value": "1" },
"retraction_hop": { "value": "2" }, "retraction_hop": { "value": "2" },
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" }, "retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
"retraction_hop_only_when_collides": { "value": "True" }, "retraction_hop_only_when_collides": { "value": "True" },
@ -155,7 +139,6 @@
"switch_extruder_prime_speed": { "value": "15" }, "switch_extruder_prime_speed": { "value": "15" },
"switch_extruder_retraction_amount": { "value": "8" }, "switch_extruder_retraction_amount": { "value": "8" },
"top_bottom_thickness": { "value": "1" }, "top_bottom_thickness": { "value": "1" },
"travel_avoid_supports": { "value": "True" },
"travel_avoid_distance": { "value": "3 if extruders_enabled_count > 1 else machine_nozzle_tip_outer_diameter / 2 * 1.5" }, "travel_avoid_distance": { "value": "3 if extruders_enabled_count > 1 else machine_nozzle_tip_outer_diameter / 2 * 1.5" },
"wall_0_inset": { "value": "0" }, "wall_0_inset": { "value": "0" },
"initial_layer_line_width_factor": { "value": "120" }, "initial_layer_line_width_factor": { "value": "120" },

View File

@ -95,20 +95,6 @@
"infill_pattern": { "value": "'zigzag' if infill_sparse_density > 80 else 'triangles'" }, "infill_pattern": { "value": "'zigzag' if infill_sparse_density > 80 else 'triangles'" },
"infill_wipe_dist": { "value": "0" }, "infill_wipe_dist": { "value": "0" },
"jerk_enabled": { "value": "True" }, "jerk_enabled": { "value": "True" },
"jerk_print": { "value": "20", "minimum_value_warning": 20 },
"jerk_infill": {"minimum_value_warning": 20 },
"jerk_wall": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_wall_0": { "value": "jerk_wall", "minimum_value_warning": 20 },
"jerk_roofing": {"minimum_value_warning": 20 },
"jerk_topbottom": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_support": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_support_infill": {"minimum_value_warning": 20 },
"jerk_support_interface": { "value": "math.ceil(jerk_print * 5 / 20)"},
"jerk_prime_tower": { "value": "jerk_print", "minimum_value_warning": 20 },
"jerk_layer_0": { "value": "jerk_topbottom", "minimum_value_warning": 20},
"jerk_print_layer_0": {"minimum_value_warning": 20 },
"jerk_travel_layer_0": {"minimum_value_warning": 20 },
"jerk_skirt_brim": {"minimum_value_warning": 20 },
"layer_height_0": { "value": "round(machine_nozzle_size / 1.5, 2)" }, "layer_height_0": { "value": "round(machine_nozzle_size / 1.5, 2)" },
"layer_start_x": { "value": "sum(extruderValues('machine_extruder_start_pos_x')) / len(extruderValues('machine_extruder_start_pos_x'))" }, "layer_start_x": { "value": "sum(extruderValues('machine_extruder_start_pos_x')) / len(extruderValues('machine_extruder_start_pos_x'))" },
"layer_start_y": { "value": "sum(extruderValues('machine_extruder_start_pos_y')) / len(extruderValues('machine_extruder_start_pos_y'))" }, "layer_start_y": { "value": "sum(extruderValues('machine_extruder_start_pos_y')) / len(extruderValues('machine_extruder_start_pos_y'))" },
@ -130,8 +116,6 @@
"raft_surface_layers": { "value": "1" }, "raft_surface_layers": { "value": "1" },
"retraction_amount": { "value": "6.5" }, "retraction_amount": { "value": "6.5" },
"retraction_combing": { "value": "'no_outer_surfaces'"}, "retraction_combing": { "value": "'no_outer_surfaces'"},
"retraction_count_max": { "value": "10" },
"retraction_extrusion_window": { "value": "1" },
"retraction_hop": { "value": "2" }, "retraction_hop": { "value": "2" },
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" }, "retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
"retraction_hop_only_when_collides": { "value": "True" }, "retraction_hop_only_when_collides": { "value": "True" },
@ -157,7 +141,6 @@
"switch_extruder_prime_speed": { "value": "15" }, "switch_extruder_prime_speed": { "value": "15" },
"switch_extruder_retraction_amount": { "value": "8" }, "switch_extruder_retraction_amount": { "value": "8" },
"top_bottom_thickness": { "value": "1" }, "top_bottom_thickness": { "value": "1" },
"travel_avoid_supports": { "value": "True" },
"travel_avoid_distance": { "value": "3 if extruders_enabled_count > 1 else machine_nozzle_tip_outer_diameter / 2 * 1.5" }, "travel_avoid_distance": { "value": "3 if extruders_enabled_count > 1 else machine_nozzle_tip_outer_diameter / 2 * 1.5" },
"wall_0_inset": { "value": "0" }, "wall_0_inset": { "value": "0" },
"optimize_wall_printing_order": { "value": "True" }, "optimize_wall_printing_order": { "value": "True" },

View File

@ -138,7 +138,6 @@
"machine_height": {"default_value": 250}, "machine_height": {"default_value": 250},
"machine_extruder_count": {"value": 2}, "machine_extruder_count": {"value": 2},
"machine_buildplate_type": {"value": "glass"}, "machine_buildplate_type": {"value": "glass"},
"machine_heated_bed": {"default_value": true},
"machine_center_is_zero": {"default_value": false}, "machine_center_is_zero": {"default_value": false},
"machine_gcode_flavor": {"default_value": "RepRap (Marlin/Sprinter)"}, "machine_gcode_flavor": {"default_value": "RepRap (Marlin/Sprinter)"},
"machine_head_with_fans_polygon": {"default_value": [ "machine_head_with_fans_polygon": {"default_value": [

View File

@ -98,8 +98,9 @@
"machine_start_gcode": { "default_value": "print_start" }, "machine_start_gcode": { "default_value": "print_start" },
"machine_end_gcode": { "default_value": "print_end" }, "machine_end_gcode": { "default_value": "print_end" },
"adhesion_type": { "default_value": "skirt" }, "adhesion_type": { "default_value": "skirt" },
"retraction_amount": { "default_value": 0.75 },
"skirt_brim_minimal_length": { "default_value": 550 }, "skirt_brim_minimal_length": { "default_value": 550 },
"retraction_speed": { "default_value": 80, "maximum_value_warning": 130 }, "retraction_speed": { "default_value": 30, "maximum_value_warning": 130 },
"retraction_retract_speed": { "maximum_value_warning": 130 }, "retraction_retract_speed": { "maximum_value_warning": 130 },
"retraction_prime_speed": { "value": "math.ceil(retraction_speed * 0.4)", "maximum_value_warning": 130 }, "retraction_prime_speed": { "value": "math.ceil(retraction_speed * 0.4)", "maximum_value_warning": 130 },
"retraction_hop_enabled": { "default_value": true }, "retraction_hop_enabled": { "default_value": true },

View File

@ -147,7 +147,6 @@
"machine_height": {"default_value": 270}, "machine_height": {"default_value": 270},
"machine_extruder_count": {"value": 1}, "machine_extruder_count": {"value": 1},
"machine_buildplate_type": {"value": "glass"}, "machine_buildplate_type": {"value": "glass"},
"machine_heated_bed": {"default_value": true},
"machine_center_is_zero": {"default_value": false}, "machine_center_is_zero": {"default_value": false},
"machine_gcode_flavor": {"default_value": "RepRap (Marlin/Sprinter)"}, "machine_gcode_flavor": {"default_value": "RepRap (Marlin/Sprinter)"},
"machine_head_with_fans_polygon": {"default_value": [ "machine_head_with_fans_polygon": {"default_value": [

View File

@ -22,11 +22,6 @@ top_bottom_thickness = 0.8
infill_sparse_density = 15 infill_sparse_density = 15
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -16,12 +16,6 @@ is_experimental = True
infill_sparse_density = 10 infill_sparse_density = 10
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
acceleration_print = 4000 acceleration_print = 4000
acceleration_wall = 2000 acceleration_wall = 2000

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -22,11 +22,6 @@ top_bottom_thickness = 0.8
infill_sparse_density = 15 infill_sparse_density = 15
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -22,11 +22,6 @@ top_bottom_thickness = 0.8
infill_sparse_density = 15 infill_sparse_density = 15
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -16,12 +16,6 @@ is_experimental = True
infill_sparse_density = 10 infill_sparse_density = 10
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
acceleration_print = 4000 acceleration_print = 4000
acceleration_wall = 2000 acceleration_wall = 2000

View File

@ -22,11 +22,6 @@ top_bottom_thickness = 0.8
infill_sparse_density = 15 infill_sparse_density = 15
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -14,12 +14,6 @@ variant = AA 0.4
[values] [values]
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
speed_print = 30 speed_print = 30
speed_infill = =speed_print speed_infill = =speed_print

View File

@ -16,12 +16,6 @@ is_experimental = True
infill_sparse_density = 10 infill_sparse_density = 10
jerk_print = 30 jerk_print = 30
jerk_infill = =jerk_print
jerk_topbottom = =jerk_print
jerk_wall = =jerk_print
jerk_wall_0 = =jerk_wall
jerk_wall_x = =jerk_wall
jerk_layer_0 = 5
acceleration_print = 4000 acceleration_print = 4000
acceleration_wall = 2000 acceleration_wall = 2000

View File

@ -29,7 +29,7 @@ UM.Dialog
// the size of the dialog ourselves. // the size of the dialog ourselves.
// Ugly workaround for windows having overlapping elements due to incorrect dialog width // Ugly workaround for windows having overlapping elements due to incorrect dialog width
minimumWidth: content.width + (Qt.platform.os == "windows" ? 4 * margin : 2 * margin) minimumWidth: content.width + (Qt.platform.os == "windows" ? 4 * margin : 2 * margin)
minimumHeight: content.height + buttonArea.height + (Qt.platform.os == "windows" ? 5 * margin : 3 * margin) minimumHeight: content.height + footer.height + (Qt.platform.os == "windows" ? 5 * margin : 3 * margin)
property alias color: colorInput.text property alias color: colorInput.text
property var swatchColors: [ property var swatchColors: [

View File

@ -67,6 +67,8 @@ UM.TooltipArea
font: UM.Theme.getFont("fixed") font: UM.Theme.getFont("fixed")
renderType: Text.NativeRendering renderType: Text.NativeRendering
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
selectionColor: UM.Theme.getColor("text_selection")
selectedTextColor: UM.Theme.getColor("text")
wrapMode: TextEdit.NoWrap wrapMode: TextEdit.NoWrap
onActiveFocusChanged: onActiveFocusChanged:
@ -91,7 +93,7 @@ UM.TooltipArea
} }
if (gcodeTextArea.hovered || gcodeTextArea.activeFocus) if (gcodeTextArea.hovered || gcodeTextArea.activeFocus)
{ {
return UM.Theme.getColor("border_main") return UM.Theme.getColor("text_field_border_active")
} }
return UM.Theme.getColor("border_field_light") return UM.Theme.getColor("border_field_light")
} }

View File

@ -39,8 +39,7 @@ jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25) jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10) jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -29,18 +29,8 @@ cool_min_speed = 20
infill_overlap = 0 infill_overlap = 0
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'cubic' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'cubic'
infill_wipe_dist = 0 infill_wipe_dist = 0
jerk_enabled = True
jerk_layer_0 = =jerk_topbottom
jerk_prime_tower = =math.ceil(jerk_print * 15 / 25)
jerk_print = 25
jerk_support = =math.ceil(jerk_print * 15 / 25)
jerk_support_interface = =jerk_topbottom
jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -29,18 +29,8 @@ cool_min_speed = 20
infill_overlap = 0 infill_overlap = 0
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'cubic' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'cubic'
infill_wipe_dist = 0 infill_wipe_dist = 0
jerk_enabled = True
jerk_layer_0 = =jerk_topbottom
jerk_prime_tower = =math.ceil(jerk_print * 15 / 25)
jerk_print = 25
jerk_support = =math.ceil(jerk_print * 15 / 25)
jerk_support_interface = =jerk_topbottom
jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -39,8 +39,7 @@ jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25) jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10) jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -29,18 +29,8 @@ cool_min_speed = 20
infill_overlap = 0 infill_overlap = 0
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'cubic' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'cubic'
infill_wipe_dist = 0 infill_wipe_dist = 0
jerk_enabled = True
jerk_layer_0 = =jerk_topbottom
jerk_prime_tower = =math.ceil(jerk_print * 15 / 25)
jerk_print = 25
jerk_support = =math.ceil(jerk_print * 15 / 25)
jerk_support_interface = =jerk_topbottom
jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -39,8 +39,7 @@ jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25) jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10) jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -25,6 +25,7 @@ raft_base_line_spacing = 1
raft_interface_line_spacing = 1 raft_interface_line_spacing = 1
raft_interface_line_width = 0.2 raft_interface_line_width = 0.2
raft_surface_line_width = 0.2 raft_surface_line_width = 0.2
retraction_count_max = 15
retraction_hop_enabled = 0.2 retraction_hop_enabled = 0.2
speed_layer_0 = =math.ceil(speed_print * 30 / 40) speed_layer_0 = =math.ceil(speed_print * 30 / 40)
speed_print = 40 speed_print = 40

View File

@ -23,6 +23,7 @@ raft_base_line_spacing = 2
raft_base_line_width = 0.8 raft_base_line_width = 0.8
raft_interface_line_spacing = 1 raft_interface_line_spacing = 1
raft_margin = 12 raft_margin = 12
retraction_count_max = 15
retraction_hop_enabled = 0.2 retraction_hop_enabled = 0.2
speed_layer_0 = =math.ceil(speed_print * 30 / 40) speed_layer_0 = =math.ceil(speed_print * 30 / 40)
speed_print = 40 speed_print = 40

View File

@ -26,6 +26,7 @@ raft_interface_line_spacing = 1.2
raft_interface_line_width = 0.57 raft_interface_line_width = 0.57
raft_margin = 15 raft_margin = 15
raft_surface_line_width = 0.5 raft_surface_line_width = 0.5
retraction_count_max = 15
retraction_hop_enabled = 0.2 retraction_hop_enabled = 0.2
speed_layer_0 = =math.ceil(speed_print * 30 / 45) speed_layer_0 = =math.ceil(speed_print * 30 / 45)
speed_print = 45 speed_print = 45

View File

@ -29,18 +29,8 @@ cool_min_speed = 20
infill_overlap = 0 infill_overlap = 0
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral'
infill_wipe_dist = 0 infill_wipe_dist = 0
jerk_enabled = True
jerk_layer_0 = =jerk_topbottom
jerk_prime_tower = =math.ceil(jerk_print * 15 / 25)
jerk_print = 25
jerk_support = =math.ceil(jerk_print * 15 / 25)
jerk_support_interface = =jerk_topbottom
jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -29,18 +29,8 @@ cool_min_speed = 20
infill_overlap = 0 infill_overlap = 0
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral'
infill_wipe_dist = 0 infill_wipe_dist = 0
jerk_enabled = True
jerk_layer_0 = =jerk_topbottom
jerk_prime_tower = =math.ceil(jerk_print * 15 / 25)
jerk_print = 25
jerk_support = =math.ceil(jerk_print * 15 / 25)
jerk_support_interface = =jerk_topbottom
jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -29,18 +29,8 @@ cool_min_speed = 20
infill_overlap = 0 infill_overlap = 0
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral'
infill_wipe_dist = 0 infill_wipe_dist = 0
jerk_enabled = True
jerk_layer_0 = =jerk_topbottom
jerk_prime_tower = =math.ceil(jerk_print * 15 / 25)
jerk_print = 25
jerk_support = =math.ceil(jerk_print * 15 / 25)
jerk_support_interface = =jerk_topbottom
jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -29,18 +29,8 @@ cool_min_speed = 20
infill_overlap = 0 infill_overlap = 0
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral'
infill_wipe_dist = 0 infill_wipe_dist = 0
jerk_enabled = True
jerk_layer_0 = =jerk_topbottom
jerk_prime_tower = =math.ceil(jerk_print * 15 / 25)
jerk_print = 25
jerk_support = =math.ceil(jerk_print * 15 / 25)
jerk_support_interface = =jerk_topbottom
jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -39,8 +39,7 @@ jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25) jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10) jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -29,18 +29,8 @@ cool_min_speed = 20
infill_overlap = 0 infill_overlap = 0
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'tetrahedral'
infill_wipe_dist = 0 infill_wipe_dist = 0
jerk_enabled = True
jerk_layer_0 = =jerk_topbottom
jerk_prime_tower = =math.ceil(jerk_print * 15 / 25)
jerk_print = 25
jerk_support = =math.ceil(jerk_print * 15 / 25)
jerk_support_interface = =jerk_topbottom
jerk_topbottom = =math.ceil(jerk_print * 5 / 25)
jerk_wall = =math.ceil(jerk_print * 10 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 5 / 10)
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
retraction_count_max = 12 retraction_count_max = 15
retraction_extrusion_window = 1
retraction_hop = 0.15 retraction_hop = 0.15
retraction_hop_enabled = True retraction_hop_enabled = True
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True

View File

@ -25,6 +25,7 @@ raft_base_line_spacing = 1
raft_interface_line_spacing = 1 raft_interface_line_spacing = 1
raft_interface_line_width = 0.2 raft_interface_line_width = 0.2
raft_surface_line_width = 0.2 raft_surface_line_width = 0.2
retraction_count_max = 15
retraction_hop_enabled = 0.2 retraction_hop_enabled = 0.2
speed_layer_0 = =math.ceil(speed_print * 30 / 40) speed_layer_0 = =math.ceil(speed_print * 30 / 40)
speed_print = 40 speed_print = 40

View File

@ -23,6 +23,7 @@ raft_base_line_spacing = 2
raft_base_line_width = 0.8 raft_base_line_width = 0.8
raft_interface_line_spacing = 1 raft_interface_line_spacing = 1
raft_margin = 12 raft_margin = 12
retraction_count_max = 15
retraction_hop_enabled = 0.2 retraction_hop_enabled = 0.2
speed_layer_0 = =math.ceil(speed_print * 30 / 40) speed_layer_0 = =math.ceil(speed_print * 30 / 40)
speed_print = 40 speed_print = 40

View File

@ -26,6 +26,7 @@ raft_interface_line_spacing = 1.2
raft_interface_line_width = 0.57 raft_interface_line_width = 0.57
raft_margin = 15 raft_margin = 15
raft_surface_line_width = 0.5 raft_surface_line_width = 0.5
retraction_count_max = 15
retraction_hop_enabled = 0.2 retraction_hop_enabled = 0.2
speed_layer_0 = =math.ceil(speed_print * 30 / 45) speed_layer_0 = =math.ceil(speed_print * 30 / 45)
speed_print = 45 speed_print = 45

View File

@ -12,7 +12,6 @@ material = generic_cpe
variant = AA 0.25 variant = AA 0.25
[values] [values]
retraction_extrusion_window = 0.5
speed_infill = =math.ceil(speed_print * 40 / 55) speed_infill = =math.ceil(speed_print * 40 / 55)
speed_topbottom = =math.ceil(speed_print * 30 / 55) speed_topbottom = =math.ceil(speed_print * 30 / 55)
top_bottom_thickness = 0.8 top_bottom_thickness = 0.8

View File

@ -21,7 +21,6 @@ cool_min_layer_time_fan_speed_max = 5
cool_min_speed = 5 cool_min_speed = 5
infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles' infill_pattern = ='zigzag' if infill_sparse_density > 80 else 'triangles'
infill_wipe_dist = 0.1 infill_wipe_dist = 0.1
jerk_enabled = True
jerk_print = 25 jerk_print = 25
machine_min_cool_heat_time_window = 15 machine_min_cool_heat_time_window = 15
multiple_mesh_overlap = 0 multiple_mesh_overlap = 0
@ -30,7 +29,6 @@ prime_tower_enable = True
prime_tower_wipe_enabled = True prime_tower_wipe_enabled = True
raft_airgap = 0.25 raft_airgap = 0.25
raft_interface_thickness = =max(layer_height * 1.5, 0.225) raft_interface_thickness = =max(layer_height * 1.5, 0.225)
retraction_count_max = 80
retraction_hop = 2 retraction_hop = 2
retraction_hop_only_when_collides = True retraction_hop_only_when_collides = True
retraction_min_travel = 0.8 retraction_min_travel = 0.8

Some files were not shown because too many files have changed in this diff Show More