mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-16 11:17:49 -06:00
Merge branch 'master' of github.com:Ultimaker/Cura into qtquick-controls-2.0
This commit is contained in:
commit
7d28b26ff2
446 changed files with 4278 additions and 1340 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -42,6 +42,7 @@ plugins/FlatProfileExporter
|
||||||
plugins/ProfileFlattener
|
plugins/ProfileFlattener
|
||||||
plugins/cura-god-mode-plugin
|
plugins/cura-god-mode-plugin
|
||||||
plugins/cura-big-flame-graph
|
plugins/cura-big-flame-graph
|
||||||
|
plugins/cura-siemensnx-plugin
|
||||||
|
|
||||||
#Build stuff
|
#Build stuff
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
|
|
|
@ -10,6 +10,6 @@ TryExec=@CMAKE_INSTALL_FULL_BINDIR@/cura
|
||||||
Icon=cura-icon
|
Icon=cura-icon
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
MimeType=application/sla;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;
|
MimeType=application/sla;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;image/bmp;image/gif;image/jpeg;image/png;model/x3d+xml;
|
||||||
Categories=Graphics;
|
Categories=Graphics;
|
||||||
Keywords=3D;Printing;
|
Keywords=3D;Printing;
|
||||||
|
|
|
@ -12,8 +12,8 @@ class CameraAnimation(QVariantAnimation):
|
||||||
def __init__(self, parent = None):
|
def __init__(self, parent = None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._camera_tool = None
|
self._camera_tool = None
|
||||||
self.setDuration(500)
|
self.setDuration(300)
|
||||||
self.setEasingCurve(QEasingCurve.InOutQuad)
|
self.setEasingCurve(QEasingCurve.OutQuad)
|
||||||
|
|
||||||
def setCameraTool(self, camera_tool):
|
def setCameraTool(self, camera_tool):
|
||||||
self._camera_tool = camera_tool
|
self._camera_tool = camera_tool
|
||||||
|
|
|
@ -1,18 +1,28 @@
|
||||||
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import platform
|
import platform
|
||||||
import traceback
|
import traceback
|
||||||
import webbrowser
|
|
||||||
import faulthandler
|
import faulthandler
|
||||||
import tempfile
|
import tempfile
|
||||||
import os
|
import os
|
||||||
import urllib
|
import os.path
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import ssl
|
||||||
|
import urllib.request
|
||||||
|
import urllib.error
|
||||||
|
|
||||||
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, Qt, QCoreApplication
|
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QCoreApplication
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox
|
||||||
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QHBoxLayout, QVBoxLayout, QLabel, QTextEdit
|
|
||||||
|
|
||||||
|
from UM.Application import Application
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
from UM.View.GL.OpenGL import OpenGL
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
from UM.Platform import Platform
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
MYPY = False
|
MYPY = False
|
||||||
|
@ -35,83 +45,240 @@ fatal_exception_types = [
|
||||||
SystemError,
|
SystemError,
|
||||||
]
|
]
|
||||||
|
|
||||||
def show(exception_type, value, tb):
|
|
||||||
Logger.log("c", "An uncaught exception has occurred!")
|
|
||||||
for line in traceback.format_exception(exception_type, value, tb):
|
|
||||||
for part in line.rstrip("\n").split("\n"):
|
|
||||||
Logger.log("c", part)
|
|
||||||
|
|
||||||
if not CuraDebugMode and exception_type not in fatal_exception_types:
|
class CrashHandler:
|
||||||
return
|
crash_url = "https://stats.ultimaker.com/api/cura"
|
||||||
|
|
||||||
application = QCoreApplication.instance()
|
def __init__(self, exception_type, value, tb):
|
||||||
if not application:
|
self.exception_type = exception_type
|
||||||
sys.exit(1)
|
self.value = value
|
||||||
|
self.traceback = tb
|
||||||
|
self.dialog = QDialog()
|
||||||
|
|
||||||
dialog = QDialog()
|
# While we create the GUI, the information will be stored for sending afterwards
|
||||||
dialog.setMinimumWidth(640)
|
self.data = dict()
|
||||||
dialog.setMinimumHeight(640)
|
self.data["time_stamp"] = time.time()
|
||||||
dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))
|
|
||||||
|
|
||||||
layout = QVBoxLayout(dialog)
|
Logger.log("c", "An uncaught exception has occurred!")
|
||||||
|
for line in traceback.format_exception(exception_type, value, tb):
|
||||||
|
for part in line.rstrip("\n").split("\n"):
|
||||||
|
Logger.log("c", part)
|
||||||
|
|
||||||
#label = QLabel(dialog)
|
if not CuraDebugMode and exception_type not in fatal_exception_types:
|
||||||
#pixmap = QPixmap()
|
return
|
||||||
#try:
|
|
||||||
# data = urllib.request.urlopen("http://www.randomkittengenerator.com/cats/rotator.php").read()
|
|
||||||
# pixmap.loadFromData(data)
|
|
||||||
#except:
|
|
||||||
# try:
|
|
||||||
# from UM.Resources import Resources
|
|
||||||
# path = Resources.getPath(Resources.Images, "kitten.jpg")
|
|
||||||
# pixmap.load(path)
|
|
||||||
# except:
|
|
||||||
# pass
|
|
||||||
#pixmap = pixmap.scaled(150, 150)
|
|
||||||
#label.setPixmap(pixmap)
|
|
||||||
#label.setAlignment(Qt.AlignCenter)
|
|
||||||
#layout.addWidget(label)
|
|
||||||
|
|
||||||
label = QLabel(dialog)
|
application = QCoreApplication.instance()
|
||||||
layout.addWidget(label)
|
if not application:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
#label.setScaledContents(True)
|
self._createDialog()
|
||||||
label.setText(catalog.i18nc("@label", """<p>A fatal exception has occurred that we could not recover from!</p>
|
|
||||||
<p>Please use the information below to post a bug report at <a href=\"http://github.com/Ultimaker/Cura/issues\">http://github.com/Ultimaker/Cura/issues</a></p>
|
|
||||||
"""))
|
|
||||||
|
|
||||||
textarea = QTextEdit(dialog)
|
## Creates a modal dialog.
|
||||||
layout.addWidget(textarea)
|
def _createDialog(self):
|
||||||
|
self.dialog.setMinimumWidth(640)
|
||||||
|
self.dialog.setMinimumHeight(640)
|
||||||
|
self.dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))
|
||||||
|
|
||||||
try:
|
layout = QVBoxLayout(self.dialog)
|
||||||
from UM.Application import Application
|
|
||||||
version = Application.getInstance().getVersion()
|
|
||||||
except:
|
|
||||||
version = "Unknown"
|
|
||||||
|
|
||||||
trace = "".join(traceback.format_exception(exception_type, value, tb))
|
layout.addWidget(self._messageWidget())
|
||||||
|
layout.addWidget(self._informationWidget())
|
||||||
|
layout.addWidget(self._exceptionInfoWidget())
|
||||||
|
layout.addWidget(self._logInfoWidget())
|
||||||
|
layout.addWidget(self._userDescriptionWidget())
|
||||||
|
layout.addWidget(self._buttonsWidget())
|
||||||
|
|
||||||
crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}"
|
def _messageWidget(self):
|
||||||
crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace)
|
label = QLabel()
|
||||||
|
label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal exception has occurred. Please send us this Crash Report to fix the problem</p></b>
|
||||||
|
<p>Please use the "Send report" button to post a bug report automatically to our servers</p>
|
||||||
|
"""))
|
||||||
|
|
||||||
tmp_file_fd, tmp_file_path = tempfile.mkstemp(prefix = "cura-crash", text = True)
|
return label
|
||||||
os.close(tmp_file_fd)
|
|
||||||
with open(tmp_file_path, "w") as f:
|
|
||||||
faulthandler.dump_traceback(f, all_threads=True)
|
|
||||||
with open(tmp_file_path, "r") as f:
|
|
||||||
data = f.read()
|
|
||||||
|
|
||||||
msg = "-------------------------\n"
|
def _informationWidget(self):
|
||||||
msg += data
|
group = QGroupBox()
|
||||||
crash_info += "\n\n" + msg
|
group.setTitle(catalog.i18nc("@title:groupbox", "System information"))
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
label = QLabel()
|
||||||
|
|
||||||
textarea.setText(crash_info)
|
try:
|
||||||
|
from UM.Application import Application
|
||||||
|
self.cura_version = Application.getInstance().getVersion()
|
||||||
|
except:
|
||||||
|
self.cura_version = catalog.i18nc("@label unknown version of Cura", "Unknown")
|
||||||
|
|
||||||
buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog)
|
crash_info = catalog.i18nc("@label Cura version", "<b>Cura version:</b> {version}<br/>").format(version = self.cura_version)
|
||||||
layout.addWidget(buttons)
|
crash_info += catalog.i18nc("@label Platform", "<b>Platform:</b> {platform}<br/>").format(platform = platform.platform())
|
||||||
buttons.addButton(catalog.i18nc("@action:button", "Open Web Page"), QDialogButtonBox.HelpRole)
|
crash_info += catalog.i18nc("@label Qt version", "<b>Qt version:</b> {qt}<br/>").format(qt = QT_VERSION_STR)
|
||||||
buttons.rejected.connect(dialog.close)
|
crash_info += catalog.i18nc("@label PyQt version", "<b>PyQt version:</b> {pyqt}<br/>").format(pyqt = PYQT_VERSION_STR)
|
||||||
buttons.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues"))
|
crash_info += catalog.i18nc("@label OpenGL", "<b>OpenGL:</b> {opengl}<br/>").format(opengl = self._getOpenGLInfo())
|
||||||
|
label.setText(crash_info)
|
||||||
|
|
||||||
dialog.exec_()
|
layout.addWidget(label)
|
||||||
sys.exit(1)
|
group.setLayout(layout)
|
||||||
|
|
||||||
|
self.data["cura_version"] = self.cura_version
|
||||||
|
self.data["os"] = {"type": platform.system(), "version": platform.version()}
|
||||||
|
self.data["qt_version"] = QT_VERSION_STR
|
||||||
|
self.data["pyqt_version"] = PYQT_VERSION_STR
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
||||||
|
def _getOpenGLInfo(self):
|
||||||
|
info = "<ul>"
|
||||||
|
info += catalog.i18nc("@label OpenGL version", "<li>OpenGL Version: {version}</li>").format(version = OpenGL.getInstance().getOpenGLVersion())
|
||||||
|
info += catalog.i18nc("@label OpenGL vendor", "<li>OpenGL Vendor: {vendor}</li>").format(vendor = OpenGL.getInstance().getGPUVendorName())
|
||||||
|
info += catalog.i18nc("@label OpenGL renderer", "<li>OpenGL Renderer: {renderer}</li>").format(renderer = OpenGL.getInstance().getGPUType())
|
||||||
|
info += "</ul>"
|
||||||
|
|
||||||
|
self.data["opengl"] = {"version": OpenGL.getInstance().getOpenGLVersion(), "vendor": OpenGL.getInstance().getGPUVendorName(), "type": OpenGL.getInstance().getGPUType()}
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
def _exceptionInfoWidget(self):
|
||||||
|
group = QGroupBox()
|
||||||
|
group.setTitle(catalog.i18nc("@title:groupbox", "Exception traceback"))
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
text_area = QTextEdit()
|
||||||
|
trace_dict = traceback.format_exception(self.exception_type, self.value, self.traceback)
|
||||||
|
trace = "".join(trace_dict)
|
||||||
|
text_area.setText(trace)
|
||||||
|
text_area.setReadOnly(True)
|
||||||
|
|
||||||
|
layout.addWidget(text_area)
|
||||||
|
group.setLayout(layout)
|
||||||
|
|
||||||
|
# Parsing all the information to fill the dictionary
|
||||||
|
summary = trace_dict[len(trace_dict)-1].rstrip("\n")
|
||||||
|
module = trace_dict[len(trace_dict)-2].rstrip("\n").split("\n")
|
||||||
|
module_split = module[0].split(", ")
|
||||||
|
filepath = module_split[0].split("\"")[1]
|
||||||
|
directory, filename = os.path.split(filepath)
|
||||||
|
line = int(module_split[1].lstrip("line "))
|
||||||
|
function = module_split[2].lstrip("in ")
|
||||||
|
code = module[1].lstrip(" ")
|
||||||
|
|
||||||
|
# Using this workaround for a cross-platform path splitting
|
||||||
|
split_path = []
|
||||||
|
folder_name = ""
|
||||||
|
# Split until reach folder "cura"
|
||||||
|
while folder_name != "cura":
|
||||||
|
directory, folder_name = os.path.split(directory)
|
||||||
|
if not folder_name:
|
||||||
|
break
|
||||||
|
split_path.append(folder_name)
|
||||||
|
|
||||||
|
# Look for plugins. If it's not a plugin, the current cura version is set
|
||||||
|
isPlugin = False
|
||||||
|
module_version = self.cura_version
|
||||||
|
module_name = "Cura"
|
||||||
|
if split_path.__contains__("plugins"):
|
||||||
|
isPlugin = True
|
||||||
|
# Look backwards until plugin.json is found
|
||||||
|
directory, name = os.path.split(filepath)
|
||||||
|
while not os.listdir(directory).__contains__("plugin.json"):
|
||||||
|
directory, name = os.path.split(directory)
|
||||||
|
|
||||||
|
json_metadata_file = os.path.join(directory, "plugin.json")
|
||||||
|
try:
|
||||||
|
with open(json_metadata_file, "r") as f:
|
||||||
|
try:
|
||||||
|
metadata = json.loads(f.read())
|
||||||
|
module_version = metadata["version"]
|
||||||
|
module_name = metadata["name"]
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
# Not throw new exceptions
|
||||||
|
Logger.logException("e", "Failed to parse plugin.json for plugin %s", name)
|
||||||
|
except:
|
||||||
|
# Not throw new exceptions
|
||||||
|
pass
|
||||||
|
|
||||||
|
exception_dict = dict()
|
||||||
|
exception_dict["traceback"] = {"summary": summary, "full_trace": trace}
|
||||||
|
exception_dict["location"] = {"path": filepath, "file": filename, "function": function, "code": code, "line": line,
|
||||||
|
"module_name": module_name, "version": module_version, "is_plugin": isPlugin}
|
||||||
|
self.data["exception"] = exception_dict
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
||||||
|
def _logInfoWidget(self):
|
||||||
|
group = QGroupBox()
|
||||||
|
group.setTitle(catalog.i18nc("@title:groupbox", "Logs"))
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
text_area = QTextEdit()
|
||||||
|
tmp_file_fd, tmp_file_path = tempfile.mkstemp(prefix = "cura-crash", text = True)
|
||||||
|
os.close(tmp_file_fd)
|
||||||
|
with open(tmp_file_path, "w") as f:
|
||||||
|
faulthandler.dump_traceback(f, all_threads=True)
|
||||||
|
with open(tmp_file_path, "r") as f:
|
||||||
|
logdata = f.read()
|
||||||
|
|
||||||
|
text_area.setText(logdata)
|
||||||
|
text_area.setReadOnly(True)
|
||||||
|
|
||||||
|
layout.addWidget(text_area)
|
||||||
|
group.setLayout(layout)
|
||||||
|
|
||||||
|
self.data["log"] = logdata
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
||||||
|
def _userDescriptionWidget(self):
|
||||||
|
group = QGroupBox()
|
||||||
|
group.setTitle(catalog.i18nc("@title:groupbox", "User description"))
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
# When sending the report, the user comments will be collected
|
||||||
|
self.user_description_text_area = QTextEdit()
|
||||||
|
self.user_description_text_area.setFocus(True)
|
||||||
|
|
||||||
|
layout.addWidget(self.user_description_text_area)
|
||||||
|
group.setLayout(layout)
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
||||||
|
def _buttonsWidget(self):
|
||||||
|
buttons = QDialogButtonBox()
|
||||||
|
buttons.addButton(QDialogButtonBox.Close)
|
||||||
|
buttons.addButton(catalog.i18nc("@action:button", "Send report"), QDialogButtonBox.AcceptRole)
|
||||||
|
buttons.rejected.connect(self.dialog.close)
|
||||||
|
buttons.accepted.connect(self._sendCrashReport)
|
||||||
|
|
||||||
|
return buttons
|
||||||
|
|
||||||
|
def _sendCrashReport(self):
|
||||||
|
# Before sending data, the user comments are stored
|
||||||
|
self.data["user_info"] = self.user_description_text_area.toPlainText()
|
||||||
|
|
||||||
|
# Convert data to bytes
|
||||||
|
binary_data = json.dumps(self.data).encode("utf-8")
|
||||||
|
|
||||||
|
# Submit data
|
||||||
|
kwoptions = {"data": binary_data, "timeout": 5}
|
||||||
|
|
||||||
|
if Platform.isOSX():
|
||||||
|
kwoptions["context"] = ssl._create_unverified_context()
|
||||||
|
|
||||||
|
Logger.log("i", "Sending crash report info to [%s]...", self.crash_url)
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = urllib.request.urlopen(self.crash_url, **kwoptions)
|
||||||
|
Logger.log("i", "Sent crash report info.")
|
||||||
|
f.close()
|
||||||
|
except urllib.error.HTTPError:
|
||||||
|
Logger.logException("e", "An HTTP error occurred while trying to send crash report")
|
||||||
|
except Exception: # We don't want any exception to cause problems
|
||||||
|
Logger.logException("e", "An exception occurred while trying to send crash report")
|
||||||
|
|
||||||
|
os._exit(1)
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
# must run the GUI code on the Qt thread, otherwise the widgets on the dialog won't react correctly.
|
||||||
|
Application.getInstance().callLater(self._show)
|
||||||
|
|
||||||
|
def _show(self):
|
||||||
|
self.dialog.exec_()
|
||||||
|
os._exit(1)
|
||||||
|
|
|
@ -51,6 +51,7 @@ from cura.Settings.MaterialsModel import MaterialsModel
|
||||||
from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesModel
|
from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesModel
|
||||||
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
||||||
from cura.Settings.UserProfilesModel import UserProfilesModel
|
from cura.Settings.UserProfilesModel import UserProfilesModel
|
||||||
|
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
||||||
|
|
||||||
from . import PlatformPhysics
|
from . import PlatformPhysics
|
||||||
from . import BuildVolume
|
from . import BuildVolume
|
||||||
|
@ -104,7 +105,7 @@ class CuraApplication(QtApplication):
|
||||||
# SettingVersion represents the set of settings available in the machine/extruder definitions.
|
# SettingVersion represents the set of settings available in the machine/extruder definitions.
|
||||||
# You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
|
# You need to make sure that this version number needs to be increased if there is any non-backwards-compatible
|
||||||
# changes of the settings.
|
# changes of the settings.
|
||||||
SettingVersion = 3
|
SettingVersion = 4
|
||||||
|
|
||||||
class ResourceTypes:
|
class ResourceTypes:
|
||||||
QmlFiles = Resources.UserType + 1
|
QmlFiles = Resources.UserType + 1
|
||||||
|
@ -125,6 +126,8 @@ class CuraApplication(QtApplication):
|
||||||
# Cura will always show the Add Machine Dialog upon start.
|
# Cura will always show the Add Machine Dialog upon start.
|
||||||
stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished
|
stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished
|
||||||
|
|
||||||
|
projectFileLoaded = pyqtSignal(str) # Emitted whenever a project file is loaded
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# this list of dir names will be used by UM to detect an old cura directory
|
# this list of dir names will be used by UM to detect an old cura directory
|
||||||
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
|
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
|
||||||
|
@ -199,6 +202,7 @@ class CuraApplication(QtApplication):
|
||||||
self._machine_manager = None # This is initialized on demand.
|
self._machine_manager = None # This is initialized on demand.
|
||||||
self._material_manager = None
|
self._material_manager = None
|
||||||
self._setting_inheritance_manager = None
|
self._setting_inheritance_manager = None
|
||||||
|
self._simple_mode_settings_manager = None
|
||||||
|
|
||||||
self._additional_components = {} # Components to add to certain areas in the interface
|
self._additional_components = {} # Components to add to certain areas in the interface
|
||||||
|
|
||||||
|
@ -211,6 +215,7 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
self.setRequiredPlugins([
|
self.setRequiredPlugins([
|
||||||
"CuraEngineBackend",
|
"CuraEngineBackend",
|
||||||
|
"UserAgreement",
|
||||||
"SolidView",
|
"SolidView",
|
||||||
"LayerView",
|
"LayerView",
|
||||||
"STLReader",
|
"STLReader",
|
||||||
|
@ -266,8 +271,9 @@ class CuraApplication(QtApplication):
|
||||||
empty_quality_container = copy.deepcopy(empty_container)
|
empty_quality_container = copy.deepcopy(empty_container)
|
||||||
empty_quality_container._id = "empty_quality"
|
empty_quality_container._id = "empty_quality"
|
||||||
empty_quality_container.setName("Not Supported")
|
empty_quality_container.setName("Not Supported")
|
||||||
empty_quality_container.addMetaDataEntry("quality_type", "normal")
|
empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
||||||
empty_quality_container.addMetaDataEntry("type", "quality")
|
empty_quality_container.addMetaDataEntry("type", "quality")
|
||||||
|
empty_quality_container.addMetaDataEntry("supported", False)
|
||||||
ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
||||||
empty_quality_changes_container = copy.deepcopy(empty_container)
|
empty_quality_changes_container = copy.deepcopy(empty_container)
|
||||||
empty_quality_changes_container._id = "empty_quality_changes"
|
empty_quality_changes_container._id = "empty_quality_changes"
|
||||||
|
@ -299,6 +305,8 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
preferences.addPreference("view/invert_zoom", False)
|
preferences.addPreference("view/invert_zoom", False)
|
||||||
|
|
||||||
|
self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
|
||||||
|
|
||||||
for key in [
|
for key in [
|
||||||
"dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin
|
"dialog_load_path", # dialog_save_path is in LocalFileOutputDevicePlugin
|
||||||
"dialog_profile_path",
|
"dialog_profile_path",
|
||||||
|
@ -371,6 +379,14 @@ class CuraApplication(QtApplication):
|
||||||
def _onEngineCreated(self):
|
def _onEngineCreated(self):
|
||||||
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
||||||
|
|
||||||
|
@pyqtProperty(bool)
|
||||||
|
def needToShowUserAgreement(self):
|
||||||
|
return self._need_to_show_user_agreement
|
||||||
|
|
||||||
|
|
||||||
|
def setNeedToShowUserAgreement(self, set_value = True):
|
||||||
|
self._need_to_show_user_agreement = set_value
|
||||||
|
|
||||||
## The "Quit" button click event handler.
|
## The "Quit" button click event handler.
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def closeApplication(self):
|
def closeApplication(self):
|
||||||
|
@ -389,6 +405,7 @@ class CuraApplication(QtApplication):
|
||||||
showDiscardOrKeepProfileChanges = pyqtSignal()
|
showDiscardOrKeepProfileChanges = pyqtSignal()
|
||||||
|
|
||||||
def discardOrKeepProfileChanges(self):
|
def discardOrKeepProfileChanges(self):
|
||||||
|
has_user_interaction = False
|
||||||
choice = Preferences.getInstance().getValue("cura/choice_on_profile_override")
|
choice = Preferences.getInstance().getValue("cura/choice_on_profile_override")
|
||||||
if choice == "always_discard":
|
if choice == "always_discard":
|
||||||
# don't show dialog and DISCARD the profile
|
# don't show dialog and DISCARD the profile
|
||||||
|
@ -399,6 +416,10 @@ class CuraApplication(QtApplication):
|
||||||
else:
|
else:
|
||||||
# ALWAYS ask whether to keep or discard the profile
|
# ALWAYS ask whether to keep or discard the profile
|
||||||
self.showDiscardOrKeepProfileChanges.emit()
|
self.showDiscardOrKeepProfileChanges.emit()
|
||||||
|
has_user_interaction = True
|
||||||
|
return has_user_interaction
|
||||||
|
|
||||||
|
onDiscardOrKeepProfileChangesClosed = pyqtSignal() # Used to notify other managers that the dialog was closed
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def discardOrKeepProfileChangesClosed(self, option):
|
def discardOrKeepProfileChangesClosed(self, option):
|
||||||
|
@ -406,9 +427,25 @@ class CuraApplication(QtApplication):
|
||||||
global_stack = self.getGlobalContainerStack()
|
global_stack = self.getGlobalContainerStack()
|
||||||
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
|
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
|
||||||
extruder.getTop().clear()
|
extruder.getTop().clear()
|
||||||
|
|
||||||
global_stack.getTop().clear()
|
global_stack.getTop().clear()
|
||||||
|
|
||||||
|
# if the user decided to keep settings then the user settings should be re-calculated and validated for errors
|
||||||
|
# before slicing. To ensure that slicer uses right settings values
|
||||||
|
elif option == "keep":
|
||||||
|
global_stack = self.getGlobalContainerStack()
|
||||||
|
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
|
||||||
|
user_extruder_container = extruder.getTop()
|
||||||
|
if user_extruder_container:
|
||||||
|
user_extruder_container.update()
|
||||||
|
|
||||||
|
user_global_container = global_stack.getTop()
|
||||||
|
if user_global_container:
|
||||||
|
user_global_container.update()
|
||||||
|
|
||||||
|
# notify listeners that quality has changed (after user selected discard or keep)
|
||||||
|
self.onDiscardOrKeepProfileChangesClosed.emit()
|
||||||
|
self.getMachineManager().activeQualityChanged.emit()
|
||||||
|
|
||||||
@pyqtSlot(int)
|
@pyqtSlot(int)
|
||||||
def messageBoxClosed(self, button):
|
def messageBoxClosed(self, button):
|
||||||
if self._message_box_callback:
|
if self._message_box_callback:
|
||||||
|
@ -525,6 +562,7 @@ class CuraApplication(QtApplication):
|
||||||
super().addCommandLineOptions(parser)
|
super().addCommandLineOptions(parser)
|
||||||
parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
|
parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
|
||||||
parser.add_argument("--single-instance", action="store_true", default=False)
|
parser.add_argument("--single-instance", action="store_true", default=False)
|
||||||
|
parser.add_argument("--headless", action = "store_true", default=False)
|
||||||
|
|
||||||
# Set up a local socket server which listener which coordinates single instances Curas and accepts commands.
|
# Set up a local socket server which listener which coordinates single instances Curas and accepts commands.
|
||||||
def _setUpSingleInstanceServer(self):
|
def _setUpSingleInstanceServer(self):
|
||||||
|
@ -666,18 +704,23 @@ class CuraApplication(QtApplication):
|
||||||
qmlRegisterSingletonType(MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager)
|
qmlRegisterSingletonType(MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager)
|
||||||
qmlRegisterSingletonType(MaterialManager, "Cura", 1, 0, "MaterialManager", self.getMaterialManager)
|
qmlRegisterSingletonType(MaterialManager, "Cura", 1, 0, "MaterialManager", self.getMaterialManager)
|
||||||
qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager",
|
qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager",
|
||||||
self.getSettingInheritanceManager)
|
self.getSettingInheritanceManager)
|
||||||
|
qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 2, "SimpleModeSettingsManager",
|
||||||
|
self.getSimpleModeSettingsManager)
|
||||||
|
|
||||||
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
|
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
|
||||||
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
|
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
|
||||||
self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles))
|
self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles))
|
||||||
self.initializeEngine()
|
|
||||||
|
|
||||||
if self._engine.rootObjects:
|
run_headless = self.getCommandLineOption("headless", False)
|
||||||
|
if not run_headless:
|
||||||
|
self.initializeEngine()
|
||||||
|
|
||||||
|
if run_headless or self._engine.rootObjects:
|
||||||
self.closeSplash()
|
self.closeSplash()
|
||||||
|
|
||||||
for file in self.getCommandLineOption("file", []):
|
for file_name in self.getCommandLineOption("file", []):
|
||||||
self._openFile(file)
|
self._openFile(file_name)
|
||||||
for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading.
|
for file_name in self._open_file_queue: #Open all the files that were queued up while plug-ins were loading.
|
||||||
self._openFile(file_name)
|
self._openFile(file_name)
|
||||||
|
|
||||||
|
@ -706,6 +749,11 @@ class CuraApplication(QtApplication):
|
||||||
def getMachineActionManager(self, *args):
|
def getMachineActionManager(self, *args):
|
||||||
return self._machine_action_manager
|
return self._machine_action_manager
|
||||||
|
|
||||||
|
def getSimpleModeSettingsManager(self, *args):
|
||||||
|
if self._simple_mode_settings_manager is None:
|
||||||
|
self._simple_mode_settings_manager = SimpleModeSettingsManager()
|
||||||
|
return self._simple_mode_settings_manager
|
||||||
|
|
||||||
## Handle Qt events
|
## Handle Qt events
|
||||||
def event(self, event):
|
def event(self, event):
|
||||||
if event.type() == QEvent.FileOpen:
|
if event.type() == QEvent.FileOpen:
|
||||||
|
@ -1219,6 +1267,9 @@ class CuraApplication(QtApplication):
|
||||||
# see GroupDecorator._onChildrenChanged
|
# see GroupDecorator._onChildrenChanged
|
||||||
|
|
||||||
def _createSplashScreen(self):
|
def _createSplashScreen(self):
|
||||||
|
run_headless = self.getCommandLineOption("headless", False)
|
||||||
|
if run_headless:
|
||||||
|
return None
|
||||||
return CuraSplashScreen.CuraSplashScreen()
|
return CuraSplashScreen.CuraSplashScreen()
|
||||||
|
|
||||||
def _onActiveMachineChanged(self):
|
def _onActiveMachineChanged(self):
|
||||||
|
|
|
@ -62,7 +62,7 @@ class CuraSplashScreen(QSplashScreen):
|
||||||
painter.setFont(font)
|
painter.setFont(font)
|
||||||
painter.drawText(215, 66, 330 * self._scale, 230 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[0])
|
painter.drawText(215, 66, 330 * self._scale, 230 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[0])
|
||||||
if len(version) > 1:
|
if len(version) > 1:
|
||||||
font.setPointSize(12)
|
font.setPixelSize(16)
|
||||||
painter.setFont(font)
|
painter.setFont(font)
|
||||||
painter.setPen(QColor(200, 200, 200, 255))
|
painter.setPen(QColor(200, 200, 200, 255))
|
||||||
painter.drawText(247, 105, 330 * self._scale, 255 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[1])
|
painter.drawText(247, 105, 330 * self._scale, 255 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[1])
|
||||||
|
|
57
cura/PreviewPass.py
Normal file
57
cura/PreviewPass.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
|
# Uranium is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from UM.Application import Application
|
||||||
|
from UM.Resources import Resources
|
||||||
|
|
||||||
|
from UM.View.RenderPass import RenderPass
|
||||||
|
from UM.View.GL.OpenGL import OpenGL
|
||||||
|
from UM.View.RenderBatch import RenderBatch
|
||||||
|
|
||||||
|
|
||||||
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
MYPY = False
|
||||||
|
if MYPY:
|
||||||
|
from UM.Scene.Camera import Camera
|
||||||
|
|
||||||
|
## A render pass subclass that renders slicable objects with default parameters.
|
||||||
|
# It uses the active camera by default, but it can be overridden to use a different camera.
|
||||||
|
#
|
||||||
|
# This is useful to get a preview image of a scene taken from a different location as the active camera.
|
||||||
|
class PreviewPass(RenderPass):
|
||||||
|
def __init__(self, width: int, height: int):
|
||||||
|
super().__init__("preview", width, height, 0)
|
||||||
|
|
||||||
|
self._camera = None # type: Optional[Camera]
|
||||||
|
|
||||||
|
self._renderer = Application.getInstance().getRenderer()
|
||||||
|
|
||||||
|
self._shader = None
|
||||||
|
self._scene = Application.getInstance().getController().getScene()
|
||||||
|
|
||||||
|
# Set the camera to be used by this render pass
|
||||||
|
# if it's None, the active camera is used
|
||||||
|
def setCamera(self, camera: Optional["Camera"]):
|
||||||
|
self._camera = camera
|
||||||
|
|
||||||
|
def render(self) -> None:
|
||||||
|
if not self._shader:
|
||||||
|
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "object.shader"))
|
||||||
|
|
||||||
|
# Create a new batch to be rendered
|
||||||
|
batch = RenderBatch(self._shader)
|
||||||
|
|
||||||
|
# Fill up the batch with objects that can be sliced. `
|
||||||
|
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||||
|
if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible():
|
||||||
|
batch.addItem(node.getWorldTransformation(), node.getMeshData())
|
||||||
|
|
||||||
|
self.bind()
|
||||||
|
if self._camera is None:
|
||||||
|
batch.render(Application.getInstance().getController().getScene().getActiveCamera())
|
||||||
|
else:
|
||||||
|
batch.render(self._camera)
|
||||||
|
self.release()
|
|
@ -56,6 +56,7 @@ class PrintInformation(QObject):
|
||||||
self._material_lengths = []
|
self._material_lengths = []
|
||||||
self._material_weights = []
|
self._material_weights = []
|
||||||
self._material_costs = []
|
self._material_costs = []
|
||||||
|
self._material_names = []
|
||||||
|
|
||||||
self._pre_sliced = False
|
self._pre_sliced = False
|
||||||
|
|
||||||
|
@ -66,10 +67,11 @@ class PrintInformation(QObject):
|
||||||
self._base_name = ""
|
self._base_name = ""
|
||||||
self._abbr_machine = ""
|
self._abbr_machine = ""
|
||||||
self._job_name = ""
|
self._job_name = ""
|
||||||
|
self._project_name = ""
|
||||||
|
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._updateJobName)
|
Application.getInstance().globalContainerStackChanged.connect(self._updateJobName)
|
||||||
Application.getInstance().fileLoaded.connect(self.setBaseName)
|
Application.getInstance().fileLoaded.connect(self.setBaseName)
|
||||||
|
Application.getInstance().projectFileLoaded.connect(self.setProjectName)
|
||||||
Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
|
Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
|
||||||
|
|
||||||
self._active_material_container = None
|
self._active_material_container = None
|
||||||
|
@ -78,7 +80,6 @@ class PrintInformation(QObject):
|
||||||
|
|
||||||
self._material_amounts = []
|
self._material_amounts = []
|
||||||
|
|
||||||
|
|
||||||
# Crate cura message translations and using translation keys initialize empty time Duration object for total time
|
# Crate cura message translations and using translation keys initialize empty time Duration object for total time
|
||||||
# and time for each feature
|
# and time for each feature
|
||||||
def initializeCuraMessagePrintTimeProperties(self):
|
def initializeCuraMessagePrintTimeProperties(self):
|
||||||
|
@ -139,6 +140,12 @@ class PrintInformation(QObject):
|
||||||
def materialCosts(self):
|
def materialCosts(self):
|
||||||
return self._material_costs
|
return self._material_costs
|
||||||
|
|
||||||
|
materialNamesChanged = pyqtSignal()
|
||||||
|
|
||||||
|
@pyqtProperty("QVariantList", notify = materialNamesChanged)
|
||||||
|
def materialNames(self):
|
||||||
|
return self._material_names
|
||||||
|
|
||||||
def _onPrintDurationMessage(self, print_time, material_amounts):
|
def _onPrintDurationMessage(self, print_time, material_amounts):
|
||||||
|
|
||||||
self._updateTotalPrintTimePerFeature(print_time)
|
self._updateTotalPrintTimePerFeature(print_time)
|
||||||
|
@ -170,6 +177,7 @@ class PrintInformation(QObject):
|
||||||
self._material_lengths = []
|
self._material_lengths = []
|
||||||
self._material_weights = []
|
self._material_weights = []
|
||||||
self._material_costs = []
|
self._material_costs = []
|
||||||
|
self._material_names = []
|
||||||
|
|
||||||
material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings"))
|
material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings"))
|
||||||
|
|
||||||
|
@ -188,8 +196,10 @@ class PrintInformation(QObject):
|
||||||
|
|
||||||
weight = float(amount) * float(density) / 1000
|
weight = float(amount) * float(density) / 1000
|
||||||
cost = 0
|
cost = 0
|
||||||
|
material_name = catalog.i18nc("@label unknown material", "Unknown")
|
||||||
if material:
|
if material:
|
||||||
material_guid = material.getMetaDataEntry("GUID")
|
material_guid = material.getMetaDataEntry("GUID")
|
||||||
|
material_name = material.getName()
|
||||||
if material_guid in material_preference_values:
|
if material_guid in material_preference_values:
|
||||||
material_values = material_preference_values[material_guid]
|
material_values = material_preference_values[material_guid]
|
||||||
|
|
||||||
|
@ -208,10 +218,12 @@ class PrintInformation(QObject):
|
||||||
self._material_weights.append(weight)
|
self._material_weights.append(weight)
|
||||||
self._material_lengths.append(length)
|
self._material_lengths.append(length)
|
||||||
self._material_costs.append(cost)
|
self._material_costs.append(cost)
|
||||||
|
self._material_names.append(material_name)
|
||||||
|
|
||||||
self.materialLengthsChanged.emit()
|
self.materialLengthsChanged.emit()
|
||||||
self.materialWeightsChanged.emit()
|
self.materialWeightsChanged.emit()
|
||||||
self.materialCostsChanged.emit()
|
self.materialCostsChanged.emit()
|
||||||
|
self.materialNamesChanged.emit()
|
||||||
|
|
||||||
def _onPreferencesChanged(self, preference):
|
def _onPreferencesChanged(self, preference):
|
||||||
if preference != "cura/material_settings":
|
if preference != "cura/material_settings":
|
||||||
|
@ -241,6 +253,11 @@ class PrintInformation(QObject):
|
||||||
self._job_name = name
|
self._job_name = name
|
||||||
self.jobNameChanged.emit()
|
self.jobNameChanged.emit()
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def setProjectName(self, name):
|
||||||
|
self._project_name = name
|
||||||
|
self.setJobName(name)
|
||||||
|
|
||||||
jobNameChanged = pyqtSignal()
|
jobNameChanged = pyqtSignal()
|
||||||
|
|
||||||
@pyqtProperty(str, notify = jobNameChanged)
|
@pyqtProperty(str, notify = jobNameChanged)
|
||||||
|
@ -248,6 +265,11 @@ class PrintInformation(QObject):
|
||||||
return self._job_name
|
return self._job_name
|
||||||
|
|
||||||
def _updateJobName(self):
|
def _updateJobName(self):
|
||||||
|
# if the project name is set, we use the project name as the job name, so the job name should not get updated
|
||||||
|
# if a model file is loaded after that.
|
||||||
|
if self._project_name != "":
|
||||||
|
return
|
||||||
|
|
||||||
if self._base_name == "":
|
if self._base_name == "":
|
||||||
self._job_name = ""
|
self._job_name = ""
|
||||||
self.jobNameChanged.emit()
|
self.jobNameChanged.emit()
|
||||||
|
@ -303,7 +325,12 @@ class PrintInformation(QObject):
|
||||||
elif word.isdigit():
|
elif word.isdigit():
|
||||||
abbr_machine += word
|
abbr_machine += word
|
||||||
else:
|
else:
|
||||||
abbr_machine += self._stripAccents(word.strip("()[]{}#").upper())[0]
|
stripped_word = self._stripAccents(word.strip("()[]{}#").upper())
|
||||||
|
# - use only the first character if the word is too long (> 3 characters)
|
||||||
|
# - use the whole word if it's not too long (<= 3 characters)
|
||||||
|
if len(stripped_word) > 3:
|
||||||
|
stripped_word = stripped_word[0]
|
||||||
|
abbr_machine += stripped_word
|
||||||
|
|
||||||
self._abbr_machine = abbr_machine
|
self._abbr_machine = abbr_machine
|
||||||
|
|
||||||
|
@ -329,4 +356,3 @@ class PrintInformation(QObject):
|
||||||
|
|
||||||
temp_material_amounts = [0]
|
temp_material_amounts = [0]
|
||||||
self._onPrintDurationMessage(temp_message, temp_material_amounts)
|
self._onPrintDurationMessage(temp_message, temp_material_amounts)
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
||||||
self._can_pause = True
|
self._can_pause = True
|
||||||
self._can_abort = True
|
self._can_abort = True
|
||||||
self._can_pre_heat_bed = True
|
self._can_pre_heat_bed = True
|
||||||
|
self._can_control_manually = True
|
||||||
|
|
||||||
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None):
|
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None):
|
||||||
raise NotImplementedError("requestWrite needs to be implemented")
|
raise NotImplementedError("requestWrite needs to be implemented")
|
||||||
|
@ -144,6 +145,11 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
||||||
def canAbort(self):
|
def canAbort(self):
|
||||||
return self._can_abort
|
return self._can_abort
|
||||||
|
|
||||||
|
# Does the printer support manual control at all
|
||||||
|
@pyqtProperty(bool, constant=True)
|
||||||
|
def canControlManually(self):
|
||||||
|
return self._can_control_manually
|
||||||
|
|
||||||
@pyqtProperty(QObject, constant=True)
|
@pyqtProperty(QObject, constant=True)
|
||||||
def monitorItem(self):
|
def monitorItem(self):
|
||||||
# Note that we specifically only check if the monitor component is created.
|
# Note that we specifically only check if the monitor component is created.
|
||||||
|
|
|
@ -87,7 +87,7 @@ class QualityManager:
|
||||||
qualities = set(quality_type_dict.values())
|
qualities = set(quality_type_dict.values())
|
||||||
for material_container in material_containers[1:]:
|
for material_container in material_containers[1:]:
|
||||||
next_quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_container)
|
next_quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_container)
|
||||||
qualities.update(set(next_quality_type_dict.values()))
|
qualities.intersection_update(set(next_quality_type_dict.values()))
|
||||||
|
|
||||||
return list(qualities)
|
return list(qualities)
|
||||||
|
|
||||||
|
@ -178,12 +178,25 @@ class QualityManager:
|
||||||
def findAllUsableQualitiesForMachineAndExtruders(self, global_container_stack: "GlobalStack", extruder_stacks: List["ExtruderStack"]) -> List[InstanceContainer]:
|
def findAllUsableQualitiesForMachineAndExtruders(self, global_container_stack: "GlobalStack", extruder_stacks: List["ExtruderStack"]) -> List[InstanceContainer]:
|
||||||
global_machine_definition = global_container_stack.getBottom()
|
global_machine_definition = global_container_stack.getBottom()
|
||||||
|
|
||||||
|
machine_manager = Application.getInstance().getMachineManager()
|
||||||
|
active_stack_id = machine_manager.activeStackId
|
||||||
|
|
||||||
|
materials = []
|
||||||
|
|
||||||
|
# TODO: fix this
|
||||||
if extruder_stacks:
|
if extruder_stacks:
|
||||||
# Multi-extruder machine detected.
|
# Multi-extruder machine detected
|
||||||
materials = [stack.material for stack in extruder_stacks]
|
for stack in extruder_stacks:
|
||||||
|
if stack.getId() == active_stack_id and machine_manager.newMaterial:
|
||||||
|
materials.append(machine_manager.newMaterial)
|
||||||
|
else:
|
||||||
|
materials.append(stack.material)
|
||||||
else:
|
else:
|
||||||
# Machine with one extruder.
|
# Machine with one extruder
|
||||||
materials = [global_container_stack.material]
|
if global_container_stack.getId() == active_stack_id and machine_manager.newMaterial:
|
||||||
|
materials.append(machine_manager.newMaterial)
|
||||||
|
else:
|
||||||
|
materials.append(global_container_stack.material)
|
||||||
|
|
||||||
quality_types = self.findAllQualityTypesForMachineAndMaterials(global_machine_definition, materials)
|
quality_types = self.findAllQualityTypesForMachineAndMaterials(global_machine_definition, materials)
|
||||||
|
|
||||||
|
|
|
@ -303,6 +303,9 @@ class CuraContainerRegistry(ContainerRegistry):
|
||||||
if "material" in quality_type_criteria:
|
if "material" in quality_type_criteria:
|
||||||
materials = ContainerRegistry.getInstance().findInstanceContainers(id = quality_type_criteria["material"])
|
materials = ContainerRegistry.getInstance().findInstanceContainers(id = quality_type_criteria["material"])
|
||||||
del quality_type_criteria["material"]
|
del quality_type_criteria["material"]
|
||||||
|
# Do not filter quality containers here with materials because we are trying to import a profile, so it should
|
||||||
|
# NOT be restricted by the active materials on the current machine.
|
||||||
|
materials = None
|
||||||
|
|
||||||
# Check to make sure the imported profile actually makes sense in context of the current configuration.
|
# Check to make sure the imported profile actually makes sense in context of the current configuration.
|
||||||
# This prevents issues where importing a "draft" profile for a machine without "draft" qualities would report as
|
# This prevents issues where importing a "draft" profile for a machine without "draft" qualities would report as
|
||||||
|
|
|
@ -16,6 +16,7 @@ from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
from UM.Settings.SettingFunction import SettingFunction
|
from UM.Settings.SettingFunction import SettingFunction
|
||||||
from UM.Settings.ContainerStack import ContainerStack
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
from UM.Settings.Interfaces import DefinitionContainerInterface
|
from UM.Settings.Interfaces import DefinitionContainerInterface
|
||||||
|
from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext
|
||||||
from typing import Optional, List, TYPE_CHECKING, Union
|
from typing import Optional, List, TYPE_CHECKING, Union
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -587,6 +588,46 @@ class ExtruderManager(QObject):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
## Get all extruder values for a certain setting. This function will skip the user settings container.
|
||||||
|
#
|
||||||
|
# This is exposed to SettingFunction so it can be used in value functions.
|
||||||
|
#
|
||||||
|
# \param key The key of the setting to retrieve values for.
|
||||||
|
#
|
||||||
|
# \return A list of values for all extruders. If an extruder does not have a value, it will not be in the list.
|
||||||
|
# If no extruder has the value, the list will contain the global value.
|
||||||
|
@staticmethod
|
||||||
|
def getDefaultExtruderValues(key):
|
||||||
|
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
context = PropertyEvaluationContext(global_stack)
|
||||||
|
context.context["evaluate_from_container_index"] = 1 # skip the user settings container
|
||||||
|
context.context["override_operators"] = {
|
||||||
|
"extruderValue": ExtruderManager.getDefaultExtruderValue,
|
||||||
|
"extruderValues": ExtruderManager.getDefaultExtruderValues,
|
||||||
|
"resolveOrValue": ExtruderManager.getDefaultResolveOrValue
|
||||||
|
}
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
|
||||||
|
# only include values from extruders that are "active" for the current machine instance
|
||||||
|
if int(extruder.getMetaDataEntry("position")) >= global_stack.getProperty("machine_extruder_count", "value", context = context):
|
||||||
|
continue
|
||||||
|
|
||||||
|
value = extruder.getRawProperty(key, "value", context = context)
|
||||||
|
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(value, SettingFunction):
|
||||||
|
value = value(extruder, context = context)
|
||||||
|
|
||||||
|
result.append(value)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
result.append(global_stack.getProperty(key, "value", context = context))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
## Get all extruder values for a certain setting.
|
## Get all extruder values for a certain setting.
|
||||||
#
|
#
|
||||||
# This is exposed to qml for display purposes
|
# This is exposed to qml for display purposes
|
||||||
|
@ -620,6 +661,35 @@ class ExtruderManager(QObject):
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
## Get the default value from the given extruder. This function will skip the user settings container.
|
||||||
|
#
|
||||||
|
# This is exposed to SettingFunction to use in value functions.
|
||||||
|
#
|
||||||
|
# \param extruder_index The index of the extruder to get the value from.
|
||||||
|
# \param key The key of the setting to get the value of.
|
||||||
|
#
|
||||||
|
# \return The value of the setting for the specified extruder or for the
|
||||||
|
# global stack if not found.
|
||||||
|
@staticmethod
|
||||||
|
def getDefaultExtruderValue(extruder_index, key):
|
||||||
|
extruder = ExtruderManager.getInstance().getExtruderStack(extruder_index)
|
||||||
|
context = PropertyEvaluationContext(extruder)
|
||||||
|
context.context["evaluate_from_container_index"] = 1 # skip the user settings container
|
||||||
|
context.context["override_operators"] = {
|
||||||
|
"extruderValue": ExtruderManager.getDefaultExtruderValue,
|
||||||
|
"extruderValues": ExtruderManager.getDefaultExtruderValues,
|
||||||
|
"resolveOrValue": ExtruderManager.getDefaultResolveOrValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if extruder:
|
||||||
|
value = extruder.getRawProperty(key, "value", context = context)
|
||||||
|
if isinstance(value, SettingFunction):
|
||||||
|
value = value(extruder, context = context)
|
||||||
|
else: # Just a value from global.
|
||||||
|
value = Application.getInstance().getGlobalContainerStack().getProperty(key, "value", context = context)
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
## Get the resolve value or value for a given key
|
## Get the resolve value or value for a given key
|
||||||
#
|
#
|
||||||
# This is the effective value for a given key, it is used for values in the global stack.
|
# This is the effective value for a given key, it is used for values in the global stack.
|
||||||
|
@ -633,3 +703,25 @@ class ExtruderManager(QObject):
|
||||||
resolved_value = global_stack.getProperty(key, "value")
|
resolved_value = global_stack.getProperty(key, "value")
|
||||||
|
|
||||||
return resolved_value
|
return resolved_value
|
||||||
|
|
||||||
|
## Get the resolve value or value for a given key without looking the first container (user container)
|
||||||
|
#
|
||||||
|
# This is the effective value for a given key, it is used for values in the global stack.
|
||||||
|
# This is exposed to SettingFunction to use in value functions.
|
||||||
|
# \param key The key of the setting to get the value of.
|
||||||
|
#
|
||||||
|
# \return The effective value
|
||||||
|
@staticmethod
|
||||||
|
def getDefaultResolveOrValue(key):
|
||||||
|
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
context = PropertyEvaluationContext(global_stack)
|
||||||
|
context.context["evaluate_from_container_index"] = 1 # skip the user settings container
|
||||||
|
context.context["override_operators"] = {
|
||||||
|
"extruderValue": ExtruderManager.getDefaultExtruderValue,
|
||||||
|
"extruderValues": ExtruderManager.getDefaultExtruderValues,
|
||||||
|
"resolveOrValue": ExtruderManager.getDefaultResolveOrValue
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved_value = global_stack.getProperty(key, "value", context = context)
|
||||||
|
|
||||||
|
return resolved_value
|
||||||
|
|
|
@ -4,12 +4,14 @@
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QTimer
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
import UM.Qt.ListModel
|
import UM.Qt.ListModel
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
import UM.FlameProfiler
|
import UM.FlameProfiler
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
from cura.Settings.ExtruderStack import ExtruderStack #To listen to changes on the extruders.
|
from cura.Settings.ExtruderStack import ExtruderStack #To listen to changes on the extruders.
|
||||||
from cura.Settings.MachineManager import MachineManager #To listen to changes on the extruders of the currently active machine.
|
|
||||||
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
## Model that holds extruders.
|
## Model that holds extruders.
|
||||||
#
|
#
|
||||||
|
@ -172,7 +174,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
||||||
color = material.getMetaDataEntry("color_code", default = self.defaultColors[0]) if material else self.defaultColors[0]
|
color = material.getMetaDataEntry("color_code", default = self.defaultColors[0]) if material else self.defaultColors[0]
|
||||||
item = {
|
item = {
|
||||||
"id": global_container_stack.getId(),
|
"id": global_container_stack.getId(),
|
||||||
"name": "Global",
|
"name": catalog.i18nc("@menuitem", "Global"),
|
||||||
"color": color,
|
"color": color,
|
||||||
"index": -1,
|
"index": -1,
|
||||||
"definition": ""
|
"definition": ""
|
||||||
|
@ -215,7 +217,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
||||||
if self._add_optional_extruder:
|
if self._add_optional_extruder:
|
||||||
item = {
|
item = {
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": "Not overridden",
|
"name": catalog.i18nc("@menuitem", "Not overridden"),
|
||||||
"color": "#ffffff",
|
"color": "#ffffff",
|
||||||
"index": -1,
|
"index": -1,
|
||||||
"definition": ""
|
"definition": ""
|
||||||
|
|
|
@ -96,18 +96,18 @@ class GlobalStack(CuraContainerStack):
|
||||||
if not self.definition.findDefinitions(key = key):
|
if not self.definition.findDefinitions(key = key):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if context is None:
|
||||||
|
context = PropertyEvaluationContext()
|
||||||
|
context.pushContainer(self)
|
||||||
|
|
||||||
# Handle the "resolve" property.
|
# Handle the "resolve" property.
|
||||||
if self._shouldResolve(key, property_name):
|
if self._shouldResolve(key, property_name, context):
|
||||||
self._resolving_settings.add(key)
|
self._resolving_settings.add(key)
|
||||||
resolve = super().getProperty(key, "resolve", context)
|
resolve = super().getProperty(key, "resolve", context)
|
||||||
self._resolving_settings.remove(key)
|
self._resolving_settings.remove(key)
|
||||||
if resolve is not None:
|
if resolve is not None:
|
||||||
return resolve
|
return resolve
|
||||||
|
|
||||||
if context is None:
|
|
||||||
context = PropertyEvaluationContext()
|
|
||||||
context.pushContainer(self)
|
|
||||||
|
|
||||||
# Handle the "limit_to_extruder" property.
|
# Handle the "limit_to_extruder" property.
|
||||||
limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
|
limit_to_extruder = super().getProperty(key, "limit_to_extruder", context)
|
||||||
if limit_to_extruder is not None:
|
if limit_to_extruder is not None:
|
||||||
|
@ -151,7 +151,7 @@ class GlobalStack(CuraContainerStack):
|
||||||
|
|
||||||
# Determine whether or not we should try to get the "resolve" property instead of the
|
# Determine whether or not we should try to get the "resolve" property instead of the
|
||||||
# requested property.
|
# requested property.
|
||||||
def _shouldResolve(self, key: str, property_name: str) -> bool:
|
def _shouldResolve(self, key: str, property_name: str, context: Optional[PropertyEvaluationContext] = None) -> bool:
|
||||||
if property_name is not "value":
|
if property_name is not "value":
|
||||||
# Do not try to resolve anything but the "value" property
|
# Do not try to resolve anything but the "value" property
|
||||||
return False
|
return False
|
||||||
|
@ -163,7 +163,7 @@ class GlobalStack(CuraContainerStack):
|
||||||
# track all settings that are being resolved.
|
# track all settings that are being resolved.
|
||||||
return False
|
return False
|
||||||
|
|
||||||
setting_state = super().getProperty(key, "state")
|
setting_state = super().getProperty(key, "state", context = context)
|
||||||
if setting_state is not None and setting_state != InstanceState.Default:
|
if setting_state is not None and setting_state != InstanceState.Default:
|
||||||
# When the user has explicitly set a value, we should ignore any resolve and
|
# When the user has explicitly set a value, we should ignore any resolve and
|
||||||
# just return that value.
|
# just return that value.
|
||||||
|
|
|
@ -39,8 +39,6 @@ if TYPE_CHECKING:
|
||||||
from cura.Settings.CuraContainerStack import CuraContainerStack
|
from cura.Settings.CuraContainerStack import CuraContainerStack
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
from cura.Settings.GlobalStack import GlobalStack
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class MachineManager(QObject):
|
class MachineManager(QObject):
|
||||||
def __init__(self, parent = None):
|
def __init__(self, parent = None):
|
||||||
|
@ -49,6 +47,11 @@ class MachineManager(QObject):
|
||||||
self._active_container_stack = None # type: CuraContainerStack
|
self._active_container_stack = None # type: CuraContainerStack
|
||||||
self._global_container_stack = None # type: GlobalStack
|
self._global_container_stack = None # type: GlobalStack
|
||||||
|
|
||||||
|
# Used to store the new containers until after confirming the dialog
|
||||||
|
self._new_variant_container = None
|
||||||
|
self._new_material_container = None
|
||||||
|
self._new_quality_containers = []
|
||||||
|
|
||||||
self._error_check_timer = QTimer()
|
self._error_check_timer = QTimer()
|
||||||
self._error_check_timer.setInterval(250)
|
self._error_check_timer.setInterval(250)
|
||||||
self._error_check_timer.setSingleShot(True)
|
self._error_check_timer.setSingleShot(True)
|
||||||
|
@ -60,6 +63,7 @@ class MachineManager(QObject):
|
||||||
self._instance_container_timer.timeout.connect(self.__onInstanceContainersChanged)
|
self._instance_container_timer.timeout.connect(self.__onInstanceContainersChanged)
|
||||||
|
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
|
||||||
|
|
||||||
## When the global container is changed, active material probably needs to be updated.
|
## When the global container is changed, active material probably needs to be updated.
|
||||||
self.globalContainerChanged.connect(self.activeMaterialChanged)
|
self.globalContainerChanged.connect(self.activeMaterialChanged)
|
||||||
self.globalContainerChanged.connect(self.activeVariantChanged)
|
self.globalContainerChanged.connect(self.activeVariantChanged)
|
||||||
|
@ -67,10 +71,10 @@ class MachineManager(QObject):
|
||||||
|
|
||||||
self._stacks_have_errors = None
|
self._stacks_have_errors = None
|
||||||
|
|
||||||
self._empty_variant_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
self._empty_variant_container = ContainerRegistry.getInstance().findContainers(id = "empty_variant")[0]
|
||||||
self._empty_material_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
self._empty_material_container = ContainerRegistry.getInstance().findContainers(id = "empty_material")[0]
|
||||||
self._empty_quality_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
self._empty_quality_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality")[0]
|
||||||
self._empty_quality_changes_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
self._empty_quality_changes_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality_changes")[0]
|
||||||
|
|
||||||
self._onGlobalContainerChanged()
|
self._onGlobalContainerChanged()
|
||||||
|
|
||||||
|
@ -86,6 +90,9 @@ class MachineManager(QObject):
|
||||||
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeStackChanged)
|
ExtruderManager.getInstance().activeExtruderChanged.connect(self.activeStackChanged)
|
||||||
self.activeStackChanged.connect(self.activeStackValueChanged)
|
self.activeStackChanged.connect(self.activeStackValueChanged)
|
||||||
|
|
||||||
|
# when a user closed dialog check if any delayed material or variant changes need to be applied
|
||||||
|
Application.getInstance().onDiscardOrKeepProfileChangesClosed.connect(self._executeDelayedActiveContainerStackChanges)
|
||||||
|
|
||||||
Preferences.getInstance().addPreference("cura/active_machine", "")
|
Preferences.getInstance().addPreference("cura/active_machine", "")
|
||||||
|
|
||||||
self._global_event_keys = set()
|
self._global_event_keys = set()
|
||||||
|
@ -111,7 +118,7 @@ class MachineManager(QObject):
|
||||||
"The selected material is incompatible with the selected machine or configuration."),
|
"The selected material is incompatible with the selected machine or configuration."),
|
||||||
title = catalog.i18nc("@info:title", "Incompatible Material"))
|
title = catalog.i18nc("@info:title", "Incompatible Material"))
|
||||||
|
|
||||||
globalContainerChanged = pyqtSignal() # Emitted whenever the global stack is changed (ie: when changing between printers, changing a global profile, but not when changing a value)
|
globalContainerChanged = pyqtSignal() # Emitted whenever the global stack is changed (ie: when changing between printers, changing a global profile, but not when changing a value)
|
||||||
activeMaterialChanged = pyqtSignal()
|
activeMaterialChanged = pyqtSignal()
|
||||||
activeVariantChanged = pyqtSignal()
|
activeVariantChanged = pyqtSignal()
|
||||||
activeQualityChanged = pyqtSignal()
|
activeQualityChanged = pyqtSignal()
|
||||||
|
@ -141,6 +148,14 @@ class MachineManager(QObject):
|
||||||
|
|
||||||
self.outputDevicesChanged.emit()
|
self.outputDevicesChanged.emit()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def newVariant(self):
|
||||||
|
return self._new_variant_container
|
||||||
|
|
||||||
|
@property
|
||||||
|
def newMaterial(self):
|
||||||
|
return self._new_material_container
|
||||||
|
|
||||||
@pyqtProperty("QVariantList", notify = outputDevicesChanged)
|
@pyqtProperty("QVariantList", notify = outputDevicesChanged)
|
||||||
def printerOutputDevices(self):
|
def printerOutputDevices(self):
|
||||||
return self._printer_output_devices
|
return self._printer_output_devices
|
||||||
|
@ -335,6 +350,7 @@ class MachineManager(QObject):
|
||||||
self.activeQualityChanged.emit()
|
self.activeQualityChanged.emit()
|
||||||
self.activeVariantChanged.emit()
|
self.activeVariantChanged.emit()
|
||||||
self.activeMaterialChanged.emit()
|
self.activeMaterialChanged.emit()
|
||||||
|
self._updateStacksHaveErrors() # Prevents unwanted re-slices after changing machine
|
||||||
self._error_check_timer.start()
|
self._error_check_timer.start()
|
||||||
|
|
||||||
def _onInstanceContainersChanged(self, container):
|
def _onInstanceContainersChanged(self, container):
|
||||||
|
@ -351,6 +367,8 @@ class MachineManager(QObject):
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def setActiveMachine(self, stack_id: str) -> None:
|
def setActiveMachine(self, stack_id: str) -> None:
|
||||||
self.blurSettings.emit() # Ensure no-one has focus.
|
self.blurSettings.emit() # Ensure no-one has focus.
|
||||||
|
self._cancelDelayedActiveContainerStackChanges()
|
||||||
|
|
||||||
containers = ContainerRegistry.getInstance().findContainerStacks(id = stack_id)
|
containers = ContainerRegistry.getInstance().findContainerStacks(id = stack_id)
|
||||||
if containers:
|
if containers:
|
||||||
Application.getInstance().setGlobalContainerStack(containers[0])
|
Application.getInstance().setGlobalContainerStack(containers[0])
|
||||||
|
@ -749,7 +767,7 @@ class MachineManager(QObject):
|
||||||
self.blurSettings.emit()
|
self.blurSettings.emit()
|
||||||
old_material.nameChanged.disconnect(self._onMaterialNameChanged)
|
old_material.nameChanged.disconnect(self._onMaterialNameChanged)
|
||||||
|
|
||||||
self._active_container_stack.material = material_container
|
self._new_material_container = material_container # self._active_container_stack will be updated with a delay
|
||||||
Logger.log("d", "Active material changed")
|
Logger.log("d", "Active material changed")
|
||||||
|
|
||||||
material_container.nameChanged.connect(self._onMaterialNameChanged)
|
material_container.nameChanged.connect(self._onMaterialNameChanged)
|
||||||
|
@ -803,13 +821,13 @@ class MachineManager(QObject):
|
||||||
old_material = self._active_container_stack.material
|
old_material = self._active_container_stack.material
|
||||||
if old_variant:
|
if old_variant:
|
||||||
self.blurSettings.emit()
|
self.blurSettings.emit()
|
||||||
self._active_container_stack.variant = containers[0]
|
self._new_variant_container = containers[0] # self._active_container_stack will be updated with a delay
|
||||||
Logger.log("d", "Active variant changed to {active_variant_id}".format(active_variant_id = containers[0].getId()))
|
Logger.log("d", "Active variant changed to {active_variant_id}".format(active_variant_id = containers[0].getId()))
|
||||||
preferred_material_name = None
|
preferred_material_name = None
|
||||||
if old_material:
|
if old_material:
|
||||||
preferred_material_name = old_material.getName()
|
preferred_material_name = old_material.getName()
|
||||||
|
preferred_material_id = self._updateMaterialContainer(self._global_container_stack.getBottom(), self._global_container_stack, containers[0], preferred_material_name).id
|
||||||
self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), self._global_container_stack, containers[0], preferred_material_name).id)
|
self.setActiveMaterial(preferred_material_id)
|
||||||
else:
|
else:
|
||||||
Logger.log("w", "While trying to set the active variant, no variant was found to replace.")
|
Logger.log("w", "While trying to set the active variant, no variant was found to replace.")
|
||||||
|
|
||||||
|
@ -824,8 +842,6 @@ class MachineManager(QObject):
|
||||||
if not containers or not self._global_container_stack:
|
if not containers or not self._global_container_stack:
|
||||||
return
|
return
|
||||||
|
|
||||||
Logger.log("d", "Attempting to change the active quality to %s", quality_id)
|
|
||||||
|
|
||||||
# Quality profile come in two flavours: type=quality and type=quality_changes
|
# Quality profile come in two flavours: type=quality and type=quality_changes
|
||||||
# If we found a quality_changes profile then look up its parent quality profile.
|
# If we found a quality_changes profile then look up its parent quality profile.
|
||||||
container_type = containers[0].getMetaDataEntry("type")
|
container_type = containers[0].getMetaDataEntry("type")
|
||||||
|
@ -845,30 +861,79 @@ class MachineManager(QObject):
|
||||||
if new_quality_settings_list is None:
|
if new_quality_settings_list is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
name_changed_connect_stacks = [] # Connect these stacks to the name changed callback
|
# check if any of the stacks have a not supported profile
|
||||||
|
# if that is the case, all stacks should have a not supported state (otherwise it will show quality_type normal)
|
||||||
|
has_not_supported_quality = False
|
||||||
|
|
||||||
|
# check all stacks for not supported
|
||||||
|
for setting_info in new_quality_settings_list:
|
||||||
|
if setting_info["quality"].getMetaDataEntry("quality_type") == "not_supported":
|
||||||
|
has_not_supported_quality = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# set all stacks to not supported if that's the case
|
||||||
|
if has_not_supported_quality:
|
||||||
|
for setting_info in new_quality_settings_list:
|
||||||
|
setting_info["quality"] = self._empty_quality_container
|
||||||
|
|
||||||
|
self._new_quality_containers.clear()
|
||||||
|
|
||||||
|
# store the upcoming quality profile changes per stack for later execution
|
||||||
|
# this prevents re-slicing before the user has made a choice in the discard or keep dialog
|
||||||
|
# (see _executeDelayedActiveContainerStackChanges)
|
||||||
for setting_info in new_quality_settings_list:
|
for setting_info in new_quality_settings_list:
|
||||||
stack = setting_info["stack"]
|
stack = setting_info["stack"]
|
||||||
stack_quality = setting_info["quality"]
|
stack_quality = setting_info["quality"]
|
||||||
stack_quality_changes = setting_info["quality_changes"]
|
stack_quality_changes = setting_info["quality_changes"]
|
||||||
|
|
||||||
name_changed_connect_stacks.append(stack_quality)
|
self._new_quality_containers.append({
|
||||||
name_changed_connect_stacks.append(stack_quality_changes)
|
"stack": stack,
|
||||||
self._replaceQualityOrQualityChangesInStack(stack, stack_quality, postpone_emit=True)
|
"quality": stack_quality,
|
||||||
self._replaceQualityOrQualityChangesInStack(stack, stack_quality_changes, postpone_emit=True)
|
"quality_changes": stack_quality_changes
|
||||||
|
})
|
||||||
|
|
||||||
# Send emits that are postponed in replaceContainer.
|
has_user_interaction = False
|
||||||
# Here the stacks are finished replacing and every value can be resolved based on the current state.
|
|
||||||
for setting_info in new_quality_settings_list:
|
|
||||||
setting_info["stack"].sendPostponedEmits()
|
|
||||||
|
|
||||||
# Connect to onQualityNameChanged
|
|
||||||
for stack in name_changed_connect_stacks:
|
|
||||||
stack.nameChanged.connect(self._onQualityNameChanged)
|
|
||||||
|
|
||||||
if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
|
if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
|
||||||
self._askUserToKeepOrClearCurrentSettings()
|
# Show the keep/discard user settings dialog
|
||||||
|
has_user_interaction = Application.getInstance().discardOrKeepProfileChanges()
|
||||||
|
|
||||||
self.activeQualityChanged.emit()
|
# If there is no interaction with the user (it means the dialog showing "keep" or "discard" was not shown)
|
||||||
|
# because either there are not user changes or because the used already decided to always keep or discard,
|
||||||
|
# then the quality instance container is replaced, in which case, the activeQualityChanged signal is emitted.
|
||||||
|
if not has_user_interaction:
|
||||||
|
self._executeDelayedActiveContainerStackChanges()
|
||||||
|
|
||||||
|
## Used to update material and variant in the active container stack with a delay.
|
||||||
|
# This delay prevents the stack from triggering a lot of signals (eventually resulting in slicing)
|
||||||
|
# before the user decided to keep or discard any of their changes using the dialog.
|
||||||
|
# The Application.onDiscardOrKeepProfileChangesClosed signal triggers this method.
|
||||||
|
def _executeDelayedActiveContainerStackChanges(self):
|
||||||
|
if self._new_variant_container is not None:
|
||||||
|
self._active_container_stack.variant = self._new_variant_container
|
||||||
|
self._new_variant_container = None
|
||||||
|
|
||||||
|
if self._new_material_container is not None:
|
||||||
|
self._active_container_stack.material = self._new_material_container
|
||||||
|
self._new_material_container = None
|
||||||
|
|
||||||
|
# apply the new quality to all stacks
|
||||||
|
if self._new_quality_containers:
|
||||||
|
for new_quality in self._new_quality_containers:
|
||||||
|
self._replaceQualityOrQualityChangesInStack(new_quality["stack"], new_quality["quality"], postpone_emit = True)
|
||||||
|
self._replaceQualityOrQualityChangesInStack(new_quality["stack"], new_quality["quality_changes"], postpone_emit = True)
|
||||||
|
|
||||||
|
for new_quality in self._new_quality_containers:
|
||||||
|
new_quality["stack"].nameChanged.connect(self._onQualityNameChanged)
|
||||||
|
new_quality["stack"].sendPostponedEmits() # Send the signals that were postponed in _replaceQualityOrQualityChangesInStack
|
||||||
|
|
||||||
|
self._new_quality_containers.clear()
|
||||||
|
|
||||||
|
## Cancel set changes for material and variant in the active container stack.
|
||||||
|
# Used for ignoring any changes when switching between printers (setActiveMachine)
|
||||||
|
def _cancelDelayedActiveContainerStackChanges(self):
|
||||||
|
self._new_material_container = None
|
||||||
|
self._new_variant_container = None
|
||||||
|
|
||||||
## Determine the quality and quality changes settings for the current machine for a quality name.
|
## Determine the quality and quality changes settings for the current machine for a quality name.
|
||||||
#
|
#
|
||||||
|
@ -892,8 +957,14 @@ class MachineManager(QObject):
|
||||||
|
|
||||||
for stack in stacks:
|
for stack in stacks:
|
||||||
material = stack.material
|
material = stack.material
|
||||||
|
|
||||||
|
# TODO: fix this
|
||||||
|
if self._new_material_container and stack.getId() == self._active_container_stack.getId():
|
||||||
|
material = self._new_material_container
|
||||||
|
|
||||||
quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
|
quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
|
||||||
if not quality: #No quality profile is found for this quality type.
|
if not quality:
|
||||||
|
# No quality profile is found for this quality type.
|
||||||
quality = self._empty_quality_container
|
quality = self._empty_quality_container
|
||||||
result.append({"stack": stack, "quality": quality, "quality_changes": empty_quality_changes})
|
result.append({"stack": stack, "quality": quality, "quality_changes": empty_quality_changes})
|
||||||
|
|
||||||
|
@ -928,8 +999,12 @@ class MachineManager(QObject):
|
||||||
else:
|
else:
|
||||||
Logger.log("e", "Could not find the global quality changes container with name %s", quality_changes_name)
|
Logger.log("e", "Could not find the global quality changes container with name %s", quality_changes_name)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
material = global_container_stack.material
|
material = global_container_stack.material
|
||||||
|
|
||||||
|
if self._new_material_container and self._active_container_stack.getId() == global_container_stack.getId():
|
||||||
|
material = self._new_material_container
|
||||||
|
|
||||||
# For the global stack, find a quality which matches the quality_type in
|
# For the global stack, find a quality which matches the quality_type in
|
||||||
# the quality changes profile and also satisfies any material constraints.
|
# the quality changes profile and also satisfies any material constraints.
|
||||||
quality_type = global_quality_changes.getMetaDataEntry("quality_type")
|
quality_type = global_quality_changes.getMetaDataEntry("quality_type")
|
||||||
|
@ -956,6 +1031,10 @@ class MachineManager(QObject):
|
||||||
quality_changes = self._empty_quality_changes_container
|
quality_changes = self._empty_quality_changes_container
|
||||||
|
|
||||||
material = stack.material
|
material = stack.material
|
||||||
|
|
||||||
|
if self._new_material_container and self._active_container_stack.getId() == stack.getId():
|
||||||
|
material = self._new_material_container
|
||||||
|
|
||||||
quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
|
quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
|
||||||
if not quality: #No quality profile found for this quality type.
|
if not quality: #No quality profile found for this quality type.
|
||||||
quality = self._empty_quality_container
|
quality = self._empty_quality_container
|
||||||
|
@ -987,9 +1066,6 @@ class MachineManager(QObject):
|
||||||
stack.qualityChanges.nameChanged.connect(self._onQualityNameChanged)
|
stack.qualityChanges.nameChanged.connect(self._onQualityNameChanged)
|
||||||
self._onQualityNameChanged()
|
self._onQualityNameChanged()
|
||||||
|
|
||||||
def _askUserToKeepOrClearCurrentSettings(self):
|
|
||||||
Application.getInstance().discardOrKeepProfileChanges()
|
|
||||||
|
|
||||||
@pyqtProperty(str, notify = activeVariantChanged)
|
@pyqtProperty(str, notify = activeVariantChanged)
|
||||||
def activeVariantName(self) -> str:
|
def activeVariantName(self) -> str:
|
||||||
if self._active_container_stack:
|
if self._active_container_stack:
|
||||||
|
@ -1096,7 +1172,7 @@ class MachineManager(QObject):
|
||||||
machine_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
|
machine_stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
|
||||||
other_machine_stacks = [s for s in machine_stacks if s.getId() != machine_id]
|
other_machine_stacks = [s for s in machine_stacks if s.getId() != machine_id]
|
||||||
if other_machine_stacks:
|
if other_machine_stacks:
|
||||||
Application.getInstance().setGlobalContainerStack(other_machine_stacks[0])
|
self.setActiveMachine(other_machine_stacks[0].getId())
|
||||||
|
|
||||||
ExtruderManager.getInstance().removeMachineExtruders(machine_id)
|
ExtruderManager.getInstance().removeMachineExtruders(machine_id)
|
||||||
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id)
|
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id)
|
||||||
|
|
|
@ -61,6 +61,7 @@ class ProfilesModel(InstanceContainersModel):
|
||||||
active_extruder = extruder_manager.getActiveExtruderStack()
|
active_extruder = extruder_manager.getActiveExtruderStack()
|
||||||
extruder_stacks = extruder_manager.getActiveExtruderStacks()
|
extruder_stacks = extruder_manager.getActiveExtruderStacks()
|
||||||
materials = [global_container_stack.material]
|
materials = [global_container_stack.material]
|
||||||
|
|
||||||
if active_extruder in extruder_stacks:
|
if active_extruder in extruder_stacks:
|
||||||
extruder_stacks.remove(active_extruder)
|
extruder_stacks.remove(active_extruder)
|
||||||
extruder_stacks = [active_extruder] + extruder_stacks
|
extruder_stacks = [active_extruder] + extruder_stacks
|
||||||
|
@ -83,21 +84,30 @@ class ProfilesModel(InstanceContainersModel):
|
||||||
if quality.getMetaDataEntry("quality_type") not in quality_type_set:
|
if quality.getMetaDataEntry("quality_type") not in quality_type_set:
|
||||||
result.append(quality)
|
result.append(quality)
|
||||||
|
|
||||||
|
# if still profiles are found, add a single empty_quality ("Not supported") instance to the drop down list
|
||||||
|
if len(result) == 0:
|
||||||
|
# If not qualities are found we dynamically create a not supported container for this machine + material combination
|
||||||
|
not_supported_container = ContainerRegistry.getInstance().findContainers(id = "empty_quality")[0]
|
||||||
|
result.append(not_supported_container)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
## Re-computes the items in this model, and adds the layer height role.
|
## Re-computes the items in this model, and adds the layer height role.
|
||||||
def _recomputeItems(self):
|
def _recomputeItems(self):
|
||||||
#Some globals that we can re-use.
|
|
||||||
|
# Some globals that we can re-use.
|
||||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
if global_container_stack is None:
|
if global_container_stack is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Detecting if the machine has multiple extrusion
|
# Detecting if the machine has multiple extrusion
|
||||||
multiple_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
|
multiple_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
|
||||||
|
|
||||||
# Get the list of extruders and place the selected extruder at the front of the list.
|
# Get the list of extruders and place the selected extruder at the front of the list.
|
||||||
extruder_manager = ExtruderManager.getInstance()
|
extruder_manager = ExtruderManager.getInstance()
|
||||||
active_extruder = extruder_manager.getActiveExtruderStack()
|
active_extruder = extruder_manager.getActiveExtruderStack()
|
||||||
extruder_stacks = extruder_manager.getActiveExtruderStacks()
|
extruder_stacks = extruder_manager.getActiveExtruderStacks()
|
||||||
|
|
||||||
if multiple_extrusion:
|
if multiple_extrusion:
|
||||||
# Place the active extruder at the front of the list.
|
# Place the active extruder at the front of the list.
|
||||||
# This is a workaround checking if there is an active_extruder or not before moving it to the front of the list.
|
# This is a workaround checking if there is an active_extruder or not before moving it to the front of the list.
|
||||||
|
@ -111,8 +121,7 @@ class ProfilesModel(InstanceContainersModel):
|
||||||
extruder_stacks = new_extruder_stacks + extruder_stacks
|
extruder_stacks = new_extruder_stacks + extruder_stacks
|
||||||
|
|
||||||
# Get a list of usable/available qualities for this machine and material
|
# Get a list of usable/available qualities for this machine and material
|
||||||
qualities = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_container_stack,
|
qualities = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_container_stack, extruder_stacks)
|
||||||
extruder_stacks)
|
|
||||||
|
|
||||||
container_registry = ContainerRegistry.getInstance()
|
container_registry = ContainerRegistry.getInstance()
|
||||||
machine_manager = Application.getInstance().getMachineManager()
|
machine_manager = Application.getInstance().getMachineManager()
|
||||||
|
@ -155,14 +164,24 @@ class ProfilesModel(InstanceContainersModel):
|
||||||
|
|
||||||
# Now all the containers are set
|
# Now all the containers are set
|
||||||
for item in containers:
|
for item in containers:
|
||||||
profile = container_registry.findContainers(id=item["id"])
|
profile = container_registry.findContainers(id = item["id"])
|
||||||
|
|
||||||
|
# When for some reason there is no profile container in the registry
|
||||||
if not profile:
|
if not profile:
|
||||||
self._setItemLayerHeight(item, "", unit)
|
self._setItemLayerHeight(item, "", "")
|
||||||
item["available"] = False
|
item["available"] = False
|
||||||
yield item
|
yield item
|
||||||
continue
|
continue
|
||||||
|
|
||||||
profile = profile[0]
|
profile = profile[0]
|
||||||
|
|
||||||
|
# When there is a profile but it's an empty quality should. It's shown in the list (they are "Not Supported" profiles)
|
||||||
|
if profile.getId() == "empty_quality":
|
||||||
|
self._setItemLayerHeight(item, "", "")
|
||||||
|
item["available"] = True
|
||||||
|
yield item
|
||||||
|
continue
|
||||||
|
|
||||||
item["available"] = profile in qualities
|
item["available"] = profile in qualities
|
||||||
|
|
||||||
# Easy case: This profile defines its own layer height.
|
# Easy case: This profile defines its own layer height.
|
||||||
|
@ -179,9 +198,10 @@ class ProfilesModel(InstanceContainersModel):
|
||||||
if quality_result["stack"] is global_container_stack:
|
if quality_result["stack"] is global_container_stack:
|
||||||
quality = quality_result["quality"]
|
quality = quality_result["quality"]
|
||||||
break
|
break
|
||||||
else: #No global container stack in the results:
|
else:
|
||||||
|
# No global container stack in the results:
|
||||||
if quality_results:
|
if quality_results:
|
||||||
quality = quality_results[0]["quality"] #Take any of the extruders.
|
quality = quality_results[0]["quality"] # Take any of the extruders.
|
||||||
else:
|
else:
|
||||||
quality = None
|
quality = None
|
||||||
if quality and quality.hasProperty("layer_height", "value"):
|
if quality and quality.hasProperty("layer_height", "value"):
|
||||||
|
@ -189,7 +209,7 @@ class ProfilesModel(InstanceContainersModel):
|
||||||
yield item
|
yield item
|
||||||
continue
|
continue
|
||||||
|
|
||||||
#Quality has no value for layer height either. Get the layer height from somewhere lower in the stack.
|
# Quality has no value for layer height either. Get the layer height from somewhere lower in the stack.
|
||||||
skip_until_container = global_container_stack.material
|
skip_until_container = global_container_stack.material
|
||||||
if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No material in stack.
|
if not skip_until_container or skip_until_container == ContainerRegistry.getInstance().getEmptyInstanceContainer(): #No material in stack.
|
||||||
skip_until_container = global_container_stack.variant
|
skip_until_container = global_container_stack.variant
|
||||||
|
|
|
@ -58,8 +58,8 @@ class QualityAndUserProfilesModel(ProfilesModel):
|
||||||
# If the printer has multiple extruders then quality changes related to the current extruder are kept
|
# If the printer has multiple extruders then quality changes related to the current extruder are kept
|
||||||
filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
|
filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
|
||||||
qc.getMetaDataEntry("extruder") is not None and
|
qc.getMetaDataEntry("extruder") is not None and
|
||||||
qc.getMetaDataEntry("extruder") == active_extruder.definition.getMetaDataEntry("quality_definition") or
|
(qc.getMetaDataEntry("extruder") == active_extruder.definition.getMetaDataEntry("quality_definition") or
|
||||||
qc.getMetaDataEntry("extruder") == active_extruder.definition.getId()]
|
qc.getMetaDataEntry("extruder") == active_extruder.definition.getId())]
|
||||||
else:
|
else:
|
||||||
# If not, the quality changes of the global stack are selected
|
# If not, the quality changes of the global stack are selected
|
||||||
filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
|
filtered_quality_changes = [qc for qc in quality_changes_list if qc.getMetaDataEntry("quality_type") in quality_type_set and
|
||||||
|
|
92
cura/Settings/SimpleModeSettingsManager.py
Normal file
92
cura/Settings/SimpleModeSettingsManager.py
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
|
||||||
|
|
||||||
|
from UM.Application import Application
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleModeSettingsManager(QObject):
|
||||||
|
|
||||||
|
def __init__(self, parent = None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self._machine_manager = Application.getInstance().getMachineManager()
|
||||||
|
self._is_profile_customized = False # True when default profile has user changes
|
||||||
|
self._is_profile_user_created = False # True when profile was custom created by user
|
||||||
|
|
||||||
|
self._machine_manager.activeStackValueChanged.connect(self._updateIsProfileCustomized)
|
||||||
|
self._machine_manager.activeQualityChanged.connect(self._updateIsProfileUserCreated)
|
||||||
|
|
||||||
|
# update on create as the activeQualityChanged signal is emitted before this manager is created when Cura starts
|
||||||
|
self._updateIsProfileCustomized()
|
||||||
|
self._updateIsProfileUserCreated()
|
||||||
|
|
||||||
|
isProfileCustomizedChanged = pyqtSignal()
|
||||||
|
isProfileUserCreatedChanged = pyqtSignal()
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify = isProfileCustomizedChanged)
|
||||||
|
def isProfileCustomized(self):
|
||||||
|
return self._is_profile_customized
|
||||||
|
|
||||||
|
def _updateIsProfileCustomized(self):
|
||||||
|
user_setting_keys = set()
|
||||||
|
|
||||||
|
if not self._machine_manager.activeMachine:
|
||||||
|
return False
|
||||||
|
|
||||||
|
global_stack = self._machine_manager.activeMachine
|
||||||
|
|
||||||
|
# check user settings in the global stack
|
||||||
|
user_setting_keys.update(set(global_stack.userChanges.getAllKeys()))
|
||||||
|
|
||||||
|
# check user settings in the extruder stacks
|
||||||
|
if global_stack.extruders:
|
||||||
|
for extruder_stack in global_stack.extruders.values():
|
||||||
|
user_setting_keys.update(set(extruder_stack.userChanges.getAllKeys()))
|
||||||
|
|
||||||
|
# remove settings that are visible in recommended (we don't show the reset button for those)
|
||||||
|
for skip_key in self.__ignored_custom_setting_keys:
|
||||||
|
if skip_key in user_setting_keys:
|
||||||
|
user_setting_keys.remove(skip_key)
|
||||||
|
|
||||||
|
has_customized_user_settings = len(user_setting_keys) > 0
|
||||||
|
|
||||||
|
if has_customized_user_settings != self._is_profile_customized:
|
||||||
|
self._is_profile_customized = has_customized_user_settings
|
||||||
|
self.isProfileCustomizedChanged.emit()
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify = isProfileUserCreatedChanged)
|
||||||
|
def isProfileUserCreated(self):
|
||||||
|
return self._is_profile_user_created
|
||||||
|
|
||||||
|
def _updateIsProfileUserCreated(self):
|
||||||
|
quality_changes_keys = set()
|
||||||
|
|
||||||
|
if not self._machine_manager.activeMachine:
|
||||||
|
return False
|
||||||
|
|
||||||
|
global_stack = self._machine_manager.activeMachine
|
||||||
|
|
||||||
|
# check quality changes settings in the global stack
|
||||||
|
quality_changes_keys.update(set(global_stack.qualityChanges.getAllKeys()))
|
||||||
|
|
||||||
|
# check quality changes settings in the extruder stacks
|
||||||
|
if global_stack.extruders:
|
||||||
|
for extruder_stack in global_stack.extruders.values():
|
||||||
|
quality_changes_keys.update(set(extruder_stack.qualityChanges.getAllKeys()))
|
||||||
|
|
||||||
|
# check if the qualityChanges container is not empty (meaning it is a user created profile)
|
||||||
|
has_quality_changes = len(quality_changes_keys) > 0
|
||||||
|
|
||||||
|
if has_quality_changes != self._is_profile_user_created:
|
||||||
|
self._is_profile_user_created = has_quality_changes
|
||||||
|
self.isProfileUserCreatedChanged.emit()
|
||||||
|
|
||||||
|
# These are the settings included in the Simple ("Recommended") Mode, so only when the other settings have been
|
||||||
|
# changed, we consider it as a user customized profile in the Simple ("Recommended") Mode.
|
||||||
|
__ignored_custom_setting_keys = ["support_enable",
|
||||||
|
"infill_sparse_density",
|
||||||
|
"gradual_infill_steps",
|
||||||
|
"adhesion_type",
|
||||||
|
"support_extruder_nr"]
|
|
@ -6,6 +6,7 @@ from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Settings.SettingFunction import SettingFunction
|
from UM.Settings.SettingFunction import SettingFunction
|
||||||
|
from UM.Settings.PropertyEvaluationContext import PropertyEvaluationContext
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import os
|
import os
|
||||||
|
@ -66,8 +67,15 @@ class UserChangesModel(ListModel):
|
||||||
containers.extend(latest_stack.getContainers())
|
containers.extend(latest_stack.getContainers())
|
||||||
latest_stack = latest_stack.getNextStack()
|
latest_stack = latest_stack.getNextStack()
|
||||||
|
|
||||||
# Drop the user container.
|
# Override "getExtruderValue" with "getDefaultExtruderValue" so we can get the default values
|
||||||
user_changes = containers.pop(0)
|
user_changes = containers.pop(0)
|
||||||
|
default_value_resolve_context = PropertyEvaluationContext(stack)
|
||||||
|
default_value_resolve_context.context["evaluate_from_container_index"] = 1 # skip the user settings container
|
||||||
|
default_value_resolve_context.context["override_operators"] = {
|
||||||
|
"extruderValue": ExtruderManager.getDefaultExtruderValue,
|
||||||
|
"extruderValues": ExtruderManager.getDefaultExtruderValues,
|
||||||
|
"resolveOrValue": ExtruderManager.getDefaultResolveOrValue
|
||||||
|
}
|
||||||
|
|
||||||
for setting_key in user_changes.getAllKeys():
|
for setting_key in user_changes.getAllKeys():
|
||||||
original_value = None
|
original_value = None
|
||||||
|
@ -90,16 +98,16 @@ class UserChangesModel(ListModel):
|
||||||
|
|
||||||
for container in containers:
|
for container in containers:
|
||||||
if stack == global_stack:
|
if stack == global_stack:
|
||||||
resolve = global_stack.getProperty(setting_key, "resolve")
|
resolve = global_stack.getProperty(setting_key, "resolve", default_value_resolve_context)
|
||||||
if resolve is not None:
|
if resolve is not None:
|
||||||
original_value = resolve
|
original_value = resolve
|
||||||
break
|
break
|
||||||
|
|
||||||
original_value = container.getProperty(setting_key, "value")
|
original_value = container.getProperty(setting_key, "value", default_value_resolve_context)
|
||||||
|
|
||||||
# If a value is a function, ensure it's called with the stack it's in.
|
# If a value is a function, ensure it's called with the stack it's in.
|
||||||
if isinstance(original_value, SettingFunction):
|
if isinstance(original_value, SettingFunction):
|
||||||
original_value = original_value(stack)
|
original_value = original_value(stack, default_value_resolve_context)
|
||||||
|
|
||||||
if original_value is not None:
|
if original_value is not None:
|
||||||
break
|
break
|
||||||
|
|
|
@ -41,8 +41,9 @@ if "PYTHONPATH" in os.environ.keys(): # If PYTHONPATH is u
|
||||||
sys.path.insert(1, PATH_real) # Insert it at 1 after os.curdir, which is 0.
|
sys.path.insert(1, PATH_real) # Insert it at 1 after os.curdir, which is 0.
|
||||||
|
|
||||||
def exceptHook(hook_type, value, traceback):
|
def exceptHook(hook_type, value, traceback):
|
||||||
import cura.CrashHandler
|
from cura.CrashHandler import CrashHandler
|
||||||
cura.CrashHandler.show(hook_type, value, traceback)
|
_crash_handler = CrashHandler(hook_type, value, traceback)
|
||||||
|
_crash_handler.show()
|
||||||
|
|
||||||
sys.excepthook = exceptHook
|
sys.excepthook = exceptHook
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,14 @@ from cura.Settings.CuraStackBuilder import CuraStackBuilder
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
from cura.Settings.ExtruderStack import ExtruderStack
|
from cura.Settings.ExtruderStack import ExtruderStack
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
from cura.Settings.GlobalStack import GlobalStack
|
||||||
|
from cura.Settings.CuraContainerStack import _ContainerIndexes
|
||||||
|
from cura.QualityManager import QualityManager
|
||||||
|
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import zipfile
|
import zipfile
|
||||||
import io
|
import io
|
||||||
import configparser
|
import configparser
|
||||||
|
import os
|
||||||
|
|
||||||
i18n_catalog = i18nCatalog("cura")
|
i18n_catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
@ -756,13 +759,37 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
self._container_registry.removeContainer(container.getId())
|
self._container_registry.removeContainer(container.getId())
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Check quality profiles to make sure that if one stack has the "not supported" quality profile,
|
||||||
|
# all others should have the same.
|
||||||
|
#
|
||||||
|
# This block code tries to fix the following problems in Cura 3.0 and earlier:
|
||||||
|
# 1. The upgrade script can rename all "Not Supported" quality profiles to "empty_quality", but it cannot fix
|
||||||
|
# the problem that the global stack the extruder stacks may have different quality profiles. The code
|
||||||
|
# below loops over all stacks and make sure that if there is one stack with "Not Supported" profile, the
|
||||||
|
# rest should also use the "Not Supported" profile.
|
||||||
|
# 2. In earlier versions (at least 2.7 and 3.0), a wrong quality profile could be assigned to a stack. For
|
||||||
|
# example, a UM3 can have a BB 0.8 variant with "aa04_pla_fast" quality profile enabled. To fix this,
|
||||||
|
# in the code below we also check the actual available quality profiles for the machine.
|
||||||
|
#
|
||||||
|
has_not_supported = False
|
||||||
|
for stack in [global_stack] + extruder_stacks:
|
||||||
|
if stack.quality.getId() == "empty_quality":
|
||||||
|
has_not_supported = True
|
||||||
|
break
|
||||||
|
if not has_not_supported:
|
||||||
|
available_quality = QualityManager.getInstance().findAllUsableQualitiesForMachineAndExtruders(global_stack, extruder_stacks)
|
||||||
|
has_not_supported = not available_quality
|
||||||
|
if has_not_supported:
|
||||||
|
empty_quality_container = self._container_registry.findInstanceContainers(id = "empty_quality")[0]
|
||||||
|
for stack in [global_stack] + extruder_stacks:
|
||||||
|
stack.replaceContainer(_ContainerIndexes.Quality, empty_quality_container)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Replacing the old containers if resolve is "new".
|
# Replacing the old containers if resolve is "new".
|
||||||
# When resolve is "new", some containers will get renamed, so all the other containers that reference to those
|
# When resolve is "new", some containers will get renamed, so all the other containers that reference to those
|
||||||
# MUST get updated too.
|
# MUST get updated too.
|
||||||
#
|
#
|
||||||
if self._resolve_strategies["machine"] == "new":
|
if self._resolve_strategies["machine"] == "new":
|
||||||
|
|
||||||
# A new machine was made, but it was serialized with the wrong user container. Fix that now.
|
# A new machine was made, but it was serialized with the wrong user container. Fix that now.
|
||||||
for container in user_instance_containers:
|
for container in user_instance_containers:
|
||||||
# replacing the container ID for user instance containers for the extruders
|
# replacing the container ID for user instance containers for the extruders
|
||||||
|
@ -876,6 +903,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
nodes = self._3mf_mesh_reader.read(file_name)
|
nodes = self._3mf_mesh_reader.read(file_name)
|
||||||
if nodes is None:
|
if nodes is None:
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|
||||||
|
base_file_name = os.path.basename(file_name)
|
||||||
|
if base_file_name.endswith(".curaproject.3mf"):
|
||||||
|
base_file_name = base_file_name[:base_file_name.rfind(".curaproject.3mf")]
|
||||||
|
Application.getInstance().projectFileLoaded.emit(base_file_name)
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
## HACK: Replaces the material container in the given stack with a newly created material container.
|
## HACK: Replaces the material container in the given stack with a newly created material container.
|
||||||
|
|
|
@ -8,7 +8,6 @@ from UM.Application import Application
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from UM.Version import Version
|
from UM.Version import Version
|
||||||
|
|
||||||
from PyQt5.QtQuick import QQuickView
|
|
||||||
from PyQt5.QtQml import QQmlComponent, QQmlContext
|
from PyQt5.QtQml import QQmlComponent, QQmlContext
|
||||||
from PyQt5.QtCore import QUrl, pyqtSlot, QObject
|
from PyQt5.QtCore import QUrl, pyqtSlot, QObject
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,92 @@
|
||||||
|
[3.0.4]
|
||||||
|
*Bug fixes
|
||||||
|
- Fixed OpenGL issue that prevents Cura from starting.
|
||||||
|
|
||||||
|
*License agreement on the first startup has been added
|
||||||
|
|
||||||
|
[3.0.3]
|
||||||
|
*Bug fixes
|
||||||
|
- Add missing libraries for the MakePrintable plugin.
|
||||||
|
|
||||||
[3.0.0]
|
[3.0.0]
|
||||||
*Will be updated soon!
|
*Faster start-up
|
||||||
|
Start-up speed has been cut in half compared to the previous version.
|
||||||
|
|
||||||
|
*New color scheme
|
||||||
|
Color scheme has been updated to reflect Ultimaker Cura rebrand.
|
||||||
|
|
||||||
|
*Updated UX design
|
||||||
|
The Ultimaker Cura logo has moved from the bottom to the top of the interface. Print status icons have been updated and repositioned.
|
||||||
|
|
||||||
|
*Redesigned splash screen
|
||||||
|
A new splash screen on Ultimaker Cura startup has been added.
|
||||||
|
|
||||||
|
*Top navigation bar improvements
|
||||||
|
The width of tab functionality changes accordingly to the word space (multilingual).
|
||||||
|
|
||||||
|
*Print quality slider
|
||||||
|
A slider can now be used to control the quality profile in recommended mode.
|
||||||
|
|
||||||
|
*Infill slider
|
||||||
|
Model infill can now be changed using a slider in recommended mode.
|
||||||
|
|
||||||
|
*Changed layer view
|
||||||
|
Layer view icon, panel and slider have moved to top-right of interface.
|
||||||
|
|
||||||
|
*Rasterized build plate
|
||||||
|
The build plate now shows graduations of 10 mm and 1 mm for easy model positioning.
|
||||||
|
|
||||||
|
*Changed row of extruder buttons
|
||||||
|
Extruder tabs have become buttons and icons have been updated.
|
||||||
|
|
||||||
|
*Add an "Export to Cura" button in SOLIDWORKS
|
||||||
|
SOLIDWORKS plugin can now be installed using an automatic installer.
|
||||||
|
|
||||||
|
*Siemens NX macro
|
||||||
|
When a user updates models in Siemens NX and clicks the button, the updated models replace the models opened in Ultimaker Cura.
|
||||||
|
|
||||||
|
*Skin removal width
|
||||||
|
Remove thin strips of skin from a model to prevent print head zigzagging, in turn preventing vibrations.
|
||||||
|
|
||||||
|
*Skin expand distance
|
||||||
|
Cutting away skins on steep overhangs makes prints less sturdy. By expanding skins with the thickness of walls, features will be better supported. In addition, features such as towers on top of infill will be stronger.
|
||||||
|
|
||||||
|
*Extra skin wall count
|
||||||
|
Printing extra skin directly on top of infill can lead to gaps, curling and pillowing. This is reduced by printing a wall around the skin first, and also improves the printing speed.
|
||||||
|
|
||||||
|
*Minimum extrusion for skin
|
||||||
|
Will prevent filling small gaps that are probably filled already, resulting in less strings, better top details and faster prints.
|
||||||
|
|
||||||
|
*PVA retractions
|
||||||
|
PVA (switch) retraction length is increased, minimum travel distance for retraction is decreased and max count is slightly increased, this reduces stringing by a lot at the cost of slightly increased print time.
|
||||||
|
|
||||||
|
*Z seam options
|
||||||
|
Gives the user control over where to place the seam - hide it in convex corners or in easy to remove locations such as concave corners. Don’t let corner angles influence the seam position.
|
||||||
|
|
||||||
|
*Quarter cubic infill
|
||||||
|
Similar to tetrahedral (octet) infill, but half of the lines are shifted half of the period up. This pattern sacrifices some rigidity of octet infill for greater toughness.
|
||||||
|
|
||||||
|
*Cross infill
|
||||||
|
A fractal pattern infill that requires fewer retractions than other infill types. This is useful for flexible materials as it causes less material elongation. The internal structure given by this infill also assists flexible models having more resistance, while retaining ‘soft’ properties in all directions.
|
||||||
|
|
||||||
|
*Layer start negative position
|
||||||
|
Layer start X/Y values can be less than 0 when the machine centre is zero.
|
||||||
|
|
||||||
|
*PostProcessing stretch script
|
||||||
|
This new script performs "post stretch" algorithm to fix the problem of insufficient inner and outer diameters. Thanks to electrocbd for contributing.
|
||||||
|
|
||||||
|
*Ironing speed settings
|
||||||
|
Ironing speed settings have been moved to experimental category.
|
||||||
|
|
||||||
|
*Doodle3D plugin
|
||||||
|
Update Doodle3D plugin to connect with printers. Thanks to mith for contributing.
|
||||||
|
|
||||||
|
*Bug fixes
|
||||||
|
- Customized profiles are not sent when connecting to a printer
|
||||||
|
- Sync z-hop with layer changes, thanks to smartavionics for contributing
|
||||||
|
- Memory leaks on MacOS
|
||||||
|
- Printer name not loaded when project file is opened
|
||||||
|
- Doodle3D Wifi box was selected by default on non-UM3 printers
|
||||||
|
|
||||||
[2.7.0]
|
[2.7.0]
|
||||||
*Top surface skin
|
*Top surface skin
|
||||||
|
|
|
@ -293,7 +293,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
error_labels.add(definitions[0].label)
|
error_labels.add(definitions[0].label)
|
||||||
|
|
||||||
error_labels = ", ".join(error_labels)
|
error_labels = ", ".join(error_labels)
|
||||||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}".format(error_labels)),
|
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}").format(error_labels),
|
||||||
title = catalog.i18nc("@info:title", "Unable to slice"))
|
title = catalog.i18nc("@info:title", "Unable to slice"))
|
||||||
self._error_message.show()
|
self._error_message.show()
|
||||||
self.backendStateChange.emit(BackendState.Error)
|
self.backendStateChange.emit(BackendState.Error)
|
||||||
|
|
|
@ -240,3 +240,4 @@ class ProcessSlicedLayersJob(Job):
|
||||||
else:
|
else:
|
||||||
if self._progress_message:
|
if self._progress_message:
|
||||||
self._progress_message.hide()
|
self._progress_message.hide()
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2017 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 PyQt5.QtCore import QUrl
|
||||||
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
|
||||||
from UM.Extension import Extension
|
from UM.Extension import Extension
|
||||||
from UM.Preferences import Preferences
|
from UM.Preferences import Preferences
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
@ -32,6 +35,17 @@ class FirmwareUpdateChecker(Extension):
|
||||||
if Preferences.getInstance().getValue("info/automatic_update_check"):
|
if Preferences.getInstance().getValue("info/automatic_update_check"):
|
||||||
ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded)
|
ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded)
|
||||||
|
|
||||||
|
self._download_url = None
|
||||||
|
|
||||||
|
## Callback for the message that is spawned when there is a new version.
|
||||||
|
def _onActionTriggered(self, message, action):
|
||||||
|
if action == "download":
|
||||||
|
if self._download_url is not None:
|
||||||
|
QDesktopServices.openUrl(QUrl(self._download_url))
|
||||||
|
|
||||||
|
def _onSetDownloadUrl(self, download_url):
|
||||||
|
self._download_url = download_url
|
||||||
|
|
||||||
def _onContainerAdded(self, container):
|
def _onContainerAdded(self, container):
|
||||||
# Only take care when a new GlobalStack was added
|
# Only take care when a new GlobalStack was added
|
||||||
if isinstance(container, GlobalStack):
|
if isinstance(container, GlobalStack):
|
||||||
|
@ -45,5 +59,7 @@ class FirmwareUpdateChecker(Extension):
|
||||||
# \param silent type(boolean) Suppresses messages other than "new version found" messages.
|
# \param silent type(boolean) Suppresses messages other than "new version found" messages.
|
||||||
# This is used when checking for a new firmware version at startup.
|
# This is used when checking for a new firmware version at startup.
|
||||||
def checkFirmwareVersion(self, container = None, silent = False):
|
def checkFirmwareVersion(self, container = None, silent = False):
|
||||||
job = FirmwareUpdateCheckerJob(container = container, silent = silent, url = self.JEDI_VERSION_URL)
|
job = FirmwareUpdateCheckerJob(container = container, silent = silent, url = self.JEDI_VERSION_URL,
|
||||||
|
callback = self._onActionTriggered,
|
||||||
|
set_download_url_callback = self._onSetDownloadUrl)
|
||||||
job.start()
|
job.start()
|
||||||
|
|
|
@ -10,30 +10,21 @@ from UM.Job import Job
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import codecs
|
import codecs
|
||||||
|
|
||||||
from PyQt5.QtCore import QUrl
|
|
||||||
from PyQt5.QtGui import QDesktopServices
|
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
i18n_catalog = i18nCatalog("cura")
|
i18n_catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
## This job checks if there is an update available on the provided URL.
|
## This job checks if there is an update available on the provided URL.
|
||||||
class FirmwareUpdateCheckerJob(Job):
|
class FirmwareUpdateCheckerJob(Job):
|
||||||
def __init__(self, container = None, silent = False, url = None):
|
def __init__(self, container = None, silent = False, url = None, callback = None, set_download_url_callback = None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._container = container
|
self._container = container
|
||||||
self.silent = silent
|
self.silent = silent
|
||||||
self._url = url
|
self._url = url
|
||||||
self._download_url = None # If an update was found, the download_url will be set to the location of the new version.
|
self._callback = callback
|
||||||
|
self._set_download_url_callback = set_download_url_callback
|
||||||
## Callback for the message that is spawned when there is a new version.
|
|
||||||
def actionTriggered(self, message, action):
|
|
||||||
if action == "download":
|
|
||||||
if self._download_url is not None:
|
|
||||||
QDesktopServices.openUrl(QUrl(self._download_url))
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self._download_url = None # Reset download ur.
|
|
||||||
if not self._url:
|
if not self._url:
|
||||||
Logger.log("e", "Can not check for a new release. URL not set!")
|
Logger.log("e", "Can not check for a new release. URL not set!")
|
||||||
return
|
return
|
||||||
|
@ -70,13 +61,14 @@ class FirmwareUpdateCheckerJob(Job):
|
||||||
# notify the user when no new firmware version is available.
|
# notify the user when no new firmware version is available.
|
||||||
if (checked_version != "") and (checked_version != current_version):
|
if (checked_version != "") and (checked_version != current_version):
|
||||||
Logger.log("i", "SHOWING FIRMWARE UPDATE MESSAGE")
|
Logger.log("i", "SHOWING FIRMWARE UPDATE MESSAGE")
|
||||||
message = Message(i18n_catalog.i18nc("@info Don't translate {machine_name}, since it gets replaced by a printer name!", "To ensure that your {machine_name} is equipped with the latest features it is recommended to update the firmware regularly. This can be done on the {machine_name} (when connected to the network) or via USB.").format(machine_name = machine_name),
|
message = Message(i18n_catalog.i18nc("@info Don't translate {machine_name}, since it gets replaced by a printer name!", "New features are available for your {machine_name}! It is recommended to update the firmware on your printer.").format(machine_name = machine_name),
|
||||||
title = i18n_catalog.i18nc("@info:title The %s gets replaced with the printer name.", "New %s firmware available") % machine_name)
|
title = i18n_catalog.i18nc("@info:title The %s gets replaced with the printer name.", "New %s firmware available") % machine_name)
|
||||||
message.addAction("download", i18n_catalog.i18nc("@action:button", "Download"), "[no_icon]", "[no_description]")
|
message.addAction("download", i18n_catalog.i18nc("@action:button", "How to update"), "[no_icon]", "[no_description]")
|
||||||
|
|
||||||
# If we do this in a cool way, the download url should be available in the JSON file
|
# If we do this in a cool way, the download url should be available in the JSON file
|
||||||
self._download_url = "https://ultimaker.com/en/resources/20500-upgrade-firmware"
|
if self._set_download_url_callback:
|
||||||
message.actionTriggered.connect(self.actionTriggered)
|
self._set_download_url_callback("https://ultimaker.com/en/resources/20500-upgrade-firmware")
|
||||||
|
message.actionTriggered.connect(self._callback)
|
||||||
message.show()
|
message.show()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -48,7 +48,7 @@ UM.PointingRectangle {
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
leftMargin: UM.Theme.getSize("default_margin").width / 2
|
leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ UM.PointingRectangle {
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.right
|
left: parent.right
|
||||||
leftMargin: UM.Theme.getSize("default_margin").width / 2
|
leftMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,6 @@ class LayerView(View):
|
||||||
self._layer_pass = LayerPass.LayerPass(1, 1)
|
self._layer_pass = LayerPass.LayerPass(1, 1)
|
||||||
self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode"))
|
self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode"))
|
||||||
self._layer_pass.setLayerView(self)
|
self._layer_pass.setLayerView(self)
|
||||||
self.getRenderer().addRenderPass(self._layer_pass)
|
|
||||||
return self._layer_pass
|
return self._layer_pass
|
||||||
|
|
||||||
def getCurrentLayer(self):
|
def getCurrentLayer(self):
|
||||||
|
@ -310,7 +309,8 @@ class LayerView(View):
|
||||||
|
|
||||||
if event.type == Event.ViewActivateEvent:
|
if event.type == Event.ViewActivateEvent:
|
||||||
# Make sure the LayerPass is created
|
# Make sure the LayerPass is created
|
||||||
self.getLayerPass()
|
layer_pass = self.getLayerPass()
|
||||||
|
self.getRenderer().addRenderPass(layer_pass)
|
||||||
|
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||||
self._onGlobalStackChanged()
|
self._onGlobalStackChanged()
|
||||||
|
@ -335,6 +335,7 @@ class LayerView(View):
|
||||||
if self._global_container_stack:
|
if self._global_container_stack:
|
||||||
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
|
self._global_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
|
||||||
|
|
||||||
|
self.getRenderer().removeRenderPass(self._layer_pass)
|
||||||
self._composite_pass.setLayerBindings(self._old_layer_bindings)
|
self._composite_pass.setLayerBindings(self._old_layer_bindings)
|
||||||
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ class MachineSettingsAction(MachineAction):
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def onFinishAction(self):
|
def onFinishAction(self):
|
||||||
# Restore autoslicing when the machineaction is dismissed
|
# Restore autoslicing when the machineaction is dismissed
|
||||||
if self._backend.determineAutoSlicing():
|
if self._backend and self._backend.determineAutoSlicing():
|
||||||
self._backend.tickle()
|
self._backend.tickle()
|
||||||
|
|
||||||
def _onActiveExtruderStackChanged(self):
|
def _onActiveExtruderStackChanged(self):
|
||||||
|
@ -147,6 +147,7 @@ class MachineSettingsAction(MachineAction):
|
||||||
for setting_instance in extruder_user_container.findInstances():
|
for setting_instance in extruder_user_container.findInstances():
|
||||||
setting_key = setting_instance.definition.key
|
setting_key = setting_instance.definition.key
|
||||||
settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder")
|
settable_per_extruder = self._global_container_stack.getProperty(setting_key, "settable_per_extruder")
|
||||||
|
|
||||||
if settable_per_extruder:
|
if settable_per_extruder:
|
||||||
limit_to_extruder = self._global_container_stack.getProperty(setting_key, "limit_to_extruder")
|
limit_to_extruder = self._global_container_stack.getProperty(setting_key, "limit_to_extruder")
|
||||||
|
|
||||||
|
@ -154,11 +155,16 @@ class MachineSettingsAction(MachineAction):
|
||||||
global_user_container.setProperty(setting_key, "value", extruder_user_container.getProperty(setting_key, "value"))
|
global_user_container.setProperty(setting_key, "value", extruder_user_container.getProperty(setting_key, "value"))
|
||||||
extruder_user_container.removeInstance(setting_key)
|
extruder_user_container.removeInstance(setting_key)
|
||||||
|
|
||||||
# Check to see if any features are set to print with an extruder that will no longer exist
|
# reset all extruder number settings whose value is no longer valid
|
||||||
for setting_key in ["adhesion_extruder_nr", "support_extruder_nr", "support_extruder_nr_layer_0", "support_infill_extruder_nr", "support_interface_extruder_nr"]:
|
for setting_instance in self._global_container_stack.userChanges.findInstances():
|
||||||
if int(self._global_container_stack.getProperty(setting_key, "value")) > extruder_count - 1:
|
setting_key = setting_instance.definition.key
|
||||||
Logger.log("i", "Lowering %s setting to match number of extruders", setting_key)
|
if not self._global_container_stack.getProperty(setting_key, "type") in ("extruder", "optional_extruder"):
|
||||||
self._global_container_stack.getTop().setProperty(setting_key, "value", extruder_count - 1)
|
continue
|
||||||
|
|
||||||
|
old_value = int(self._global_container_stack.userChanges.getProperty(setting_key, "value"))
|
||||||
|
if old_value >= extruder_count:
|
||||||
|
self._global_container_stack.userChanges.removeInstance(setting_key)
|
||||||
|
Logger.log("d", "Reset [%s] because its old value [%s] is no longer valid ", setting_key, old_value)
|
||||||
|
|
||||||
# Check to see if any objects are set to print with an extruder that will no longer exist
|
# Check to see if any objects are set to print with an extruder that will no longer exist
|
||||||
root_node = Application.getInstance().getController().getScene().getRoot()
|
root_node = Application.getInstance().getController().getScene().getRoot()
|
||||||
|
|
|
@ -26,7 +26,7 @@ class PluginBrowser(QObject, Extension):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
self._api_version = 1
|
self._api_version = 2
|
||||||
self._api_url = "http://software.ultimaker.com/cura/v%s/" % self._api_version
|
self._api_url = "http://software.ultimaker.com/cura/v%s/" % self._api_version
|
||||||
|
|
||||||
self._plugin_list_request = None
|
self._plugin_list_request = None
|
||||||
|
|
|
@ -114,7 +114,7 @@ UM.Dialog
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
text: "<b>" + model.name + "</b> - " + model.author
|
text: "<b>" + model.name + "</b>" + ((model.author !== "") ? (" - " + model.author) : "")
|
||||||
width: contentWidth
|
width: contentWidth
|
||||||
height: contentHeight + UM.Theme.getSize("default_margin").height
|
height: contentHeight + UM.Theme.getSize("default_margin").height
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
|
|
||||||
from . import RemovableDrivePlugin
|
from . import RemovableDrivePlugin
|
||||||
|
|
||||||
from UM.Logger import Logger
|
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -15,12 +13,12 @@ import plistlib
|
||||||
class OSXRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
class OSXRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
||||||
def checkRemovableDrives(self):
|
def checkRemovableDrives(self):
|
||||||
drives = {}
|
drives = {}
|
||||||
p = subprocess.Popen(["system_profiler", "SPUSBDataType", "-xml"], stdout = subprocess.PIPE)
|
p = subprocess.Popen(["system_profiler", "SPUSBDataType", "-xml"], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||||
plist = plistlib.loads(p.communicate()[0])
|
plist = plistlib.loads(p.communicate()[0])
|
||||||
|
|
||||||
result = self._recursiveSearch(plist, "removable_media")
|
result = self._recursiveSearch(plist, "removable_media")
|
||||||
|
|
||||||
p = subprocess.Popen(["system_profiler", "SPCardReaderDataType", "-xml"], stdout=subprocess.PIPE)
|
p = subprocess.Popen(["system_profiler", "SPCardReaderDataType", "-xml"], stdout=subprocess.PIPE, stderr = subprocess.PIPE)
|
||||||
plist = plistlib.loads(p.communicate()[0])
|
plist = plistlib.loads(p.communicate()[0])
|
||||||
|
|
||||||
result.extend(self._recursiveSearch(plist, "removable_media"))
|
result.extend(self._recursiveSearch(plist, "removable_media"))
|
||||||
|
|
|
@ -83,8 +83,7 @@ Component
|
||||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||||
//TODO; It's probably nicer to do this with a dynamic data model instead of hardcoding this.
|
|
||||||
//But you know the drill; time constraints don't result in elegant code.
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
|
@ -114,7 +114,7 @@ Cura.MachineAction
|
||||||
|
|
||||||
Column
|
Column
|
||||||
{
|
{
|
||||||
width: (parent.width * 0.5) | 0
|
width: Math.floor(parent.width * 0.5)
|
||||||
spacing: UM.Theme.getSize("default_margin").height
|
spacing: UM.Theme.getSize("default_margin").height
|
||||||
|
|
||||||
ScrollView
|
ScrollView
|
||||||
|
@ -191,8 +191,6 @@ Cura.MachineAction
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
//: Tips label
|
|
||||||
//TODO: get actual link from webteam
|
|
||||||
text: catalog.i18nc("@label", "If your printer is not listed, read the <a href='%1'>network printing troubleshooting guide</a>").arg("https://ultimaker.com/en/troubleshooting");
|
text: catalog.i18nc("@label", "If your printer is not listed, read the <a href='%1'>network printing troubleshooting guide</a>").arg("https://ultimaker.com/en/troubleshooting");
|
||||||
onLinkActivated: Qt.openUrlExternally(link)
|
onLinkActivated: Qt.openUrlExternally(link)
|
||||||
}
|
}
|
||||||
|
@ -200,7 +198,7 @@ Cura.MachineAction
|
||||||
}
|
}
|
||||||
Column
|
Column
|
||||||
{
|
{
|
||||||
width: (parent.width * 0.5) | 0
|
width: Math.floor(parent.width * 0.5)
|
||||||
visible: base.selectedPrinter ? true : false
|
visible: base.selectedPrinter ? true : false
|
||||||
spacing: UM.Theme.getSize("default_margin").height
|
spacing: UM.Theme.getSize("default_margin").height
|
||||||
Label
|
Label
|
||||||
|
@ -218,13 +216,13 @@ Cura.MachineAction
|
||||||
columns: 2
|
columns: 2
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
width: (parent.width * 0.5) | 0
|
width: Math.floor(parent.width * 0.5)
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: catalog.i18nc("@label", "Type")
|
text: catalog.i18nc("@label", "Type")
|
||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
width: (parent.width * 0.5) | 0
|
width: Math.floor(parent.width * 0.5)
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text:
|
text:
|
||||||
{
|
{
|
||||||
|
@ -249,25 +247,25 @@ Cura.MachineAction
|
||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
width: (parent.width * 0.5) | 0
|
width: Math.floor(parent.width * 0.5)
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: catalog.i18nc("@label", "Firmware version")
|
text: catalog.i18nc("@label", "Firmware version")
|
||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
width: (parent.width * 0.5) | 0
|
width: Math.floor(parent.width * 0.5)
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: base.selectedPrinter ? base.selectedPrinter.firmwareVersion : ""
|
text: base.selectedPrinter ? base.selectedPrinter.firmwareVersion : ""
|
||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
width: (parent.width * 0.5) | 0
|
width: Math.floor(parent.width * 0.5)
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: catalog.i18nc("@label", "Address")
|
text: catalog.i18nc("@label", "Address")
|
||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
width: (parent.width * 0.5) | 0
|
width: Math.floor(parent.width * 0.5)
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: base.selectedPrinter ? base.selectedPrinter.ipAddress : ""
|
text: base.selectedPrinter ? base.selectedPrinter.ipAddress : ""
|
||||||
}
|
}
|
||||||
|
@ -279,7 +277,7 @@ Cura.MachineAction
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text:{
|
text:{
|
||||||
// The property cluster size does not exist for older UM3 devices.
|
// The property cluster size does not exist for older UM3 devices.
|
||||||
if(base.selectedPrinter != undefined && base.selectedPrinter.clusterSize == null || base.selectedPrinter.clusterSize == 1)
|
if(!base.selectedPrinter || base.selectedPrinter.clusterSize == null || base.selectedPrinter.clusterSize == 1)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@ Component
|
||||||
}
|
}
|
||||||
return (sourceSize.width / sourceSize.height) > (maximumWidth / maximumHeight);
|
return (sourceSize.width / sourceSize.height) > (maximumWidth / maximumHeight);
|
||||||
}
|
}
|
||||||
property real _width: Math.min(maximumWidth, sourceSize.width)
|
property real _width: Math.floor(Math.min(maximumWidth, sourceSize.width))
|
||||||
property real _height: Math.min(maximumHeight, sourceSize.height)
|
property real _height: Math.floor(Math.min(maximumHeight, sourceSize.height))
|
||||||
width: proportionalHeight ? _width : sourceSize.width * _height / sourceSize.height
|
width: proportionalHeight ? _width : Math.floor(sourceSize.width * _height / sourceSize.height)
|
||||||
height: !proportionalHeight ? _height : sourceSize.height * _width / sourceSize.width
|
height: !proportionalHeight ? _height : Math.floor(sourceSize.height * _width / sourceSize.width)
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
onVisibleChanged:
|
onVisibleChanged:
|
||||||
|
|
|
@ -103,6 +103,7 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
|
||||||
self._can_pause = True
|
self._can_pause = True
|
||||||
self._can_abort = True
|
self._can_abort = True
|
||||||
self._can_pre_heat_bed = False
|
self._can_pre_heat_bed = False
|
||||||
|
self._can_control_manually = False
|
||||||
self._cluster_size = int(properties.get(b"cluster_size", 0))
|
self._cluster_size = int(properties.get(b"cluster_size", 0))
|
||||||
|
|
||||||
self._cleanupRequest()
|
self._cleanupRequest()
|
||||||
|
@ -220,7 +221,9 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
|
||||||
self.setPrinters(json_data)
|
self.setPrinters(json_data)
|
||||||
|
|
||||||
def materialHotendChangedMessage(self, callback):
|
def materialHotendChangedMessage(self, callback):
|
||||||
pass # Do nothing.
|
# When there is just one printer, the activate configuration option is enabled
|
||||||
|
if (self._cluster_size == 1):
|
||||||
|
super().materialHotendChangedMessage(callback = callback)
|
||||||
|
|
||||||
def _startCameraStream(self):
|
def _startCameraStream(self):
|
||||||
## Request new image
|
## Request new image
|
||||||
|
|
|
@ -102,6 +102,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||||
self._target_bed_temperature = 0
|
self._target_bed_temperature = 0
|
||||||
self._processing_preheat_requests = True
|
self._processing_preheat_requests = True
|
||||||
|
|
||||||
|
self._can_control_manually = False
|
||||||
|
|
||||||
self.setPriority(3) # Make sure the output device gets selected above local file output
|
self.setPriority(3) # Make sure the output device gets selected above local file output
|
||||||
self.setName(key)
|
self.setName(key)
|
||||||
self.setShortDescription(i18n_catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print over network"))
|
self.setShortDescription(i18n_catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print over network"))
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2017 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
|
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
|
from queue import Queue
|
||||||
|
from threading import Event, Thread
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtSlot
|
||||||
from PyQt5.QtCore import QUrl
|
from PyQt5.QtCore import QUrl
|
||||||
from PyQt5.QtGui import QDesktopServices
|
from PyQt5.QtGui import QDesktopServices
|
||||||
from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager, QNetworkReply
|
from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager
|
||||||
from PyQt5.QtQml import QQmlComponent, QQmlContext
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
|
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
|
||||||
from UM.PluginRegistry import PluginRegistry
|
|
||||||
from UM.Preferences import Preferences
|
from UM.Preferences import Preferences
|
||||||
from UM.Signal import Signal, signalemitter
|
from UM.Signal import Signal, signalemitter
|
||||||
from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo # type: ignore
|
from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo # type: ignore
|
||||||
|
@ -57,6 +56,16 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||||
|
|
||||||
self._network_requests_buffer = {} # store api responses until data is complete
|
self._network_requests_buffer = {} # store api responses until data is complete
|
||||||
|
|
||||||
|
# The zeroconf service changed requests are handled in a separate thread, so we can re-schedule the requests
|
||||||
|
# which fail to get detailed service info.
|
||||||
|
# Any new or re-scheduled requests will be appended to the request queue, and the handling thread will pick
|
||||||
|
# them up and process them.
|
||||||
|
self._service_changed_request_queue = Queue()
|
||||||
|
self._service_changed_request_event = Event()
|
||||||
|
self._service_changed_request_thread = Thread(target = self._handleOnServiceChangedRequests,
|
||||||
|
daemon = True)
|
||||||
|
self._service_changed_request_thread.start()
|
||||||
|
|
||||||
addPrinterSignal = Signal()
|
addPrinterSignal = Signal()
|
||||||
removePrinterSignal = Signal()
|
removePrinterSignal = Signal()
|
||||||
printerListChanged = Signal()
|
printerListChanged = Signal()
|
||||||
|
@ -76,7 +85,7 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||||
# After network switching, one must make a new instance of Zeroconf
|
# After network switching, one must make a new instance of Zeroconf
|
||||||
# On windows, the instance creation is very fast (unnoticable). Other platforms?
|
# On windows, the instance creation is very fast (unnoticable). Other platforms?
|
||||||
self._zero_conf = Zeroconf()
|
self._zero_conf = Zeroconf()
|
||||||
self._browser = ServiceBrowser(self._zero_conf, u'_ultimaker._tcp.local.', [self._onServiceChanged])
|
self._browser = ServiceBrowser(self._zero_conf, u'_ultimaker._tcp.local.', [self._appendServiceChangedRequest])
|
||||||
|
|
||||||
# Look for manual instances from preference
|
# Look for manual instances from preference
|
||||||
for address in self._manual_instances:
|
for address in self._manual_instances:
|
||||||
|
@ -154,7 +163,18 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||||
if status_code == 200:
|
if status_code == 200:
|
||||||
# We know it's a cluster printer
|
# We know it's a cluster printer
|
||||||
Logger.log("d", "Cluster printer detected: [%s]", reply.url())
|
Logger.log("d", "Cluster printer detected: [%s]", reply.url())
|
||||||
|
|
||||||
|
try:
|
||||||
|
cluster_printers_list = json.loads(bytes(reply.readAll()).decode("utf-8"))
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
Logger.log("e", "Printer returned invalid JSON.")
|
||||||
|
return
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
Logger.log("e", "Printer returned incorrect UTF-8.")
|
||||||
|
return
|
||||||
|
|
||||||
self._network_requests_buffer[address]["cluster"] = True
|
self._network_requests_buffer[address]["cluster"] = True
|
||||||
|
self._network_requests_buffer[address]["cluster_size"] = len(cluster_printers_list)
|
||||||
else:
|
else:
|
||||||
Logger.log("d", "This url is not from a cluster printer: [%s]", reply.url())
|
Logger.log("d", "This url is not from a cluster printer: [%s]", reply.url())
|
||||||
self._network_requests_buffer[address]["cluster"] = False
|
self._network_requests_buffer[address]["cluster"] = False
|
||||||
|
@ -166,7 +186,6 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||||
|
|
||||||
instance_name = "manual:%s" % address
|
instance_name = "manual:%s" % address
|
||||||
system_info = self._network_requests_buffer[address]["system"]
|
system_info = self._network_requests_buffer[address]["system"]
|
||||||
is_cluster = self._network_requests_buffer[address]["cluster"]
|
|
||||||
machine = "unknown"
|
machine = "unknown"
|
||||||
if "variant" in system_info:
|
if "variant" in system_info:
|
||||||
variant = system_info["variant"]
|
variant = system_info["variant"]
|
||||||
|
@ -182,10 +201,14 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||||
b"manual": b"true",
|
b"manual": b"true",
|
||||||
b"machine": machine.encode("utf-8")
|
b"machine": machine.encode("utf-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self._network_requests_buffer[address]["cluster"]:
|
||||||
|
properties[b"cluster_size"] = self._network_requests_buffer[address]["cluster_size"]
|
||||||
|
|
||||||
if instance_name in self._printers:
|
if instance_name in self._printers:
|
||||||
# Only replace the printer if it is still in the list of (manual) printers
|
# Only replace the printer if it is still in the list of (manual) printers
|
||||||
self.removePrinter(instance_name)
|
self.removePrinter(instance_name)
|
||||||
self.addPrinter(instance_name, address, properties, force_cluster=is_cluster)
|
self.addPrinter(instance_name, address, properties)
|
||||||
|
|
||||||
del self._network_requests_buffer[address]
|
del self._network_requests_buffer[address]
|
||||||
|
|
||||||
|
@ -216,12 +239,9 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||||
self._printers[key].connectionStateChanged.disconnect(self._onPrinterConnectionStateChanged)
|
self._printers[key].connectionStateChanged.disconnect(self._onPrinterConnectionStateChanged)
|
||||||
|
|
||||||
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
|
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
|
||||||
def addPrinter(self, name, address, properties, force_cluster=False):
|
def addPrinter(self, name, address, properties):
|
||||||
cluster_size = int(properties.get(b"cluster_size", -1))
|
cluster_size = int(properties.get(b"cluster_size", -1))
|
||||||
was_cluster_before = name in self._cluster_printers_seen
|
if cluster_size >= 0:
|
||||||
if was_cluster_before:
|
|
||||||
Logger.log("d", "Printer [%s] had Cura Connect before, so assume it's still equipped with Cura Connect.", name)
|
|
||||||
if force_cluster or cluster_size >= 0 or was_cluster_before:
|
|
||||||
printer = NetworkClusterPrinterOutputDevice.NetworkClusterPrinterOutputDevice(
|
printer = NetworkClusterPrinterOutputDevice.NetworkClusterPrinterOutputDevice(
|
||||||
name, address, properties, self._api_prefix)
|
name, address, properties, self._api_prefix)
|
||||||
else:
|
else:
|
||||||
|
@ -254,7 +274,8 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||||
else:
|
else:
|
||||||
self.getOutputDeviceManager().removeOutputDevice(key)
|
self.getOutputDeviceManager().removeOutputDevice(key)
|
||||||
|
|
||||||
## Handler for zeroConf detection
|
## Handler for zeroConf detection.
|
||||||
|
# Return True or False indicating if the process succeeded.
|
||||||
def _onServiceChanged(self, zeroconf, service_type, name, state_change):
|
def _onServiceChanged(self, zeroconf, service_type, name, state_change):
|
||||||
if state_change == ServiceStateChange.Added:
|
if state_change == ServiceStateChange.Added:
|
||||||
Logger.log("d", "Bonjour service added: %s" % name)
|
Logger.log("d", "Bonjour service added: %s" % name)
|
||||||
|
@ -284,11 +305,50 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
||||||
Logger.log("w", "The type of the found device is '%s', not 'printer'! Ignoring.." % type_of_device )
|
Logger.log("w", "The type of the found device is '%s', not 'printer'! Ignoring.." % type_of_device )
|
||||||
else:
|
else:
|
||||||
Logger.log("w", "Could not get information about %s" % name)
|
Logger.log("w", "Could not get information about %s" % name)
|
||||||
|
return False
|
||||||
|
|
||||||
elif state_change == ServiceStateChange.Removed:
|
elif state_change == ServiceStateChange.Removed:
|
||||||
Logger.log("d", "Bonjour service removed: %s" % name)
|
Logger.log("d", "Bonjour service removed: %s" % name)
|
||||||
self.removePrinterSignal.emit(str(name))
|
self.removePrinterSignal.emit(str(name))
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
## Appends a service changed request so later the handling thread will pick it up and processes it.
|
||||||
|
def _appendServiceChangedRequest(self, zeroconf, service_type, name, state_change):
|
||||||
|
# append the request and set the event so the event handling thread can pick it up
|
||||||
|
item = (zeroconf, service_type, name, state_change)
|
||||||
|
self._service_changed_request_queue.put(item)
|
||||||
|
self._service_changed_request_event.set()
|
||||||
|
|
||||||
|
def _handleOnServiceChangedRequests(self):
|
||||||
|
while True:
|
||||||
|
# wait for the event to be set
|
||||||
|
self._service_changed_request_event.wait(timeout = 5.0)
|
||||||
|
# stop if the application is shutting down
|
||||||
|
if Application.getInstance().isShuttingDown():
|
||||||
|
return
|
||||||
|
|
||||||
|
self._service_changed_request_event.clear()
|
||||||
|
|
||||||
|
# handle all pending requests
|
||||||
|
reschedule_requests = [] # a list of requests that have failed so later they will get re-scheduled
|
||||||
|
while not self._service_changed_request_queue.empty():
|
||||||
|
request = self._service_changed_request_queue.get()
|
||||||
|
zeroconf, service_type, name, state_change = request
|
||||||
|
try:
|
||||||
|
result = self._onServiceChanged(zeroconf, service_type, name, state_change)
|
||||||
|
if not result:
|
||||||
|
reschedule_requests.append(request)
|
||||||
|
except Exception:
|
||||||
|
Logger.logException("e", "Failed to get service info for [%s] [%s], the request will be rescheduled",
|
||||||
|
service_type, name)
|
||||||
|
reschedule_requests.append(request)
|
||||||
|
|
||||||
|
# re-schedule the failed requests if any
|
||||||
|
if reschedule_requests:
|
||||||
|
for request in reschedule_requests:
|
||||||
|
self._service_changed_request_queue.put(request)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def openControlPanel(self):
|
def openControlPanel(self):
|
||||||
Logger.log("d", "Opening print jobs web UI...")
|
Logger.log("d", "Opening print jobs web UI...")
|
||||||
|
|
|
@ -10,7 +10,7 @@ Item
|
||||||
id: extruderInfo
|
id: extruderInfo
|
||||||
property var printCoreConfiguration
|
property var printCoreConfiguration
|
||||||
|
|
||||||
width: parent.width / 2
|
width: Math.floor(parent.width / 2)
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
|
|
|
@ -73,7 +73,7 @@ Rectangle
|
||||||
hoverEnabled: true;
|
hoverEnabled: true;
|
||||||
|
|
||||||
// Only clickable if no printer is selected
|
// Only clickable if no printer is selected
|
||||||
enabled: OutputDevice.selectedPrinterName == ""
|
enabled: OutputDevice.selectedPrinterName == "" && printer.status !== "unreachable"
|
||||||
}
|
}
|
||||||
|
|
||||||
Row
|
Row
|
||||||
|
@ -86,7 +86,7 @@ Rectangle
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
width: parent.width / 3
|
width: Math.floor(parent.width / 3)
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
Label // Print job name
|
Label // Print job name
|
||||||
|
@ -131,7 +131,7 @@ Rectangle
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
width: parent.width / 3 * 2
|
width: Math.floor(parent.width / 3 * 2)
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
Label // Friendly machine name
|
Label // Friendly machine name
|
||||||
|
@ -139,7 +139,7 @@ Rectangle
|
||||||
id: printerNameLabel
|
id: printerNameLabel
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
width: parent.width / 2 - UM.Theme.getSize("default_margin").width - showCameraIcon.width
|
width: Math.floor(parent.width / 2 - UM.Theme.getSize("default_margin").width - showCameraIcon.width)
|
||||||
text: printer.friendly_name
|
text: printer.friendly_name
|
||||||
font: UM.Theme.getFont("default_bold")
|
font: UM.Theme.getFont("default_bold")
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
@ -149,7 +149,7 @@ Rectangle
|
||||||
{
|
{
|
||||||
id: printerTypeLabel
|
id: printerTypeLabel
|
||||||
anchors.top: printerNameLabel.bottom
|
anchors.top: printerNameLabel.bottom
|
||||||
width: parent.width / 2 - UM.Theme.getSize("default_margin").width
|
width: Math.floor(parent.width / 2 - UM.Theme.getSize("default_margin").width)
|
||||||
text: printer.machine_variant
|
text: printer.machine_variant
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
@ -183,7 +183,7 @@ Rectangle
|
||||||
id: extruderInfo
|
id: extruderInfo
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
width: parent.width / 2 - UM.Theme.getSize("default_margin").width
|
width: Math.floor(parent.width / 2 - UM.Theme.getSize("default_margin").width)
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
|
|
||||||
spacing: UM.Theme.getSize("default_margin").width
|
spacing: UM.Theme.getSize("default_margin").width
|
||||||
|
@ -217,7 +217,7 @@ Rectangle
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
height: showExtended ? parent.height: printProgressTitleBar.height
|
height: showExtended ? parent.height: printProgressTitleBar.height
|
||||||
width: parent.width / 2 - UM.Theme.getSize("default_margin").width
|
width: Math.floor(parent.width / 2 - UM.Theme.getSize("default_margin").width)
|
||||||
border.width: UM.Theme.getSize("default_lining").width
|
border.width: UM.Theme.getSize("default_lining").width
|
||||||
border.color: lineColor
|
border.color: lineColor
|
||||||
radius: cornerRadius
|
radius: cornerRadius
|
||||||
|
@ -257,6 +257,11 @@ Rectangle
|
||||||
return catalog.i18nc("@label:status", "Disabled");
|
return catalog.i18nc("@label:status", "Disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (printer.status === "unreachable")
|
||||||
|
{
|
||||||
|
return printerStatusText(printer);
|
||||||
|
}
|
||||||
|
|
||||||
if (printJob != null)
|
if (printJob != null)
|
||||||
{
|
{
|
||||||
switch (printJob.status)
|
switch (printJob.status)
|
||||||
|
@ -327,6 +332,12 @@ Rectangle
|
||||||
{
|
{
|
||||||
return "blocked-icon.svg";
|
return "blocked-icon.svg";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (printer.status === "unreachable")
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
if (printJob != null)
|
if (printJob != null)
|
||||||
{
|
{
|
||||||
if(printJob.status === "queued")
|
if(printJob.status === "queued")
|
||||||
|
@ -378,6 +389,11 @@ Rectangle
|
||||||
return catalog.i18nc("@label", "Not accepting print jobs");
|
return catalog.i18nc("@label", "Not accepting print jobs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (printer.status === "unreachable")
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
if(printJob != null)
|
if(printJob != null)
|
||||||
{
|
{
|
||||||
switch (printJob.status)
|
switch (printJob.status)
|
||||||
|
|
|
@ -57,7 +57,7 @@ Item
|
||||||
{
|
{
|
||||||
id: cameraImage
|
id: cameraImage
|
||||||
width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth)
|
width: Math.min(sourceSize.width === 0 ? 800 * screenScaleFactor : sourceSize.width, maximumWidth)
|
||||||
height: (sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width
|
height: Math.floor((sourceSize.height === 0 ? 600 * screenScaleFactor : sourceSize.height) * width / sourceSize.width)
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
z: 1
|
z: 1
|
||||||
|
|
|
@ -115,8 +115,22 @@ Item
|
||||||
{
|
{
|
||||||
tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura")
|
tooltip: catalog.i18nc("@info:tooltip", "Load the configuration of the printer into Cura")
|
||||||
text: catalog.i18nc("@action:button", "Activate Configuration")
|
text: catalog.i18nc("@action:button", "Activate Configuration")
|
||||||
visible: printerConnected
|
visible: printerConnected && !isClusterPrinter()
|
||||||
onClicked: manager.loadConfigurationFromPrinter()
|
onClicked: manager.loadConfigurationFromPrinter()
|
||||||
|
|
||||||
|
function isClusterPrinter() {
|
||||||
|
if(Cura.MachineManager.printerOutputDevices.length == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var clusterSize = Cura.MachineManager.printerOutputDevices[0].clusterSize;
|
||||||
|
// This is not a cluster printer or the cluster it is just one printer
|
||||||
|
if(clusterSize == undefined || clusterSize == 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="24" viewBox="0 0 25 24">
|
||||||
<path fill="#000" fill-rule="evenodd" d="M6 10h12v4H6v-4zm6 14c6.627 0 12-5.373 12-12S18.627 0 12 0 0 5.373 0 12s5.373 12 12 12z"/>
|
<g fill="none" fill-rule="evenodd" stroke="#000" stroke-width="2.4" transform="translate(.567)">
|
||||||
|
<circle cx="12" cy="12" r="10.8"/>
|
||||||
|
<path stroke-linecap="square" d="M5.5 18.5L18.935 5.065"/>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
Before Width: | Height: | Size: 227 B After Width: | Height: | Size: 311 B |
53
plugins/UserAgreementPlugin/UserAgreement.py
Normal file
53
plugins/UserAgreementPlugin/UserAgreement.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from UM.Extension import Extension
|
||||||
|
from UM.Preferences import Preferences
|
||||||
|
from UM.Application import Application
|
||||||
|
from UM.PluginRegistry import PluginRegistry
|
||||||
|
from UM.Logger import Logger
|
||||||
|
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
|
from PyQt5.QtQml import QQmlComponent, QQmlContext
|
||||||
|
from PyQt5.QtCore import QUrl, QObject, pyqtSlot
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
class UserAgreement(QObject, Extension):
|
||||||
|
def __init__(self, parent = None):
|
||||||
|
super(UserAgreement, self).__init__()
|
||||||
|
self._user_agreement_window = None
|
||||||
|
self._user_agreement_context = None
|
||||||
|
Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated)
|
||||||
|
Preferences.getInstance().addPreference("general/accepted_user_agreement", False)
|
||||||
|
|
||||||
|
def _onEngineCreated(self):
|
||||||
|
if not Preferences.getInstance().getValue("general/accepted_user_agreement"):
|
||||||
|
self.showUserAgreement()
|
||||||
|
|
||||||
|
def showUserAgreement(self):
|
||||||
|
if not self._user_agreement_window:
|
||||||
|
self.createUserAgreementWindow()
|
||||||
|
|
||||||
|
self._user_agreement_window.show()
|
||||||
|
|
||||||
|
@pyqtSlot(bool)
|
||||||
|
def didAgree(self, userChoice):
|
||||||
|
if userChoice:
|
||||||
|
Logger.log("i", "User agreed to the user agreement")
|
||||||
|
Preferences.getInstance().setValue("general/accepted_user_agreement", True)
|
||||||
|
self._user_agreement_window.hide()
|
||||||
|
else:
|
||||||
|
Logger.log("i", "User did NOT agree to the user agreement")
|
||||||
|
Preferences.getInstance().setValue("general/accepted_user_agreement", False)
|
||||||
|
CuraApplication.getInstance().quit()
|
||||||
|
CuraApplication.getInstance().setNeedToShowUserAgreement(False)
|
||||||
|
|
||||||
|
def createUserAgreementWindow(self):
|
||||||
|
path = QUrl.fromLocalFile(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "UserAgreement.qml"))
|
||||||
|
|
||||||
|
component = QQmlComponent(Application.getInstance()._engine, path)
|
||||||
|
self._user_agreement_context = QQmlContext(Application.getInstance()._engine.rootContext())
|
||||||
|
self._user_agreement_context.setContextProperty("manager", self)
|
||||||
|
self._user_agreement_window = component.create(self._user_agreement_context)
|
64
plugins/UserAgreementPlugin/UserAgreement.qml
Normal file
64
plugins/UserAgreementPlugin/UserAgreement.qml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright (c) 2017 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
|
import UM 1.3 as UM
|
||||||
|
|
||||||
|
UM.Dialog
|
||||||
|
{
|
||||||
|
id: baseDialog
|
||||||
|
minimumWidth: Math.floor(UM.Theme.getSize("modal_window_minimum").width * 0.75)
|
||||||
|
minimumHeight: Math.floor(UM.Theme.getSize("modal_window_minimum").height * 0.5)
|
||||||
|
width: minimumWidth
|
||||||
|
height: minimumHeight
|
||||||
|
title: catalog.i18nc("@title:window", "User Agreement")
|
||||||
|
|
||||||
|
TextArea
|
||||||
|
{
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: parent.width
|
||||||
|
anchors.bottom: buttonRow.top
|
||||||
|
text: ' <center><h3>DISCLAIMER BY ULTIMAKER</h3></center>
|
||||||
|
<p>PLEASE READ THIS DISCLAIMER CAREFULLY.</p>
|
||||||
|
<p>EXCEPT WHEN OTHERWISE STATED IN WRITING, ULTIMAKER PROVIDES ANY ULTIMAKER SOFTWARE OR THIRD PARTY SOFTWARE “AS IS” WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF ULTIMAKER SOFTWARE IS WITH YOU.</p>
|
||||||
|
<p>UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, IN NO EVENT WILL ULTIMAKER BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE ANY ULTIMAKER SOFTWARE OR THIRD PARTY SOFTWARE.</p>
|
||||||
|
'
|
||||||
|
readOnly: true;
|
||||||
|
textFormat: TextEdit.RichText
|
||||||
|
}
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
id: buttonRow
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
width: parent.width
|
||||||
|
anchors.bottomMargin: UM.Theme.getSize("default_margin").height
|
||||||
|
|
||||||
|
UM.I18nCatalog { id: catalog; name:"cura" }
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
anchors.right: parent.right
|
||||||
|
text: catalog.i18nc("@action:button", "I understand and agree")
|
||||||
|
onClicked: {
|
||||||
|
manager.didAgree(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button
|
||||||
|
{
|
||||||
|
anchors.left: parent.left
|
||||||
|
text: catalog.i18nc("@action:button", "I don't agree")
|
||||||
|
onClicked: {
|
||||||
|
manager.didAgree(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosing: {
|
||||||
|
manager.didAgree(false)
|
||||||
|
}
|
||||||
|
}
|
10
plugins/UserAgreementPlugin/__init__.py
Normal file
10
plugins/UserAgreementPlugin/__init__.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from . import UserAgreement
|
||||||
|
|
||||||
|
def getMetaData():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def register(app):
|
||||||
|
return {"extension": UserAgreement.UserAgreement()}
|
8
plugins/UserAgreementPlugin/plugin.json
Normal file
8
plugins/UserAgreementPlugin/plugin.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"name": "UserAgreement",
|
||||||
|
"author": "Ultimaker B.V.",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Ask the user once if he/she agrees with our license",
|
||||||
|
"api": 4,
|
||||||
|
"i18n-catalog": "cura"
|
||||||
|
}
|
|
@ -118,24 +118,23 @@ class VersionUpgrade27to30(VersionUpgrade):
|
||||||
if not parser.has_section("general"):
|
if not parser.has_section("general"):
|
||||||
parser.add_section("general")
|
parser.add_section("general")
|
||||||
|
|
||||||
# Need to exclude the following names:
|
# The ultimaker 2 family
|
||||||
# - ultimaker2_plus
|
ultimaker2_prefix_list = ["ultimaker2_extended_",
|
||||||
# - ultimaker2_go
|
"ultimaker2_go_",
|
||||||
# - ultimaker2_extended
|
"ultimaker2_"]
|
||||||
# - ultimaker2_extended_plus
|
# ultimaker 2+ is a different family, so don't do anything with those
|
||||||
exclude_prefix_list = ["ultimaker2_plus_",
|
exclude_prefix_list = ["ultimaker2_extended_plus_",
|
||||||
"ultimaker2_go_",
|
"ultimaker2_plus_"]
|
||||||
"ultimaker2_extended_",
|
|
||||||
"ultimaker2_extended_plus_"]
|
# set machine definition to "ultimaker2" for the custom quality profiles that can be for the ultimaker 2 family
|
||||||
file_base_name = os.path.basename(filename)
|
file_base_name = os.path.basename(filename)
|
||||||
if file_base_name.startswith("ultimaker2_"):
|
is_ultimaker2_family = False
|
||||||
skip_this = False
|
if not any(file_base_name.startswith(ep) for ep in exclude_prefix_list):
|
||||||
for exclude_prefix in exclude_prefix_list:
|
is_ultimaker2_family = any(file_base_name.startswith(ep) for ep in ultimaker2_prefix_list)
|
||||||
if file_base_name.startswith(exclude_prefix):
|
|
||||||
skip_this = True
|
# ultimaker2 family quality profiles used to set as "fdmprinter" profiles
|
||||||
break
|
if is_ultimaker2_family and parser["general"]["definition"] == "fdmprinter":
|
||||||
if not skip_this:
|
parser["general"]["definition"] = "ultimaker2"
|
||||||
parser["general"]["definition"] = "ultimaker2"
|
|
||||||
|
|
||||||
# Update version numbers
|
# Update version numbers
|
||||||
parser["general"]["version"] = "2"
|
parser["general"]["version"] = "2"
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import configparser #To parse preference files.
|
||||||
|
import io #To serialise the preference files afterwards.
|
||||||
|
|
||||||
|
from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this.
|
||||||
|
|
||||||
|
|
||||||
|
# a list of all legacy "Not Supported" quality profiles
|
||||||
|
_OLD_NOT_SUPPORTED_PROFILES = [
|
||||||
|
"um2p_pp_0.25_normal",
|
||||||
|
"um2p_tpu_0.8_normal",
|
||||||
|
"um3_bb0.4_ABS_Fast_Print",
|
||||||
|
"um3_bb0.4_ABS_Superdraft_Print",
|
||||||
|
"um3_bb0.4_CPEP_Fast_Print",
|
||||||
|
"um3_bb0.4_CPEP_Superdraft_Print",
|
||||||
|
"um3_bb0.4_CPE_Fast_Print",
|
||||||
|
"um3_bb0.4_CPE_Superdraft_Print",
|
||||||
|
"um3_bb0.4_Nylon_Fast_Print",
|
||||||
|
"um3_bb0.4_Nylon_Superdraft_Print",
|
||||||
|
"um3_bb0.4_PC_Fast_Print",
|
||||||
|
"um3_bb0.4_PLA_Fast_Print",
|
||||||
|
"um3_bb0.4_PLA_Superdraft_Print",
|
||||||
|
"um3_bb0.4_PP_Fast_Print",
|
||||||
|
"um3_bb0.4_PP_Superdraft_Print",
|
||||||
|
"um3_bb0.4_TPU_Fast_Print",
|
||||||
|
"um3_bb0.4_TPU_Superdraft_Print",
|
||||||
|
"um3_bb0.8_ABS_Fast_Print",
|
||||||
|
"um3_bb0.8_ABS_Superdraft_Print",
|
||||||
|
"um3_bb0.8_CPEP_Fast_Print",
|
||||||
|
"um3_bb0.8_CPEP_Superdraft_Print",
|
||||||
|
"um3_bb0.8_CPE_Fast_Print",
|
||||||
|
"um3_bb0.8_CPE_Superdraft_Print",
|
||||||
|
"um3_bb0.8_Nylon_Fast_Print",
|
||||||
|
"um3_bb0.8_Nylon_Superdraft_Print",
|
||||||
|
"um3_bb0.8_PC_Fast_Print",
|
||||||
|
"um3_bb0.8_PC_Superdraft_Print",
|
||||||
|
"um3_bb0.8_PLA_Fast_Print",
|
||||||
|
"um3_bb0.8_PLA_Superdraft_Print",
|
||||||
|
"um3_bb0.8_PP_Fast_Print",
|
||||||
|
"um3_bb0.8_PP_Superdraft_Print",
|
||||||
|
"um3_bb0.8_TPU_Fast_print",
|
||||||
|
"um3_bb0.8_TPU_Superdraft_Print",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class VersionUpgrade30to31(VersionUpgrade):
|
||||||
|
## Gets the version number from a CFG file in Uranium's 3.0 format.
|
||||||
|
#
|
||||||
|
# Since the format may change, this is implemented for the 3.0 format only
|
||||||
|
# and needs to be included in the version upgrade system rather than
|
||||||
|
# globally in Uranium.
|
||||||
|
#
|
||||||
|
# \param serialised The serialised form of a CFG file.
|
||||||
|
# \return The version number stored in the CFG file.
|
||||||
|
# \raises ValueError The format of the version number in the file is
|
||||||
|
# incorrect.
|
||||||
|
# \raises KeyError The format of the file is incorrect.
|
||||||
|
def getCfgVersion(self, serialised):
|
||||||
|
parser = configparser.ConfigParser(interpolation = None)
|
||||||
|
parser.read_string(serialised)
|
||||||
|
format_version = int(parser.get("general", "version")) #Explicitly give an exception when this fails. That means that the file format is not recognised.
|
||||||
|
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
|
||||||
|
return format_version * 1000000 + setting_version
|
||||||
|
|
||||||
|
## Upgrades a preferences file from version 3.0 to 3.1.
|
||||||
|
#
|
||||||
|
# \param serialised The serialised form of a preferences file.
|
||||||
|
# \param filename The name of the file to upgrade.
|
||||||
|
def upgradePreferences(self, serialised, filename):
|
||||||
|
parser = configparser.ConfigParser(interpolation=None)
|
||||||
|
parser.read_string(serialised)
|
||||||
|
|
||||||
|
# Update version numbers
|
||||||
|
if "general" not in parser:
|
||||||
|
parser["general"] = {}
|
||||||
|
parser["general"]["version"] = "5"
|
||||||
|
if "metadata" not in parser:
|
||||||
|
parser["metadata"] = {}
|
||||||
|
parser["metadata"]["setting_version"] = "4"
|
||||||
|
|
||||||
|
# Re-serialise the file.
|
||||||
|
output = io.StringIO()
|
||||||
|
parser.write(output)
|
||||||
|
return [filename], [output.getvalue()]
|
||||||
|
|
||||||
|
## Upgrades the given instance container file from version 3.0 to 3.1.
|
||||||
|
#
|
||||||
|
# \param serialised The serialised form of the container file.
|
||||||
|
# \param filename The name of the file to upgrade.
|
||||||
|
def upgradeInstanceContainer(self, serialised, filename):
|
||||||
|
parser = configparser.ConfigParser(interpolation=None)
|
||||||
|
parser.read_string(serialised)
|
||||||
|
|
||||||
|
for each_section in ("general", "metadata"):
|
||||||
|
if not parser.has_section(each_section):
|
||||||
|
parser.add_section(each_section)
|
||||||
|
|
||||||
|
# Update version numbers
|
||||||
|
parser["general"]["version"] = "2"
|
||||||
|
parser["metadata"]["setting_version"] = "4"
|
||||||
|
|
||||||
|
# Re-serialise the file.
|
||||||
|
output = io.StringIO()
|
||||||
|
parser.write(output)
|
||||||
|
return [filename], [output.getvalue()]
|
||||||
|
|
||||||
|
|
||||||
|
## Upgrades a container stack from version 3.0 to 3.1.
|
||||||
|
#
|
||||||
|
# \param serialised The serialised form of a container stack.
|
||||||
|
# \param filename The name of the file to upgrade.
|
||||||
|
def upgradeStack(self, serialised, filename):
|
||||||
|
parser = configparser.ConfigParser(interpolation=None)
|
||||||
|
parser.read_string(serialised)
|
||||||
|
|
||||||
|
for each_section in ("general", "metadata"):
|
||||||
|
if not parser.has_section(each_section):
|
||||||
|
parser.add_section(each_section)
|
||||||
|
|
||||||
|
# change "not supported" quality profiles to empty because they no longer exist
|
||||||
|
if parser.has_section("containers"):
|
||||||
|
if parser.has_option("containers", "2"):
|
||||||
|
quality_profile_id = parser["containers"]["2"]
|
||||||
|
if quality_profile_id in _OLD_NOT_SUPPORTED_PROFILES:
|
||||||
|
parser["containers"]["2"] = "empty_quality"
|
||||||
|
|
||||||
|
# Update version numbers
|
||||||
|
if "general" not in parser:
|
||||||
|
parser["general"] = {}
|
||||||
|
parser["general"]["version"] = "3"
|
||||||
|
|
||||||
|
if "metadata" not in parser:
|
||||||
|
parser["metadata"] = {}
|
||||||
|
parser["metadata"]["setting_version"] = "4"
|
||||||
|
|
||||||
|
# Re-serialise the file.
|
||||||
|
output = io.StringIO()
|
||||||
|
parser.write(output)
|
||||||
|
return [filename], [output.getvalue()]
|
56
plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py
Normal file
56
plugins/VersionUpgrade/VersionUpgrade30to31/__init__.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from . import VersionUpgrade30to31
|
||||||
|
|
||||||
|
upgrade = VersionUpgrade30to31.VersionUpgrade30to31()
|
||||||
|
|
||||||
|
def getMetaData():
|
||||||
|
return {
|
||||||
|
"version_upgrade": {
|
||||||
|
# From To Upgrade function
|
||||||
|
("preferences", 5000003): ("preferences", 5000004, upgrade.upgradePreferences),
|
||||||
|
|
||||||
|
("machine_stack", 3000003): ("machine_stack", 3000004, upgrade.upgradeStack),
|
||||||
|
("extruder_train", 3000003): ("extruder_train", 3000004, upgrade.upgradeStack),
|
||||||
|
|
||||||
|
("quality_changes", 2000003): ("quality_changes", 2000004, upgrade.upgradeInstanceContainer),
|
||||||
|
("user", 2000003): ("user", 2000004, upgrade.upgradeInstanceContainer),
|
||||||
|
("quality", 2000003): ("quality", 2000004, upgrade.upgradeInstanceContainer),
|
||||||
|
("definition_changes", 2000003): ("definition_changes", 2000004, upgrade.upgradeInstanceContainer),
|
||||||
|
("variant", 2000003): ("variant", 2000004, upgrade.upgradeInstanceContainer)
|
||||||
|
},
|
||||||
|
"sources": {
|
||||||
|
"preferences": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"."}
|
||||||
|
},
|
||||||
|
"machine_stack": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"./machine_instances"}
|
||||||
|
},
|
||||||
|
"extruder_train": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"./extruders"}
|
||||||
|
},
|
||||||
|
"quality_changes": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"./quality"}
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"./user"}
|
||||||
|
},
|
||||||
|
"definition_changes": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"./definition_changes"}
|
||||||
|
},
|
||||||
|
"variant": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"./variants"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def register(app):
|
||||||
|
return { "version_upgrade": upgrade }
|
8
plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json
Normal file
8
plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"name": "Version Upgrade 3.0 to 3.1",
|
||||||
|
"author": "Ultimaker B.V.",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Upgrades configurations from Cura 3.0 to Cura 3.1.",
|
||||||
|
"api": 4,
|
||||||
|
"i18n-catalog": "cura"
|
||||||
|
}
|
|
@ -56,7 +56,8 @@ class XRayView(View):
|
||||||
# Currently the RenderPass constructor requires a size > 0
|
# Currently the RenderPass constructor requires a size > 0
|
||||||
# This should be fixed in RenderPass's constructor.
|
# This should be fixed in RenderPass's constructor.
|
||||||
self._xray_pass = XRayPass.XRayPass(1, 1)
|
self._xray_pass = XRayPass.XRayPass(1, 1)
|
||||||
self.getRenderer().addRenderPass(self._xray_pass)
|
|
||||||
|
self.getRenderer().addRenderPass(self._xray_pass)
|
||||||
|
|
||||||
if not self._xray_composite_shader:
|
if not self._xray_composite_shader:
|
||||||
self._xray_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray_composite.shader"))
|
self._xray_composite_shader = OpenGL.getInstance().createShaderProgram(os.path.join(PluginRegistry.getInstance().getPluginPath("XRayView"), "xray_composite.shader"))
|
||||||
|
@ -74,5 +75,6 @@ class XRayView(View):
|
||||||
self._composite_pass.setCompositeShader(self._xray_composite_shader)
|
self._composite_pass.setCompositeShader(self._xray_composite_shader)
|
||||||
|
|
||||||
if event.type == Event.ViewDeactivateEvent:
|
if event.type == Event.ViewDeactivateEvent:
|
||||||
|
self.getRenderer().removeRenderPass(self._xray_pass)
|
||||||
self._composite_pass.setLayerBindings(self._old_layer_bindings)
|
self._composite_pass.setLayerBindings(self._old_layer_bindings)
|
||||||
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
self._composite_pass.setCompositeShader(self._old_composite_shader)
|
||||||
|
|
|
@ -33,9 +33,10 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
#
|
#
|
||||||
# \param xml_version: The version number found in an XML file.
|
# \param xml_version: The version number found in an XML file.
|
||||||
# \return The corresponding setting_version.
|
# \return The corresponding setting_version.
|
||||||
def xmlVersionToSettingVersion(self, xml_version: str) -> int:
|
@classmethod
|
||||||
|
def xmlVersionToSettingVersion(cls, xml_version: str) -> int:
|
||||||
if xml_version == "1.3":
|
if xml_version == "1.3":
|
||||||
return 3
|
return CuraApplication.SettingVersion
|
||||||
return 0 #Older than 1.3.
|
return 0 #Older than 1.3.
|
||||||
|
|
||||||
def getInheritedFiles(self):
|
def getInheritedFiles(self):
|
||||||
|
@ -220,10 +221,15 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
|
|
||||||
machine_container_map[definition_id] = container
|
machine_container_map[definition_id] = container
|
||||||
|
|
||||||
|
# Map machine human-readable names to IDs
|
||||||
|
product_id_map = {}
|
||||||
|
for container in registry.findDefinitionContainers(type = "machine"):
|
||||||
|
product_id_map[container.getName()] = container.getId()
|
||||||
|
|
||||||
for definition_id, container in machine_container_map.items():
|
for definition_id, container in machine_container_map.items():
|
||||||
definition = container.getDefinition()
|
definition = container.getDefinition()
|
||||||
try:
|
try:
|
||||||
product = UM.Dictionary.findKey(self.__product_id_map, definition_id)
|
product = UM.Dictionary.findKey(product_id_map, definition_id)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# An unknown product id; export it anyway
|
# An unknown product id; export it anyway
|
||||||
product = definition_id
|
product = definition_id
|
||||||
|
@ -402,15 +408,16 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
def getConfigurationTypeFromSerialized(self, serialized: str) -> Optional[str]:
|
def getConfigurationTypeFromSerialized(self, serialized: str) -> Optional[str]:
|
||||||
return "materials"
|
return "materials"
|
||||||
|
|
||||||
def getVersionFromSerialized(self, serialized: str) -> Optional[int]:
|
@classmethod
|
||||||
|
def getVersionFromSerialized(cls, serialized: str) -> Optional[int]:
|
||||||
data = ET.fromstring(serialized)
|
data = ET.fromstring(serialized)
|
||||||
|
|
||||||
version = 1
|
version = XmlMaterialProfile.Version
|
||||||
# get setting version
|
# get setting version
|
||||||
if "version" in data.attrib:
|
if "version" in data.attrib:
|
||||||
setting_version = self.xmlVersionToSettingVersion(data.attrib["version"])
|
setting_version = XmlMaterialProfile.xmlVersionToSettingVersion(data.attrib["version"])
|
||||||
else:
|
else:
|
||||||
setting_version = self.xmlVersionToSettingVersion("1.2")
|
setting_version = XmlMaterialProfile.xmlVersionToSettingVersion("1.2")
|
||||||
|
|
||||||
return version * 1000000 + setting_version
|
return version * 1000000 + setting_version
|
||||||
|
|
||||||
|
@ -504,14 +511,17 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
elif key in self.__unmapped_settings:
|
elif key in self.__unmapped_settings:
|
||||||
if key == "hardware compatible":
|
if key == "hardware compatible":
|
||||||
common_compatibility = self._parseCompatibleValue(entry.text)
|
common_compatibility = self._parseCompatibleValue(entry.text)
|
||||||
else:
|
|
||||||
Logger.log("d", "Unsupported material setting %s", key)
|
|
||||||
self._cached_values = common_setting_values # from InstanceContainer ancestor
|
self._cached_values = common_setting_values # from InstanceContainer ancestor
|
||||||
|
|
||||||
meta_data["compatible"] = common_compatibility
|
meta_data["compatible"] = common_compatibility
|
||||||
self.setMetaData(meta_data)
|
self.setMetaData(meta_data)
|
||||||
self._dirty = False
|
self._dirty = False
|
||||||
|
|
||||||
|
# Map machine human-readable names to IDs
|
||||||
|
product_id_map = {}
|
||||||
|
for container in ContainerRegistry.getInstance().findDefinitionContainers(type = "machine"):
|
||||||
|
product_id_map[container.getName()] = container.getId()
|
||||||
|
|
||||||
machines = data.iterfind("./um:settings/um:machine", self.__namespaces)
|
machines = data.iterfind("./um:settings/um:machine", self.__namespaces)
|
||||||
for machine in machines:
|
for machine in machines:
|
||||||
machine_compatibility = common_compatibility
|
machine_compatibility = common_compatibility
|
||||||
|
@ -532,7 +542,7 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
|
|
||||||
identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces)
|
identifiers = machine.iterfind("./um:machine_identifier", self.__namespaces)
|
||||||
for identifier in identifiers:
|
for identifier in identifiers:
|
||||||
machine_id = self.__product_id_map.get(identifier.get("product"), None)
|
machine_id = product_id_map.get(identifier.get("product"), None)
|
||||||
if machine_id is None:
|
if machine_id is None:
|
||||||
# Lets try again with some naive heuristics.
|
# Lets try again with some naive heuristics.
|
||||||
machine_id = identifier.get("product").replace(" ", "").lower()
|
machine_id = identifier.get("product").replace(" ", "").lower()
|
||||||
|
@ -666,7 +676,9 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
"processing temperature graph": "material_flow_temp_graph",
|
"processing temperature graph": "material_flow_temp_graph",
|
||||||
"print cooling": "cool_fan_speed",
|
"print cooling": "cool_fan_speed",
|
||||||
"retraction amount": "retraction_amount",
|
"retraction amount": "retraction_amount",
|
||||||
"retraction speed": "retraction_speed"
|
"retraction speed": "retraction_speed",
|
||||||
|
"adhesion tendency": "material_adhesion_tendency",
|
||||||
|
"surface energy": "material_surface_energy"
|
||||||
}
|
}
|
||||||
__unmapped_settings = [
|
__unmapped_settings = [
|
||||||
"hardware compatible"
|
"hardware compatible"
|
||||||
|
@ -678,21 +690,6 @@ class XmlMaterialProfile(InstanceContainer):
|
||||||
"GUID": "material_guid"
|
"GUID": "material_guid"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Map XML file product names to internal ids
|
|
||||||
# TODO: Move this to definition's metadata
|
|
||||||
__product_id_map = {
|
|
||||||
"Ultimaker 3": "ultimaker3",
|
|
||||||
"Ultimaker 3 Extended": "ultimaker3_extended",
|
|
||||||
"Ultimaker 2": "ultimaker2",
|
|
||||||
"Ultimaker 2+": "ultimaker2_plus",
|
|
||||||
"Ultimaker 2 Go": "ultimaker2_go",
|
|
||||||
"Ultimaker 2 Extended": "ultimaker2_extended",
|
|
||||||
"Ultimaker 2 Extended+": "ultimaker2_extended_plus",
|
|
||||||
"Ultimaker Original": "ultimaker_original",
|
|
||||||
"Ultimaker Original+": "ultimaker_original_plus",
|
|
||||||
"IMADE3D JellyBOX": "imade3d_jellybox"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Map of recognised namespaces with a proper prefix.
|
# Map of recognised namespaces with a proper prefix.
|
||||||
__namespaces = {
|
__namespaces = {
|
||||||
"um": "http://www.ultimaker.com/material"
|
"um": "http://www.ultimaker.com/material"
|
||||||
|
|
|
@ -5,24 +5,16 @@ import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from UM.VersionUpgrade import VersionUpgrade
|
from UM.VersionUpgrade import VersionUpgrade
|
||||||
|
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
from .XmlMaterialProfile import XmlMaterialProfile
|
||||||
|
|
||||||
|
|
||||||
class XmlMaterialUpgrader(VersionUpgrade):
|
class XmlMaterialUpgrader(VersionUpgrade):
|
||||||
def getXmlVersion(self, serialized):
|
def getXmlVersion(self, serialized):
|
||||||
data = ET.fromstring(serialized)
|
return XmlMaterialProfile.getVersionFromSerialized(serialized)
|
||||||
|
|
||||||
version = 1
|
|
||||||
# get setting version
|
|
||||||
if "version" in data.attrib:
|
|
||||||
setting_version = self._xmlVersionToSettingVersion(data.attrib["version"])
|
|
||||||
else:
|
|
||||||
setting_version = self._xmlVersionToSettingVersion("1.2")
|
|
||||||
|
|
||||||
return version * 1000000 + setting_version
|
|
||||||
|
|
||||||
def _xmlVersionToSettingVersion(self, xml_version: str) -> int:
|
def _xmlVersionToSettingVersion(self, xml_version: str) -> int:
|
||||||
if xml_version == "1.3":
|
return XmlMaterialProfile.xmlVersionToSettingVersion(xml_version)
|
||||||
return 2
|
|
||||||
return 0 #Older than 1.3.
|
|
||||||
|
|
||||||
def upgradeMaterial(self, serialised, filename):
|
def upgradeMaterial(self, serialised, filename):
|
||||||
data = ET.fromstring(serialised)
|
data = ET.fromstring(serialised)
|
||||||
|
|
|
@ -19,7 +19,7 @@ def getMetaData():
|
||||||
"mimetype": "application/x-ultimaker-material-profile"
|
"mimetype": "application/x-ultimaker-material-profile"
|
||||||
},
|
},
|
||||||
"version_upgrade": {
|
"version_upgrade": {
|
||||||
("materials", 1000000): ("materials", 1000003, upgrader.upgradeMaterial),
|
("materials", 1000000): ("materials", 1000004, upgrader.upgradeMaterial),
|
||||||
},
|
},
|
||||||
"sources": {
|
"sources": {
|
||||||
"materials": {
|
"materials": {
|
||||||
|
|
117
resources/definitions/builder_premium_large.def.json
Normal file
117
resources/definitions/builder_premium_large.def.json
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_large",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Builder Premium Large",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Builder SZ",
|
||||||
|
"manufacturer": "Builder",
|
||||||
|
"category": "Other",
|
||||||
|
"quality_definition": "builder_premium_small",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"platform": "builder_premium_platform.stl",
|
||||||
|
"platform_offset": [-126, -36, 117],
|
||||||
|
"has_machine_quality": true,
|
||||||
|
"preferred_quality": "*Normal*",
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "builder_premium_large_rear",
|
||||||
|
"1": "builder_premium_large_front"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Builder Premium Large" },
|
||||||
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
"machine_width": { "default_value": 215 },
|
||||||
|
"machine_height": { "default_value": 600 },
|
||||||
|
"machine_depth": { "default_value": 205 },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
|
||||||
|
"infill_pattern": {"value": "'triangles'" },
|
||||||
|
"infill_before_walls": {"value": false },
|
||||||
|
|
||||||
|
"default_material_print_temperature": { "value": "215" },
|
||||||
|
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
|
||||||
|
"material_standby_temperature": { "value": "material_print_temperature" },
|
||||||
|
|
||||||
|
"switch_extruder_retraction_speeds": {"default_value": 15 },
|
||||||
|
"switch_extruder_retraction_speed": {"default_value": 15 },
|
||||||
|
"switch_extruder_prime_speed": {"default_value": 15 },
|
||||||
|
"switch_extruder_retraction_amount": {"value": 1 },
|
||||||
|
|
||||||
|
"speed_travel": { "value": "100" },
|
||||||
|
"speed_layer_0": { "value": "20" },
|
||||||
|
"speed_prime_tower": { "value": "speed_topbottom" },
|
||||||
|
"speed_print": { "value": "40" },
|
||||||
|
"speed_support": { "value": "speed_wall_0" },
|
||||||
|
"speed_support_interface": { "value": "speed_topbottom" },
|
||||||
|
"speed_topbottom": { "value": "math.ceil(speed_print * 20 / 35)" },
|
||||||
|
"speed_wall": { "value": "math.ceil(speed_print * 30 / 40)" },
|
||||||
|
"speed_wall_0": { "value": "math.ceil(speed_wall * 20 / 25)" },
|
||||||
|
"speed_wall_x": { "value": "speed_wall" },
|
||||||
|
|
||||||
|
"prime_tower_position_x": { "default_value": 175 },
|
||||||
|
"prime_tower_position_y": { "default_value": 178 },
|
||||||
|
"prime_tower_wipe_enabled": { "default_value": false },
|
||||||
|
"prime_tower_min_volume": { "default_value": 50 },
|
||||||
|
"dual_pre_wipe": { "default_value": false },
|
||||||
|
|
||||||
|
"prime_blob_enable": { "enabled": true },
|
||||||
|
|
||||||
|
"acceleration_enabled": { "value": "True" },
|
||||||
|
"acceleration_layer_0": { "value": "acceleration_topbottom" },
|
||||||
|
"acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
|
||||||
|
"acceleration_print": { "value": "3000" },
|
||||||
|
"acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
|
||||||
|
"acceleration_support_interface": { "value": "acceleration_topbottom" },
|
||||||
|
"acceleration_topbottom": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
|
||||||
|
"acceleration_travel": { "value": "acceleration_print" },
|
||||||
|
"acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
|
||||||
|
"acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 1000 / 1000)" },
|
||||||
|
|
||||||
|
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
|
||||||
|
"cool_min_layer_time": { "default_value": 10 },
|
||||||
|
|
||||||
|
"jerk_enabled": { "value": "True" },
|
||||||
|
"jerk_layer_0": { "value": "jerk_topbottom" },
|
||||||
|
"jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" },
|
||||||
|
"jerk_print": { "value": "25" },
|
||||||
|
"jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" },
|
||||||
|
"jerk_support_interface": { "value": "jerk_topbottom" },
|
||||||
|
"jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" },
|
||||||
|
"jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" },
|
||||||
|
"jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" },
|
||||||
|
|
||||||
|
"wall_thickness": { "value": "1.2" },
|
||||||
|
|
||||||
|
"retraction_amount": { "default_value": 3 },
|
||||||
|
"retraction_speed": { "default_value": 15 },
|
||||||
|
"retraction_retract_speed": { "default_value": 15 },
|
||||||
|
"retraction_prime_speed": { "default_value": 15 },
|
||||||
|
"travel_retract_before_outer_wall": { "default_value": true },
|
||||||
|
"skin_overlap": { "value": "15" },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_nozzle_heat_up_speed": { "default_value": 2 },
|
||||||
|
"machine_nozzle_cool_down_speed": { "default_value": 2 },
|
||||||
|
"machine_head_polygon": { "default_value": [[-75, -18],[-75, 35],[18, 35],[18, -18]] },
|
||||||
|
"gantry_height": { "default_value": 55 },
|
||||||
|
"machine_max_feedrate_x": { "default_value": 300 },
|
||||||
|
"machine_max_feedrate_y": { "default_value": 300 },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 40 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E15 ;extrude 15mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nT0 ;Start with Rear Extruder\n;Put printing message on LCD screen\nM117 Printing..."
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": { "default_value": 2 }
|
||||||
|
}
|
||||||
|
}
|
117
resources/definitions/builder_premium_medium.def.json
Normal file
117
resources/definitions/builder_premium_medium.def.json
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_medium",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Builder Premium Medium",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Builder SZ",
|
||||||
|
"manufacturer": "Builder",
|
||||||
|
"category": "Other",
|
||||||
|
"quality_definition": "builder_premium_small",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"platform": "builder_premium_platform.stl",
|
||||||
|
"platform_offset": [-126, -36, 117],
|
||||||
|
"has_machine_quality": true,
|
||||||
|
"preferred_quality": "*Normal*",
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "builder_premium_medium_rear",
|
||||||
|
"1": "builder_premium_medium_front"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Builder Premium Medium" },
|
||||||
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
"machine_width": { "default_value": 215 },
|
||||||
|
"machine_height": { "default_value": 400 },
|
||||||
|
"machine_depth": { "default_value": 205 },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
|
||||||
|
"infill_pattern": {"value": "'triangles'" },
|
||||||
|
"infill_before_walls": {"value": false },
|
||||||
|
|
||||||
|
"default_material_print_temperature": { "value": "215" },
|
||||||
|
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
|
||||||
|
"material_standby_temperature": { "value": "material_print_temperature" },
|
||||||
|
|
||||||
|
"switch_extruder_retraction_speeds": {"default_value": 15 },
|
||||||
|
"switch_extruder_retraction_speed": {"default_value": 15 },
|
||||||
|
"switch_extruder_prime_speed": {"default_value": 15 },
|
||||||
|
"switch_extruder_retraction_amount": {"value": 1 },
|
||||||
|
|
||||||
|
"speed_travel": { "value": "100" },
|
||||||
|
"speed_layer_0": { "value": "20" },
|
||||||
|
"speed_prime_tower": { "value": "speed_topbottom" },
|
||||||
|
"speed_print": { "value": "40" },
|
||||||
|
"speed_support": { "value": "speed_wall_0" },
|
||||||
|
"speed_support_interface": { "value": "speed_topbottom" },
|
||||||
|
"speed_topbottom": { "value": "math.ceil(speed_print * 20 / 35)" },
|
||||||
|
"speed_wall": { "value": "math.ceil(speed_print * 30 / 40)" },
|
||||||
|
"speed_wall_0": { "value": "math.ceil(speed_wall * 20 / 25)" },
|
||||||
|
"speed_wall_x": { "value": "speed_wall" },
|
||||||
|
|
||||||
|
"prime_tower_position_x": { "default_value": 175 },
|
||||||
|
"prime_tower_position_y": { "default_value": 178 },
|
||||||
|
"prime_tower_wipe_enabled": { "default_value": false },
|
||||||
|
"prime_tower_min_volume": { "default_value": 50 },
|
||||||
|
"dual_pre_wipe": { "default_value": false },
|
||||||
|
|
||||||
|
"prime_blob_enable": { "enabled": true },
|
||||||
|
|
||||||
|
"acceleration_enabled": { "value": "True" },
|
||||||
|
"acceleration_layer_0": { "value": "acceleration_topbottom" },
|
||||||
|
"acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
|
||||||
|
"acceleration_print": { "value": "3000" },
|
||||||
|
"acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
|
||||||
|
"acceleration_support_interface": { "value": "acceleration_topbottom" },
|
||||||
|
"acceleration_topbottom": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
|
||||||
|
"acceleration_travel": { "value": "acceleration_print" },
|
||||||
|
"acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
|
||||||
|
"acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 1000 / 1000)" },
|
||||||
|
|
||||||
|
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
|
||||||
|
"cool_min_layer_time": { "default_value": 10 },
|
||||||
|
|
||||||
|
"jerk_enabled": { "value": "True" },
|
||||||
|
"jerk_layer_0": { "value": "jerk_topbottom" },
|
||||||
|
"jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" },
|
||||||
|
"jerk_print": { "value": "25" },
|
||||||
|
"jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" },
|
||||||
|
"jerk_support_interface": { "value": "jerk_topbottom" },
|
||||||
|
"jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" },
|
||||||
|
"jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" },
|
||||||
|
"jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" },
|
||||||
|
|
||||||
|
"wall_thickness": { "value": "1.2" },
|
||||||
|
|
||||||
|
"retraction_amount": { "default_value": 3 },
|
||||||
|
"retraction_speed": { "default_value": 15 },
|
||||||
|
"retraction_retract_speed": { "default_value": 15 },
|
||||||
|
"retraction_prime_speed": { "default_value": 15 },
|
||||||
|
"travel_retract_before_outer_wall": { "default_value": true },
|
||||||
|
"skin_overlap": { "value": "15" },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_nozzle_heat_up_speed": { "default_value": 2 },
|
||||||
|
"machine_nozzle_cool_down_speed": { "default_value": 2 },
|
||||||
|
"machine_head_polygon": { "default_value": [[-75, -18],[-75, 35],[18, 35],[18, -18]] },
|
||||||
|
"gantry_height": { "default_value": 55 },
|
||||||
|
"machine_max_feedrate_x": { "default_value": 300 },
|
||||||
|
"machine_max_feedrate_y": { "default_value": 300 },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 40 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E15 ;extrude 15mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nT0 ;Start with Rear Extruder\n;Put printing message on LCD screen\nM117 Printing..."
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": { "default_value": 2 }
|
||||||
|
}
|
||||||
|
}
|
116
resources/definitions/builder_premium_small.def.json
Normal file
116
resources/definitions/builder_premium_small.def.json
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_small",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Builder Premium Small",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Builder SZ",
|
||||||
|
"manufacturer": "Builder",
|
||||||
|
"category": "Other",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"platform": "builder_premium_platform.stl",
|
||||||
|
"platform_offset": [-126, -36, 117],
|
||||||
|
"has_machine_quality": true,
|
||||||
|
"preferred_quality": "*Normal*",
|
||||||
|
"machine_extruder_trains":
|
||||||
|
{
|
||||||
|
"0": "builder_premium_small_rear",
|
||||||
|
"1": "builder_premium_small_front"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": { "default_value": "Builder Premium Small" },
|
||||||
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
"machine_width": { "default_value": 215 },
|
||||||
|
"machine_height": { "default_value": 200 },
|
||||||
|
"machine_depth": { "default_value": 205 },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
|
||||||
|
"infill_pattern": {"value": "'triangles'" },
|
||||||
|
"infill_before_walls": {"value": false },
|
||||||
|
|
||||||
|
"default_material_print_temperature": { "value": "215" },
|
||||||
|
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
|
||||||
|
"material_standby_temperature": { "value": "material_print_temperature" },
|
||||||
|
|
||||||
|
"switch_extruder_retraction_speeds": {"default_value": 15 },
|
||||||
|
"switch_extruder_retraction_speed": {"default_value": 15 },
|
||||||
|
"switch_extruder_prime_speed": {"default_value": 15 },
|
||||||
|
"switch_extruder_retraction_amount": {"value": 1 },
|
||||||
|
|
||||||
|
"speed_travel": { "value": "100" },
|
||||||
|
"speed_layer_0": { "value": "20" },
|
||||||
|
"speed_prime_tower": { "value": "speed_topbottom" },
|
||||||
|
"speed_print": { "value": "40" },
|
||||||
|
"speed_support": { "value": "speed_wall_0" },
|
||||||
|
"speed_support_interface": { "value": "speed_topbottom" },
|
||||||
|
"speed_topbottom": { "value": "math.ceil(speed_print * 20 / 35)" },
|
||||||
|
"speed_wall": { "value": "math.ceil(speed_print * 30 / 40)" },
|
||||||
|
"speed_wall_0": { "value": "math.ceil(speed_wall * 20 / 25)" },
|
||||||
|
"speed_wall_x": { "value": "speed_wall" },
|
||||||
|
|
||||||
|
"prime_tower_position_x": { "default_value": 175 },
|
||||||
|
"prime_tower_position_y": { "default_value": 178 },
|
||||||
|
"prime_tower_wipe_enabled": { "default_value": false },
|
||||||
|
"prime_tower_min_volume": { "default_value": 50 },
|
||||||
|
"dual_pre_wipe": { "default_value": false },
|
||||||
|
|
||||||
|
"prime_blob_enable": { "enabled": true },
|
||||||
|
|
||||||
|
"acceleration_enabled": { "value": "True" },
|
||||||
|
"acceleration_layer_0": { "value": "acceleration_topbottom" },
|
||||||
|
"acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
|
||||||
|
"acceleration_print": { "value": "3000" },
|
||||||
|
"acceleration_support": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
|
||||||
|
"acceleration_support_interface": { "value": "acceleration_topbottom" },
|
||||||
|
"acceleration_topbottom": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
|
||||||
|
"acceleration_travel": { "value": "acceleration_print" },
|
||||||
|
"acceleration_wall": { "value": "math.ceil(acceleration_print * 1000 / 3000)" },
|
||||||
|
"acceleration_wall_0": { "value": "math.ceil(acceleration_wall * 1000 / 1000)" },
|
||||||
|
|
||||||
|
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
|
||||||
|
"cool_min_layer_time": { "default_value": 10 },
|
||||||
|
|
||||||
|
"jerk_enabled": { "value": "True" },
|
||||||
|
"jerk_layer_0": { "value": "jerk_topbottom" },
|
||||||
|
"jerk_prime_tower": { "value": "math.ceil(jerk_print * 15 / 25)" },
|
||||||
|
"jerk_print": { "value": "25" },
|
||||||
|
"jerk_support": { "value": "math.ceil(jerk_print * 15 / 25)" },
|
||||||
|
"jerk_support_interface": { "value": "jerk_topbottom" },
|
||||||
|
"jerk_topbottom": { "value": "math.ceil(jerk_print * 5 / 25)" },
|
||||||
|
"jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" },
|
||||||
|
"jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" },
|
||||||
|
|
||||||
|
"wall_thickness": { "value": "1.2" },
|
||||||
|
|
||||||
|
"retraction_amount": { "default_value": 3 },
|
||||||
|
"retraction_speed": { "default_value": 15 },
|
||||||
|
"retraction_retract_speed": { "default_value": 15 },
|
||||||
|
"retraction_prime_speed": { "default_value": 15 },
|
||||||
|
"travel_retract_before_outer_wall": { "default_value": true },
|
||||||
|
"skin_overlap": { "value": "15" },
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"machine_nozzle_heat_up_speed": { "default_value": 2 },
|
||||||
|
"machine_nozzle_cool_down_speed": { "default_value": 2 },
|
||||||
|
"machine_head_polygon": { "default_value": [[-75, -18],[-75, 35],[18, 35],[18, -18]] },
|
||||||
|
"gantry_height": { "default_value": 55 },
|
||||||
|
"machine_max_feedrate_x": { "default_value": 300 },
|
||||||
|
"machine_max_feedrate_y": { "default_value": 300 },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 40 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 500 },
|
||||||
|
"machine_acceleration": { "default_value": 1000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 10 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E15 ;extrude 15mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\nT0 ;Start with Rear Extruder\n;Put printing message on LCD screen\nM117 Printing..."
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
|
||||||
|
},
|
||||||
|
"machine_extruder_count": { "default_value": 2 }
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,8 @@
|
||||||
"visible": true,
|
"visible": true,
|
||||||
"author": "Michael Wildermuth",
|
"author": "Michael Wildermuth",
|
||||||
"manufacturer": "Creality3D",
|
"manufacturer": "Creality3D",
|
||||||
"file_formats": "text/x-gcode"
|
"file_formats": "text/x-gcode",
|
||||||
|
"preferred_quality": "*Draft*"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"machine_width": {
|
"machine_width": {
|
||||||
|
@ -25,9 +26,6 @@
|
||||||
"machine_nozzle_size": {
|
"machine_nozzle_size": {
|
||||||
"default_value": 0.4
|
"default_value": 0.4
|
||||||
},
|
},
|
||||||
"layer_height": {
|
|
||||||
"default_value": 0.2
|
|
||||||
},
|
|
||||||
"layer_height_0": {
|
"layer_height_0": {
|
||||||
"default_value": 0.2
|
"default_value": 0.2
|
||||||
},
|
},
|
||||||
|
@ -61,9 +59,6 @@
|
||||||
"skirt_gap": {
|
"skirt_gap": {
|
||||||
"default_value": 5
|
"default_value": 5
|
||||||
},
|
},
|
||||||
"machine_start_gcode": {
|
|
||||||
"default_value": "G21 ;metric values\nG90 ;absolute Positioning\nG28 ; home all axes\nG1 Z5 F3000 ; lift\nG1 X20 Y2 F1500 ; avoid binder clips\nG1 Z0.2 F3000 ; get ready to prime\nG92 E0 ; reset extrusion distance\nG1 X120 E10 F600 ; prime nozzle\nG1 X150 F5000 ; quick wipe"
|
|
||||||
},
|
|
||||||
"machine_end_gcode": {
|
"machine_end_gcode": {
|
||||||
"default_value": "G91\nG1 F1800 E-3\nG1 F3000 Z10\nG90\nG28 X0 Y0 ; home x and y axis\nM106 S0 ; turn off cooling fan\nM104 S0 ; turn off extruder\nM140 S0 ; turn off bed\nM84 ; disable motors"
|
"default_value": "G91\nG1 F1800 E-3\nG1 F3000 Z10\nG90\nG28 X0 Y0 ; home x and y axis\nM106 S0 ; turn off cooling fan\nM104 S0 ; turn off extruder\nM140 S0 ; turn off bed\nM84 ; disable motors"
|
||||||
},
|
},
|
||||||
|
|
0
resources/definitions/dagoma_discoeasy200.def.json
Executable file → Normal file
0
resources/definitions/dagoma_discoeasy200.def.json
Executable file → Normal file
66
resources/definitions/deltacomb.def.json
Normal file
66
resources/definitions/deltacomb.def.json
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"id": "deltacomb",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Deltacomb 3D",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"author": "Gabriele Rossetti",
|
||||||
|
"visible": true,
|
||||||
|
"manufacturer": "Deltacomb 3D",
|
||||||
|
"category": "Other",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"icon": "icon_ultimaker2",
|
||||||
|
"platform": "deltacomb.stl",
|
||||||
|
"has_machine_quality": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"machine_heated_bed": { "default_value": false },
|
||||||
|
"machine_width": { "default_value": 190 },
|
||||||
|
"machine_height": { "default_value": 250 },
|
||||||
|
"machine_depth": { "default_value": 190 },
|
||||||
|
"machine_center_is_zero": { "default_value": true },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 ;Home all axes (max endstops)\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..."},
|
||||||
|
"machine_end_gcode": { "default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG28 ;Home all axes (max endstops)\nM84 ;steppers off\nG90 ;absolute positioning" },
|
||||||
|
"machine_shape": { "default_value": "elliptic" },
|
||||||
|
"machine_max_feedrate_x": { "default_value": 250 },
|
||||||
|
"machine_max_feedrate_y": { "default_value": 250 },
|
||||||
|
"machine_max_feedrate_z": { "default_value": 15 },
|
||||||
|
"machine_max_acceleration_x": { "default_value": 10000 },
|
||||||
|
"machine_max_acceleration_y": { "default_value": 10000 },
|
||||||
|
"machine_max_acceleration_z": { "default_value": 50 },
|
||||||
|
"machine_max_acceleration_e": { "default_value": 100 },
|
||||||
|
"machine_acceleration": { "default_value": 4000 },
|
||||||
|
"machine_max_jerk_xy": { "default_value": 25.0 },
|
||||||
|
"machine_max_jerk_z": { "default_value": 0.4 },
|
||||||
|
"machine_max_jerk_e": { "default_value": 1.0 },
|
||||||
|
"retraction_hop_enabled": { "default_value": false },
|
||||||
|
"retraction_amount" : { "default_value": 4.5 },
|
||||||
|
"retraction_speed" : { "default_value": 40 },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
"material_final_print_temperature": { "value": "material_print_temperature - 5" },
|
||||||
|
"material_initial_print_temperature": { "value": "material_print_temperature" },
|
||||||
|
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
|
||||||
|
"travel_avoid_distance": { "default_value": 1, "value": 1 },
|
||||||
|
"speed_print" : { "default_value": 70 },
|
||||||
|
"speed_travel": { "default_value": 80, "value": 80 },
|
||||||
|
"speed_infill": { "value": "round(speed_print * 1.05, 0)" },
|
||||||
|
"speed_topbottom": { "value": "round(speed_print * 0.95, 0)" },
|
||||||
|
"speed_wall": { "value": "speed_print" },
|
||||||
|
"speed_wall_0": { "value": "round(speed_print * 0.9, 0)" },
|
||||||
|
"speed_wall_x": { "value": "speed_wall" },
|
||||||
|
"speed_layer_0": { "value": "min(round(speed_print * 0.75, 0), 45.0)" },
|
||||||
|
"speed_travel_layer_0": { "value": "round(speed_travel * 0.7, 0)" },
|
||||||
|
"skirt_brim_speed": { "value": "speed_layer_0" },
|
||||||
|
"skirt_line_count": { "default_value": 3 },
|
||||||
|
"skirt_brim_minimal_length": { "default_value": 150 },
|
||||||
|
"infill_sparse_density": { "default_value": 24 },
|
||||||
|
"top_bottom_thickness": { "default_value": 0.6 },
|
||||||
|
"support_z_distance": { "default_value": 0.2, "value": "min(2 * layer_height, machine_nozzle_size * 0.75)" },
|
||||||
|
"infill_before_walls" : { "default_value": false },
|
||||||
|
"support_use_towers" : { "default_value": false }
|
||||||
|
}
|
||||||
|
}
|
181
resources/definitions/fdmprinter.def.json
Executable file → Normal file
181
resources/definitions/fdmprinter.def.json
Executable file → Normal file
|
@ -643,6 +643,20 @@
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
},
|
},
|
||||||
|
"slicing_tolerance":
|
||||||
|
{
|
||||||
|
"label": "Slicing Tolerance",
|
||||||
|
"description": "How to slice layers with diagonal surfaces. The areas of a layer can be generated based on where the middle of the layer intersects the surface (Middle). Alternatively each layer can have the areas which fall inside of the volume throughout the height of the layer (Exclusive) or a layer has the areas which fall inside anywhere within the layer (Inclusive). Exclusive retains the most details, Inclusive makes for the best fit and Middle takes the least time to process.",
|
||||||
|
"type": "enum",
|
||||||
|
"options":
|
||||||
|
{
|
||||||
|
"middle": "Middle",
|
||||||
|
"exclusive": "Exclusive",
|
||||||
|
"inclusive": "Inclusive"
|
||||||
|
},
|
||||||
|
"default_value": "middle",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
"line_width":
|
"line_width":
|
||||||
{
|
{
|
||||||
"label": "Line Width",
|
"label": "Line Width",
|
||||||
|
@ -668,6 +682,7 @@
|
||||||
"value": "line_width",
|
"value": "line_width",
|
||||||
"default_value": 0.4,
|
"default_value": 0.4,
|
||||||
"type": "float",
|
"type": "float",
|
||||||
|
"limit_to_extruder": "wall_0_extruder_nr if wall_x_extruder_nr == wall_0_extruder_nr else -1",
|
||||||
"settable_per_mesh": true,
|
"settable_per_mesh": true,
|
||||||
"children":
|
"children":
|
||||||
{
|
{
|
||||||
|
@ -866,29 +881,45 @@
|
||||||
"type": "category",
|
"type": "category",
|
||||||
"children":
|
"children":
|
||||||
{
|
{
|
||||||
"wall_0_extruder_nr":
|
"wall_extruder_nr":
|
||||||
{
|
{
|
||||||
"label": "Outer Wall Extruder",
|
"label": "Wall Extruder",
|
||||||
"description": "The extruder train used for printing the outer wall. This is used in multi-extrusion.",
|
"description": "The extruder train used for printing the walls. This is used in multi-extrusion.",
|
||||||
"type": "optional_extruder",
|
"type": "optional_extruder",
|
||||||
"default_value": "-1",
|
"default_value": "-1",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true,
|
"settable_per_meshgroup": true,
|
||||||
"settable_globally": true,
|
"settable_globally": true,
|
||||||
"enabled": "machine_extruder_count > 1"
|
"enabled": "machine_extruder_count > 1",
|
||||||
},
|
"children": {
|
||||||
"wall_x_extruder_nr":
|
"wall_0_extruder_nr":
|
||||||
{
|
{
|
||||||
"label": "Inner Walls Extruder",
|
"label": "Outer Wall Extruder",
|
||||||
"description": "The extruder train used for printing the inner walls. This is used in multi-extrusion.",
|
"description": "The extruder train used for printing the outer wall. This is used in multi-extrusion.",
|
||||||
"type": "optional_extruder",
|
"type": "optional_extruder",
|
||||||
"default_value": "-1",
|
"value": "wall_extruder_nr",
|
||||||
"settable_per_mesh": false,
|
"default_value": "-1",
|
||||||
"settable_per_extruder": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_meshgroup": true,
|
"settable_per_extruder": false,
|
||||||
"settable_globally": true,
|
"settable_per_meshgroup": true,
|
||||||
"enabled": "machine_extruder_count > 1"
|
"settable_globally": true,
|
||||||
|
"enabled": "machine_extruder_count > 1"
|
||||||
|
},
|
||||||
|
"wall_x_extruder_nr":
|
||||||
|
{
|
||||||
|
"label": "Inner Wall Extruder",
|
||||||
|
"description": "The extruder train used for printing the inner walls. This is used in multi-extrusion.",
|
||||||
|
"type": "optional_extruder",
|
||||||
|
"value": "wall_extruder_nr",
|
||||||
|
"default_value": "-1",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"settable_per_meshgroup": true,
|
||||||
|
"settable_globally": true,
|
||||||
|
"enabled": "machine_extruder_count > 1"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"wall_thickness":
|
"wall_thickness":
|
||||||
{
|
{
|
||||||
|
@ -1354,7 +1385,7 @@
|
||||||
"default_value": 2,
|
"default_value": 2,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"minimum_value_warning": "infill_line_width",
|
"minimum_value_warning": "infill_line_width",
|
||||||
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'cubic' or infill_pattern == 'cubicsubdiv' else (2 if infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' else (1 if infill_pattern == 'cross' or infill_pattern == 'cross_3d' else 1))))",
|
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'trihexagon' or infill_pattern == 'cubic' or infill_pattern == 'cubicsubdiv' else (2 if infill_pattern == 'tetrahedral' or infill_pattern == 'quarter_cubic' else (1 if infill_pattern == 'cross' or infill_pattern == 'cross_3d' else 1))))",
|
||||||
"limit_to_extruder": "infill_extruder_nr",
|
"limit_to_extruder": "infill_extruder_nr",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
}
|
}
|
||||||
|
@ -1363,13 +1394,14 @@
|
||||||
"infill_pattern":
|
"infill_pattern":
|
||||||
{
|
{
|
||||||
"label": "Infill Pattern",
|
"label": "Infill Pattern",
|
||||||
"description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, cubic, octet, quarter cubic and concentric patterns are fully printed every layer. Cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction.",
|
"description": "The pattern of the infill material of the print. The line and zig zag infill swap direction on alternate layers, reducing material cost. The grid, triangle, tri-hexagon, cubic, octet, quarter cubic, cross and concentric patterns are fully printed every layer. Cubic, quarter cubic and octet infill change with every layer to provide a more equal distribution of strength over each direction.",
|
||||||
"type": "enum",
|
"type": "enum",
|
||||||
"options":
|
"options":
|
||||||
{
|
{
|
||||||
"grid": "Grid",
|
"grid": "Grid",
|
||||||
"lines": "Lines",
|
"lines": "Lines",
|
||||||
"triangles": "Triangles",
|
"triangles": "Triangles",
|
||||||
|
"trihexagon": "Tri-Hexagon",
|
||||||
"cubic": "Cubic",
|
"cubic": "Cubic",
|
||||||
"cubicsubdiv": "Cubic Subdivision",
|
"cubicsubdiv": "Cubic Subdivision",
|
||||||
"tetrahedral": "Octet",
|
"tetrahedral": "Octet",
|
||||||
|
@ -1850,6 +1882,31 @@
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
},
|
},
|
||||||
|
"material_adhesion_tendency":
|
||||||
|
{
|
||||||
|
"label": "Adhesion Tendency",
|
||||||
|
"description": "Surface adhesion tendency.",
|
||||||
|
"type": "int",
|
||||||
|
"default_value": 10,
|
||||||
|
"minimum_value": "0",
|
||||||
|
"maximum_value": "10",
|
||||||
|
"enabled": false,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"material_surface_energy":
|
||||||
|
{
|
||||||
|
"label": "Surface Energy",
|
||||||
|
"description": "Surface energy.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "int",
|
||||||
|
"default_value": 100,
|
||||||
|
"minimum_value": "0",
|
||||||
|
"maximum_value": "100",
|
||||||
|
"enabled": false,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
"material_flow":
|
"material_flow":
|
||||||
{
|
{
|
||||||
"label": "Flow",
|
"label": "Flow",
|
||||||
|
@ -4075,30 +4132,6 @@
|
||||||
"settable_per_extruder": true,
|
"settable_per_extruder": true,
|
||||||
"limit_to_extruder": "adhesion_extruder_nr"
|
"limit_to_extruder": "adhesion_extruder_nr"
|
||||||
},
|
},
|
||||||
"z_offset_layer_0":
|
|
||||||
{
|
|
||||||
"label": "Initial Layer Z Offset",
|
|
||||||
"description": "The extruder is offset from the normal height of the first layer by this amount. It can be positive (raised) or negative (lowered). Some filament types adhere to the build plate better if the extruder is raised slightly.",
|
|
||||||
"unit": "mm",
|
|
||||||
"type": "float",
|
|
||||||
"default_value": 0,
|
|
||||||
"minimum_value_warning": "0",
|
|
||||||
"maximum_value_warning": "layer_height_0",
|
|
||||||
"enabled": "resolveOrValue('adhesion_type') != 'raft'",
|
|
||||||
"settable_per_mesh": false,
|
|
||||||
"settable_per_extruder": false
|
|
||||||
},
|
|
||||||
"z_offset_taper_layers":
|
|
||||||
{
|
|
||||||
"label": "Z Offset Taper Layers",
|
|
||||||
"description": "When non-zero, the Z offset is reduced to 0 over that many layers. A value of 0 means that the Z offset remains constant for all the layers in the print.",
|
|
||||||
"type": "int",
|
|
||||||
"default_value": 0,
|
|
||||||
"minimum_value": "0",
|
|
||||||
"enabled": "resolveOrValue('adhesion_type') != 'raft' and z_offset_layer_0 != 0",
|
|
||||||
"settable_per_mesh": false,
|
|
||||||
"settable_per_extruder": false
|
|
||||||
},
|
|
||||||
"raft_margin":
|
"raft_margin":
|
||||||
{
|
{
|
||||||
"label": "Raft Extra Margin",
|
"label": "Raft Extra Margin",
|
||||||
|
@ -4827,6 +4860,16 @@
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": true
|
"settable_per_meshgroup": true
|
||||||
|
},
|
||||||
|
"remove_empty_first_layers":
|
||||||
|
{
|
||||||
|
"label": "Remove Empty First Layers",
|
||||||
|
"description": "Remove empty layers beneath the first printed layer if they are present. Disabling this setting can cause empty first layers if the Slicing Tolerance setting is set to Exclusive or Middle.",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": true,
|
||||||
|
"enabled": "not support_enable",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5032,7 +5075,8 @@
|
||||||
"default_value": false,
|
"default_value": false,
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true
|
||||||
},
|
},
|
||||||
"support_skip_some_zags": {
|
"support_skip_some_zags":
|
||||||
|
{
|
||||||
"label": "Break Up Support In Chunks",
|
"label": "Break Up Support In Chunks",
|
||||||
"description": "Skip some support line connections to make the support structure easier to break away. This setting is applicable to the Zig Zag support infill pattern.",
|
"description": "Skip some support line connections to make the support structure easier to break away. This setting is applicable to the Zig Zag support infill pattern.",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
|
@ -5040,35 +5084,36 @@
|
||||||
"enabled": "support_enable and (support_pattern == 'zigzag')",
|
"enabled": "support_enable and (support_pattern == 'zigzag')",
|
||||||
"limit_to_extruder": "support_infill_extruder_nr",
|
"limit_to_extruder": "support_infill_extruder_nr",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"support_skip_zag_per_mm":
|
||||||
|
{
|
||||||
|
"label": "Support Chunk Size",
|
||||||
|
"description": "Leave out a connection between support lines once every N millimeter to make the support structure easier to break away.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm",
|
||||||
|
"default_value": 20,
|
||||||
|
"minimum_value": "0",
|
||||||
|
"minimum_value_warning": "support_line_distance",
|
||||||
|
"enabled": "support_enable and (support_pattern == 'zigzag') and support_skip_some_zags",
|
||||||
|
"limit_to_extruder": "support_infill_extruder_nr",
|
||||||
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true,
|
"settable_per_extruder": true,
|
||||||
"children": {
|
"children":
|
||||||
"support_skip_zag_per_mm": {
|
{
|
||||||
"label": "Support Chunk Size",
|
"support_zag_skip_count":
|
||||||
"description": "Leave out a connection between support lines once every N millimeter to make the support structure easier to break away.",
|
{
|
||||||
"type": "float",
|
"label": "Support Chunk Line Count",
|
||||||
"unit": "mm",
|
"description": "Skip one in every N connection lines to make the support structure easier to break away.",
|
||||||
"default_value": 20,
|
"type": "int",
|
||||||
"minimum_value": "0",
|
"default_value": 5,
|
||||||
"minimum_value_warning": "support_line_distance",
|
"value": "round(support_skip_zag_per_mm / support_line_distance)",
|
||||||
|
"minimum_value": "1",
|
||||||
|
"minimum_value_warning": "3",
|
||||||
"enabled": "support_enable and (support_pattern == 'zigzag') and support_skip_some_zags",
|
"enabled": "support_enable and (support_pattern == 'zigzag') and support_skip_some_zags",
|
||||||
"limit_to_extruder": "support_infill_extruder_nr",
|
"limit_to_extruder": "support_infill_extruder_nr",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true,
|
"settable_per_extruder": true
|
||||||
"children": {
|
|
||||||
"support_zag_skip_count": {
|
|
||||||
"label": "Support Chunk Line Count",
|
|
||||||
"description": "Skip one in every N connection lines to make the support structure easier to break away.",
|
|
||||||
"type": "int",
|
|
||||||
"default_value": 5,
|
|
||||||
"value": "round(support_skip_zag_per_mm / support_line_distance)",
|
|
||||||
"minimum_value": "1",
|
|
||||||
"minimum_value_warning": "3",
|
|
||||||
"enabled": "support_enable and (support_pattern == 'zigzag') and support_skip_some_zags",
|
|
||||||
"limit_to_extruder": "support_infill_extruder_nr",
|
|
||||||
"settable_per_mesh": false,
|
|
||||||
"settable_per_extruder": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
0
resources/definitions/helloBEEprusa.def.json
Executable file → Normal file
0
resources/definitions/helloBEEprusa.def.json
Executable file → Normal file
|
@ -5,7 +5,7 @@
|
||||||
"inherits": "fdmprinter",
|
"inherits": "fdmprinter",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"visible": true,
|
"visible": true,
|
||||||
"author": "Apsu",
|
"author": "Apsu, Nounours2099",
|
||||||
"manufacturer": "Prusa Research",
|
"manufacturer": "Prusa Research",
|
||||||
"file_formats": "text/x-gcode",
|
"file_formats": "text/x-gcode",
|
||||||
"icon": "icon_ultimaker2",
|
"icon": "icon_ultimaker2",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"machine_max_jerk_e": { "default_value": 2.5 },
|
"machine_max_jerk_e": { "default_value": 2.5 },
|
||||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
"machine_start_gcode": {
|
"machine_start_gcode": {
|
||||||
"default_value": "G21 ; set units to millimeters\nG90 ; use absolute positioning\nM82 ; absolute extrusion mode\nM104 S{material_print_temperature} ; set extruder temp\nM140 S{material_bed_temperature} ; set bed temp\nM190 S{material_bed_temperature} ; wait for bed temp\nM109 S{material_print_temperature} ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG92 E0.0 ; reset extruder distance position\nG1 Y-3.0 F1000.0 ; go outside print area\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E21.5 F1000.0 ; intro line\nG92 E0.0 ; reset extruder distance position"
|
"default_value": "G21 ; set units to millimeters\nG90 ; use absolute positioning\nM82 ; absolute extrusion mode\nM104 S{material_print_temperature_layer_0} ; set extruder temp\nM140 S{material_bed_temperature_layer_0} ; set bed temp\nM190 S{material_bed_temperature_layer_0} ; wait for bed temp\nM109 S{material_print_temperature_layer_0} ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG92 E0.0 ; reset extruder distance position\nG1 Y-3.0 F1000.0 ; go outside print area\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E21.5 F1000.0 ; intro line\nG92 E0.0 ; reset extruder distance position"
|
||||||
},
|
},
|
||||||
"machine_end_gcode": {
|
"machine_end_gcode": {
|
||||||
"default_value": "M104 S0 ; turn off extruder\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y210; home X axis and push Y forward\nM84 ; disable motors"
|
"default_value": "M104 S0 ; turn off extruder\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y210; home X axis and push Y forward\nM84 ; disable motors"
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
"machine_extruder_count": { "default_value": 2 },
|
"machine_extruder_count": { "default_value": 2 },
|
||||||
"extruder_prime_pos_abs": { "default_value": true },
|
"extruder_prime_pos_abs": { "default_value": true },
|
||||||
"machine_start_gcode": { "default_value": "" },
|
"machine_start_gcode": { "default_value": "" },
|
||||||
"machine_end_gcode": { "default_value": "G91 ;Relative movement\nG0 F2400 Z3 E-{retraction_amount}\nG90 ;Disable relative movement" },
|
"machine_end_gcode": { "default_value": "G91 ;Relative movement\nG0 F15000 X8.0 Z0.5 E-4.5 ;Wiping+material retraction\nG0 F10000 Z1.5 E4.5 ;Compensation for the retraction\nG90 ;Disable relative movement" },
|
||||||
"prime_tower_position_x": { "value": "machine_depth - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) - 30" },
|
"prime_tower_position_x": { "value": "machine_depth - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) - 30" },
|
||||||
"prime_tower_wipe_enabled": { "default_value": false },
|
"prime_tower_wipe_enabled": { "default_value": false },
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@
|
||||||
"top_bottom_thickness": { "value": "1" },
|
"top_bottom_thickness": { "value": "1" },
|
||||||
"travel_avoid_distance": { "value": "3" },
|
"travel_avoid_distance": { "value": "3" },
|
||||||
"wall_0_inset": { "value": "0" },
|
"wall_0_inset": { "value": "0" },
|
||||||
"wall_line_width_x": { "value": "round(line_width * 0.3 / 0.35, 2)" },
|
"wall_line_width_x": { "value": "round(wall_line_width * 0.3 / 0.35, 2)" },
|
||||||
"wall_thickness": { "value": "1" }
|
"wall_thickness": { "value": "1" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
"author": "Velleman"
|
"author": "Velleman"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
"material_diameter": {
|
||||||
|
"default_value": 1.75
|
||||||
|
},
|
||||||
"machine_width": {
|
"machine_width": {
|
||||||
"default_value": 200
|
"default_value": 200
|
||||||
},
|
},
|
||||||
|
@ -40,7 +43,7 @@
|
||||||
"machine_head_shape_max_y": {
|
"machine_head_shape_max_y": {
|
||||||
"default_value": 0
|
"default_value": 0
|
||||||
},
|
},
|
||||||
"machine_nozzle_gantry_distance": {
|
"gantry_height": {
|
||||||
"default_value": 0
|
"default_value": 0
|
||||||
},
|
},
|
||||||
"machine_nozzle_offset_x_1": {
|
"machine_nozzle_offset_x_1": {
|
||||||
|
|
27
resources/extruders/builder_premium_large_front.def.json
Normal file
27
resources/extruders/builder_premium_large_front.def.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_large_front",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Front Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "builder_premium_large",
|
||||||
|
"position": "1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 1,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_offset_x": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
|
|
||||||
|
"machine_extruder_start_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"machine_extruder_end_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"extruder_prime_pos_abs": { "default_value": true }
|
||||||
|
}
|
||||||
|
}
|
27
resources/extruders/builder_premium_large_rear.def.json
Normal file
27
resources/extruders/builder_premium_large_rear.def.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_large_rear",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Rear Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "builder_premium_large",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 0,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_offset_x": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
|
|
||||||
|
"machine_extruder_start_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"machine_extruder_end_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"extruder_prime_pos_abs": { "default_value": true }
|
||||||
|
}
|
||||||
|
}
|
27
resources/extruders/builder_premium_medium_front.def.json
Normal file
27
resources/extruders/builder_premium_medium_front.def.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_medium_front",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Front Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "builder_premium_medium",
|
||||||
|
"position": "1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 1,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_offset_x": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
|
|
||||||
|
"machine_extruder_start_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"machine_extruder_end_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"extruder_prime_pos_abs": { "default_value": true }
|
||||||
|
}
|
||||||
|
}
|
27
resources/extruders/builder_premium_medium_rear.def.json
Normal file
27
resources/extruders/builder_premium_medium_rear.def.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_medium_rear",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Rear Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "builder_premium_medium",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 0,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_offset_x": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
|
|
||||||
|
"machine_extruder_start_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"machine_extruder_end_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"extruder_prime_pos_abs": { "default_value": true }
|
||||||
|
}
|
||||||
|
}
|
27
resources/extruders/builder_premium_small_front.def.json
Normal file
27
resources/extruders/builder_premium_small_front.def.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_small_front",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Front Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "builder_premium_small",
|
||||||
|
"position": "1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 1,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_offset_x": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
|
|
||||||
|
"machine_extruder_start_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"machine_extruder_end_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"extruder_prime_pos_abs": { "default_value": true }
|
||||||
|
}
|
||||||
|
}
|
27
resources/extruders/builder_premium_small_rear.def.json
Normal file
27
resources/extruders/builder_premium_small_rear.def.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"id": "builder_premium_small_rear",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Rear Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "builder_premium_small",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": {
|
||||||
|
"default_value": 0,
|
||||||
|
"maximum_value": "1"
|
||||||
|
},
|
||||||
|
"machine_nozzle_offset_x": { "default_value": 0.0 },
|
||||||
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
|
|
||||||
|
"machine_extruder_start_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"machine_extruder_end_pos_abs": { "default_value": true },
|
||||||
|
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
|
||||||
|
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" },
|
||||||
|
"extruder_prime_pos_abs": { "default_value": true }
|
||||||
|
}
|
||||||
|
}
|
0
resources/extruders/hBp_extruder_left.def.json
Executable file → Normal file
0
resources/extruders/hBp_extruder_left.def.json
Executable file → Normal file
0
resources/extruders/hBp_extruder_right.def.json
Executable file → Normal file
0
resources/extruders/hBp_extruder_right.def.json
Executable file → Normal file
|
@ -18,6 +18,21 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
||||||
|
|
||||||
|
#Manually added for plugins/UserAgreementPlugin/UserAgreement.qml
|
||||||
|
msgctxt "@title:window"
|
||||||
|
msgid "User Agreement"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#Manually added for plugins/UserAgreementPlugin/UserAgreement.qml
|
||||||
|
msgctxt "@action:button"
|
||||||
|
msgid "I understand and agree"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#Manually added for plugins/UserAgreementPlugin/UserAgreement.qml
|
||||||
|
msgctxt "@action:button"
|
||||||
|
msgid "I don't agree"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: Manually added for plugins/UM3NetworkPrinting/PrinterInfoBlock.qml
|
#: Manually added for plugins/UM3NetworkPrinting/PrinterInfoBlock.qml
|
||||||
msgctxt "@label:status"
|
msgctxt "@label:status"
|
||||||
msgid "Print aborted"
|
msgid "Print aborted"
|
||||||
|
@ -63,6 +78,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -36,6 +36,46 @@ msgctxt "@label:status"
|
||||||
msgid "Can't start print"
|
msgid "Can't start print"
|
||||||
msgstr "Druck startet nicht"
|
msgstr "Druck startet nicht"
|
||||||
|
|
||||||
|
#: Manually added for plugins/UM3NetworkPrinting/DiscoverUM3Action.qml
|
||||||
|
msgctxt "@label"
|
||||||
|
msgid "This printer is not set up to host a group of Ultimaker 3 printers."
|
||||||
|
msgstr "Dieser Drucker ist nicht eingerichtet um eine Gruppe von Ultimaker 3 Druckern anzusteuern."
|
||||||
|
|
||||||
|
#: Manually added for plugins/UM3NetworkPrinting/PrinterInfoBlock.qml
|
||||||
|
msgctxt "@label"
|
||||||
|
msgid "Finishes at: "
|
||||||
|
msgstr "Endet um: "
|
||||||
|
|
||||||
|
#: Manually added for plugins/UM3NetworkPrinting/DiscoverUM3Action.qml
|
||||||
|
msgctxt "@label"
|
||||||
|
msgid "This printer is the host for a group of %1 Ultimaker 3 printers."
|
||||||
|
msgstr "Dieser Drucker steuert eine Gruppe von %1 Ultimaker 3 Druckern an."
|
||||||
|
|
||||||
|
#: Manually added for plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py
|
||||||
|
msgctxt "@info:status"
|
||||||
|
msgid "Printer '{printer_name}' has finished printing '{job_name}'."
|
||||||
|
msgstr "Drucker '{printer_name}' hat '{job_name}' vollständig gedrückt."
|
||||||
|
|
||||||
|
#: Manually added for plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py
|
||||||
|
msgctxt "@info:status"
|
||||||
|
msgid "Print finished"
|
||||||
|
msgstr "Druck vollendet"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "&Plugins"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Plugins durchsuchen..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Installierte plugins..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
@ -2479,7 +2519,7 @@ msgstr "Sichtbarkeit einstellen"
|
||||||
#: /home/ruben/Projects/Cura/resources/qml/Preferences/SettingVisibilityPage.qml:44
|
#: /home/ruben/Projects/Cura/resources/qml/Preferences/SettingVisibilityPage.qml:44
|
||||||
msgctxt "@label:textbox"
|
msgctxt "@label:textbox"
|
||||||
msgid "Check all"
|
msgid "Check all"
|
||||||
msgstr "Alle prüfen"
|
msgstr "Alles wählen"
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/resources/qml/Preferences/ProfileTab.qml:40
|
#: /home/ruben/Projects/Cura/resources/qml/Preferences/ProfileTab.qml:40
|
||||||
msgctxt "@info:status"
|
msgctxt "@info:status"
|
||||||
|
|
|
@ -61,6 +61,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Impresión terminada"
|
msgstr "Impresión terminada"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "&Complementos"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Examinar complementos..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Complementos instalados..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -61,6 +61,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Tulosta valmis"
|
msgstr "Tulosta valmis"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "&Lisäosat"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Selaa lisäosia..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Asennetut lisäoset..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -61,6 +61,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Impression terminée"
|
msgstr "Impression terminée"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "&Plug-ins"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Parcourir les plug-ins..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Plug-ins installés..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -61,6 +61,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Stampa finita"
|
msgstr "Stampa finita"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "&Plugin"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Sfoglia plugin..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Plugin installati..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -61,6 +61,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Print klaar"
|
msgstr "Print klaar"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "&Plugins"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Door invoegtoepassingen bladeren..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Geïnstalleerde plugins..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -63,6 +63,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Drukowanie zakończone"
|
msgstr "Drukowanie zakończone"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "W&tyczki"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Przeglądaj wtyczki..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Zainstalowane wtyczki..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -62,6 +62,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Impressão Concluída"
|
msgstr "Impressão Concluída"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "&Complementos"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Navegar complementos..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Complementos instalados..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -63,6 +63,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Печать завершена"
|
msgstr "Печать завершена"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "Плагины"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Просмотр плагинов..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Установленные плагины..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -61,6 +61,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "Baskı tamamlandı"
|
msgstr "Baskı tamamlandı"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "&Eklentiler"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "Eklentilere göz at..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "Yüklü eklentiler..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
|
@ -63,6 +63,21 @@ msgctxt "@info:status"
|
||||||
msgid "Print finished"
|
msgid "Print finished"
|
||||||
msgstr "打印完成"
|
msgstr "打印完成"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Cura.qml
|
||||||
|
msgctxt "@title:menu menubar:toplevel"
|
||||||
|
msgid "P&lugins"
|
||||||
|
msgstr "插件"
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Browse plugins..."
|
||||||
|
msgstr "浏览插件..."
|
||||||
|
|
||||||
|
#: Manually added for resources/Cura/Actions.qml
|
||||||
|
msgctxt "@action:menu"
|
||||||
|
msgid "Installed plugins..."
|
||||||
|
msgstr "已安装插件..."
|
||||||
|
|
||||||
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
|
||||||
msgctxt "@action"
|
msgctxt "@action"
|
||||||
msgid "Machine Settings"
|
msgid "Machine Settings"
|
||||||
|
|
0
resources/meshes/BEEVERYCREATIVE-helloBEEprusa.stl
Executable file → Normal file
0
resources/meshes/BEEVERYCREATIVE-helloBEEprusa.stl
Executable file → Normal file
BIN
resources/meshes/builder_premium_platform.stl
Normal file
BIN
resources/meshes/builder_premium_platform.stl
Normal file
Binary file not shown.
BIN
resources/meshes/deltacomb.stl
Normal file
BIN
resources/meshes/deltacomb.stl
Normal file
Binary file not shown.
|
@ -132,6 +132,7 @@ UM.Dialog
|
||||||
projectsModel.append({ name:"PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" });
|
projectsModel.append({ name:"PySerial", description: catalog.i18nc("@label", "Serial communication library"), license: "Python", url: "http://pyserial.sourceforge.net/" });
|
||||||
projectsModel.append({ name:"python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" });
|
projectsModel.append({ name:"python-zeroconf", description: catalog.i18nc("@label", "ZeroConf discovery library"), license: "LGPL", url: "https://github.com/jstasiak/python-zeroconf" });
|
||||||
projectsModel.append({ name:"Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" });
|
projectsModel.append({ name:"Clipper", description: catalog.i18nc("@label", "Polygon clipping library"), license: "Boost", url: "http://www.angusj.com/delphi/clipper.php" });
|
||||||
|
projectsModel.append({ name:"Requests", description: catalog.i18nc("@Label", "Python HTTP library"), license: "GPL", url: "http://docs.python-requests.org" });
|
||||||
|
|
||||||
projectsModel.append({ name:"Open Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://fonts.google.com/specimen/Open+Sans" });
|
projectsModel.append({ name:"Open Sans", description: catalog.i18nc("@label", "Font"), license: "Apache 2.0", url: "https://fonts.google.com/specimen/Open+Sans" });
|
||||||
projectsModel.append({ name:"Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" });
|
projectsModel.append({ name:"Font-Awesome-SVG-PNG", description: catalog.i18nc("@label", "SVG icons"), license: "SIL OFL 1.1", url: "https://github.com/encharm/Font-Awesome-SVG-PNG" });
|
||||||
|
|
0
resources/qml/Actions.qml
Executable file → Normal file
0
resources/qml/Actions.qml
Executable file → Normal file
|
@ -63,11 +63,12 @@ UM.Dialog
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: 20 * screenScaleFactor
|
anchors.leftMargin: 20 * screenScaleFactor
|
||||||
anchors.rightMargin: 20 * screenScaleFactor
|
anchors.rightMargin: 20 * screenScaleFactor
|
||||||
anchors.bottomMargin: 20 * screenScaleFactor
|
anchors.bottomMargin: 10 * screenScaleFactor
|
||||||
spacing: 10 * screenScaleFactor
|
spacing: 10 * screenScaleFactor
|
||||||
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
|
id: questionText
|
||||||
text: catalog.i18nc("@text:window", "This is a Cura project file. Would you like to open it as a project or import the models from it?")
|
text: catalog.i18nc("@text:window", "This is a Cura project file. Would you like to open it as a project or import the models from it?")
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
@ -80,11 +81,18 @@ UM.Dialog
|
||||||
id: rememberChoiceCheckBox
|
id: rememberChoiceCheckBox
|
||||||
text: catalog.i18nc("@text:window", "Remember my choice")
|
text: catalog.i18nc("@text:window", "Remember my choice")
|
||||||
checked: UM.Preferences.getValue("cura/choice_on_open_project") != "always_ask"
|
checked: UM.Preferences.getValue("cura/choice_on_open_project") != "always_ask"
|
||||||
|
style: CheckBoxStyle {
|
||||||
|
label: Label {
|
||||||
|
text: control.text
|
||||||
|
font: UM.Theme.getFont("default")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
|
id: buttonBar
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
|
|
7
resources/qml/Cura.qml
Executable file → Normal file
7
resources/qml/Cura.qml
Executable file → Normal file
|
@ -16,7 +16,7 @@ UM.MainWindow
|
||||||
{
|
{
|
||||||
id: base
|
id: base
|
||||||
//: Cura application window title
|
//: Cura application window title
|
||||||
title: catalog.i18nc("@title:window","Cura");
|
title: catalog.i18nc("@title:window","Ultimaker Cura");
|
||||||
viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0)
|
viewportRect: Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0)
|
||||||
property bool showPrintMonitor: false
|
property bool showPrintMonitor: false
|
||||||
|
|
||||||
|
@ -894,6 +894,11 @@ UM.MainWindow
|
||||||
if(!base.visible)
|
if(!base.visible)
|
||||||
{
|
{
|
||||||
base.visible = true;
|
base.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check later if the user agreement dialog has been closed
|
||||||
|
if (CuraApplication.needToShowUserAgreement)
|
||||||
|
{
|
||||||
restart();
|
restart();
|
||||||
}
|
}
|
||||||
else if(Cura.MachineManager.activeMachineId == null || Cura.MachineManager.activeMachineId == "")
|
else if(Cura.MachineManager.activeMachineId == null || Cura.MachineManager.activeMachineId == "")
|
||||||
|
|
|
@ -94,7 +94,7 @@ Item {
|
||||||
{
|
{
|
||||||
id: printJobTextfield
|
id: printJobTextfield
|
||||||
anchors.right: printJobPencilIcon.left
|
anchors.right: printJobPencilIcon.left
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width/2
|
anchors.rightMargin: Math.floor(UM.Theme.getSize("default_margin").width/2)
|
||||||
height: UM.Theme.getSize("jobspecs_line").height
|
height: UM.Theme.getSize("jobspecs_line").height
|
||||||
width: Math.max(__contentWidth + UM.Theme.getSize("default_margin").width, 50)
|
width: Math.max(__contentWidth + UM.Theme.getSize("default_margin").width, 50)
|
||||||
maximumLength: 120
|
maximumLength: 120
|
||||||
|
|
0
resources/qml/Menus/ContextMenu.qml
Executable file → Normal file
0
resources/qml/Menus/ContextMenu.qml
Executable file → Normal file
|
@ -14,6 +14,20 @@ Menu
|
||||||
|
|
||||||
property int extruderIndex: 0
|
property int extruderIndex: 0
|
||||||
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
||||||
|
property bool isClusterPrinter:
|
||||||
|
{
|
||||||
|
if(Cura.MachineManager.printerOutputDevices.length == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var clusterSize = Cura.MachineManager.printerOutputDevices[0].clusterSize;
|
||||||
|
// This is not a cluster printer or the cluster it is just one printer
|
||||||
|
if(clusterSize == undefined || clusterSize == 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
UM.SettingPropertyProvider
|
UM.SettingPropertyProvider
|
||||||
{
|
{
|
||||||
|
@ -29,14 +43,14 @@ Menu
|
||||||
id: automaticMaterial
|
id: automaticMaterial
|
||||||
text:
|
text:
|
||||||
{
|
{
|
||||||
if(printerConnected && Cura.MachineManager.printerOutputDevices[0].materialNames.length > extruderIndex)
|
if(printerConnected && Cura.MachineManager.printerOutputDevices[0].materialNames.length > extruderIndex && !isClusterPrinter)
|
||||||
{
|
{
|
||||||
var materialName = Cura.MachineManager.printerOutputDevices[0].materialNames[extruderIndex];
|
var materialName = Cura.MachineManager.printerOutputDevices[0].materialNames[extruderIndex];
|
||||||
return catalog.i18nc("@title:menuitem %1 is the automatically selected material", "Automatic: %1").arg(materialName);
|
return catalog.i18nc("@title:menuitem %1 is the automatically selected material", "Automatic: %1").arg(materialName);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].materialNames.length > extruderIndex
|
visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].materialNames.length > extruderIndex && !isClusterPrinter
|
||||||
onTriggered:
|
onTriggered:
|
||||||
{
|
{
|
||||||
var materialId = Cura.MachineManager.printerOutputDevices[0].materialIds[extruderIndex];
|
var materialId = Cura.MachineManager.printerOutputDevices[0].materialIds[extruderIndex];
|
||||||
|
|
|
@ -14,20 +14,34 @@ Menu
|
||||||
|
|
||||||
property int extruderIndex: 0
|
property int extruderIndex: 0
|
||||||
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
||||||
|
property bool isClusterPrinter:
|
||||||
|
{
|
||||||
|
if(Cura.MachineManager.printerOutputDevices.length == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var clusterSize = Cura.MachineManager.printerOutputDevices[0].clusterSize;
|
||||||
|
// This is not a cluster printer or the cluster it is just one printer
|
||||||
|
if(clusterSize == undefined || clusterSize == 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
MenuItem
|
MenuItem
|
||||||
{
|
{
|
||||||
id: automaticNozzle
|
id: automaticNozzle
|
||||||
text:
|
text:
|
||||||
{
|
{
|
||||||
if(printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex)
|
if(printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex && !isClusterPrinter)
|
||||||
{
|
{
|
||||||
var nozzleName = Cura.MachineManager.printerOutputDevices[0].hotendIds[extruderIndex];
|
var nozzleName = Cura.MachineManager.printerOutputDevices[0].hotendIds[extruderIndex];
|
||||||
return catalog.i18nc("@title:menuitem %1 is the nozzle currently loaded in the printer", "Automatic: %1").arg(nozzleName);
|
return catalog.i18nc("@title:menuitem %1 is the nozzle currently loaded in the printer", "Automatic: %1").arg(nozzleName);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex
|
visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex && !isClusterPrinter
|
||||||
onTriggered:
|
onTriggered:
|
||||||
{
|
{
|
||||||
var activeExtruderIndex = ExtruderManager.activeExtruderIndex;
|
var activeExtruderIndex = ExtruderManager.activeExtruderIndex;
|
||||||
|
|
|
@ -17,9 +17,9 @@ Menu
|
||||||
|
|
||||||
MenuItem
|
MenuItem
|
||||||
{
|
{
|
||||||
text: model.name + " - " + model.layer_height
|
text: (model.layer_height != "") ? model.name + " - " + model.layer_height : model.name
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: Cura.MachineManager.activeQualityChangesId == "" && Cura.MachineManager.activeQualityType == model.metadata.quality_type
|
checked: Cura.MachineManager.activeQualityId == model.id
|
||||||
exclusiveGroup: group
|
exclusiveGroup: group
|
||||||
onTriggered: Cura.MachineManager.setActiveQuality(model.id)
|
onTriggered: Cura.MachineManager.setActiveQuality(model.id)
|
||||||
visible: model.available
|
visible: model.available
|
||||||
|
|
|
@ -36,8 +36,6 @@ UM.Dialog
|
||||||
|
|
||||||
var meshName = backgroundItem.getMeshName(projectFile.toString());
|
var meshName = backgroundItem.getMeshName(projectFile.toString());
|
||||||
backgroundItem.hasMesh(decodeURIComponent(meshName));
|
backgroundItem.hasMesh(decodeURIComponent(meshName));
|
||||||
// always update the job name with the loaded project
|
|
||||||
PrintInformation.setBaseName(meshName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadModelFiles(fileUrls)
|
function loadModelFiles(fileUrls)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue