mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-25 15:48:16 +08:00
Merge branch 'master' into feature_tree_support
This commit is contained in:
commit
eb1efc4928
@ -56,11 +56,6 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||||||
if self._node is None:
|
if self._node is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if getattr(self._node, "_non_printing_mesh", False):
|
|
||||||
# infill_mesh, cutting_mesh and anti_overhang_mesh do not need a convex hull
|
|
||||||
# node._non_printing_mesh is set in SettingOverrideDecorator
|
|
||||||
return None
|
|
||||||
|
|
||||||
hull = self._compute2DConvexHull()
|
hull = self._compute2DConvexHull()
|
||||||
|
|
||||||
if self._global_stack and self._node:
|
if self._global_stack and self._node:
|
||||||
|
@ -59,7 +59,7 @@ class CrashHandler:
|
|||||||
self.data = dict()
|
self.data = dict()
|
||||||
self.data["time_stamp"] = time.time()
|
self.data["time_stamp"] = time.time()
|
||||||
|
|
||||||
Logger.log("c", "An uncaught exception has occurred!")
|
Logger.log("c", "An uncaught error has occurred!")
|
||||||
for line in traceback.format_exception(exception_type, value, tb):
|
for line in traceback.format_exception(exception_type, value, tb):
|
||||||
for part in line.rstrip("\n").split("\n"):
|
for part in line.rstrip("\n").split("\n"):
|
||||||
Logger.log("c", part)
|
Logger.log("c", part)
|
||||||
@ -90,7 +90,7 @@ class CrashHandler:
|
|||||||
|
|
||||||
def _messageWidget(self):
|
def _messageWidget(self):
|
||||||
label = QLabel()
|
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>
|
label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal error 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>
|
<p>Please use the "Send report" button to post a bug report automatically to our servers</p>
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ class CrashHandler:
|
|||||||
|
|
||||||
def _exceptionInfoWidget(self):
|
def _exceptionInfoWidget(self):
|
||||||
group = QGroupBox()
|
group = QGroupBox()
|
||||||
group.setTitle(catalog.i18nc("@title:groupbox", "Exception traceback"))
|
group.setTitle(catalog.i18nc("@title:groupbox", "Error traceback"))
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
text_area = QTextEdit()
|
text_area = QTextEdit()
|
||||||
|
@ -127,7 +127,7 @@ 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
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, **kwargs):
|
||||||
|
|
||||||
# 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"]:
|
||||||
@ -208,9 +208,12 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
self._additional_components = {} # Components to add to certain areas in the interface
|
self._additional_components = {} # Components to add to certain areas in the interface
|
||||||
|
|
||||||
super().__init__(name = "cura", version = CuraVersion, buildtype = CuraBuildType,
|
super().__init__(name = "cura",
|
||||||
|
version = CuraVersion,
|
||||||
|
buildtype = CuraBuildType,
|
||||||
is_debug_mode = CuraDebugMode,
|
is_debug_mode = CuraDebugMode,
|
||||||
tray_icon_name = "cura-icon-32.png")
|
tray_icon_name = "cura-icon-32.png",
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
self.default_theme = "cura-light"
|
self.default_theme = "cura-light"
|
||||||
|
|
||||||
@ -313,6 +316,7 @@ class CuraApplication(QtApplication):
|
|||||||
preferences.addPreference("cura/material_settings", "{}")
|
preferences.addPreference("cura/material_settings", "{}")
|
||||||
|
|
||||||
preferences.addPreference("view/invert_zoom", False)
|
preferences.addPreference("view/invert_zoom", False)
|
||||||
|
preferences.addPreference("cura/sidebar_collapse", False)
|
||||||
|
|
||||||
self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
|
self._need_to_show_user_agreement = not Preferences.getInstance().getValue("general/accepted_user_agreement")
|
||||||
|
|
||||||
@ -399,7 +403,11 @@ class CuraApplication(QtApplication):
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def closeApplication(self):
|
def closeApplication(self):
|
||||||
Logger.log("i", "Close application")
|
Logger.log("i", "Close application")
|
||||||
self._main_window.close()
|
main_window = self.getMainWindow()
|
||||||
|
if main_window is not None:
|
||||||
|
main_window.close()
|
||||||
|
else:
|
||||||
|
self.exit(0)
|
||||||
|
|
||||||
## A reusable dialogbox
|
## A reusable dialogbox
|
||||||
#
|
#
|
||||||
@ -507,11 +515,10 @@ class CuraApplication(QtApplication):
|
|||||||
self._plugins_loaded = True
|
self._plugins_loaded = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def addCommandLineOptions(self, parser):
|
def addCommandLineOptions(self, parser, parsed_command_line = {}):
|
||||||
super().addCommandLineOptions(parser)
|
super().addCommandLineOptions(parser, parsed_command_line = parsed_command_line)
|
||||||
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):
|
||||||
@ -565,13 +572,16 @@ class CuraApplication(QtApplication):
|
|||||||
# This should be called directly before creating an instance of CuraApplication.
|
# This should be called directly before creating an instance of CuraApplication.
|
||||||
# \returns \type{bool} True if the whole Cura app should continue running.
|
# \returns \type{bool} True if the whole Cura app should continue running.
|
||||||
@classmethod
|
@classmethod
|
||||||
def preStartUp(cls):
|
def preStartUp(cls, parser = None, parsed_command_line = {}):
|
||||||
# Peek the arguments and look for the 'single-instance' flag.
|
# Peek the arguments and look for the 'single-instance' flag.
|
||||||
parser = argparse.ArgumentParser(prog="cura") # pylint: disable=bad-whitespace
|
if not parser:
|
||||||
CuraApplication.addCommandLineOptions(parser)
|
parser = argparse.ArgumentParser(prog = "cura", add_help = False) # pylint: disable=bad-whitespace
|
||||||
parsed_command_line = vars(parser.parse_args())
|
CuraApplication.addCommandLineOptions(parser, parsed_command_line = parsed_command_line)
|
||||||
|
# Important: It is important to keep this line here!
|
||||||
|
# In Uranium we allow to pass unknown arguments to the final executable or script.
|
||||||
|
parsed_command_line.update(vars(parser.parse_known_args()[0]))
|
||||||
|
|
||||||
if "single_instance" in parsed_command_line and parsed_command_line["single_instance"]:
|
if parsed_command_line["single_instance"]:
|
||||||
Logger.log("i", "Checking for the presence of an ready running Cura instance.")
|
Logger.log("i", "Checking for the presence of an ready running Cura instance.")
|
||||||
single_instance_socket = QLocalSocket()
|
single_instance_socket = QLocalSocket()
|
||||||
Logger.log("d", "preStartUp(): full server name: " + single_instance_socket.fullServerName())
|
Logger.log("d", "preStartUp(): full server name: " + single_instance_socket.fullServerName())
|
||||||
@ -603,7 +613,22 @@ class CuraApplication(QtApplication):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def preRun(self):
|
||||||
|
# Last check for unknown commandline arguments
|
||||||
|
parser = self.getCommandlineParser()
|
||||||
|
parser.add_argument("--help", "-h",
|
||||||
|
action='store_true',
|
||||||
|
default = False,
|
||||||
|
help = "Show this help message and exit."
|
||||||
|
)
|
||||||
|
parsed_args = vars(parser.parse_args()) # This won't allow unknown arguments
|
||||||
|
if parsed_args["help"]:
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
self.preRun()
|
||||||
|
|
||||||
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
|
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
|
||||||
|
|
||||||
self._setUpSingleInstanceServer()
|
self._setUpSingleInstanceServer()
|
||||||
@ -658,12 +683,12 @@ class CuraApplication(QtApplication):
|
|||||||
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))
|
||||||
|
|
||||||
run_headless = self.getCommandLineOption("headless", False)
|
run_without_gui = self.getCommandLineOption("headless", False) or self.getCommandLineOption("invisible", False)
|
||||||
if not run_headless:
|
if not run_without_gui:
|
||||||
self.initializeEngine()
|
self.initializeEngine()
|
||||||
controller.setActiveStage("PrepareStage")
|
controller.setActiveStage("PrepareStage")
|
||||||
|
|
||||||
if run_headless or self._engine.rootObjects:
|
if run_without_gui or self._engine.rootObjects:
|
||||||
self.closeSplash()
|
self.closeSplash()
|
||||||
|
|
||||||
for file_name in self.getCommandLineOption("file", []):
|
for file_name in self.getCommandLineOption("file", []):
|
||||||
@ -1361,7 +1386,8 @@ class CuraApplication(QtApplication):
|
|||||||
# If a model is to small then it will not contain any points
|
# If a model is to small then it will not contain any points
|
||||||
if offset_shape_arr is None and hull_shape_arr is None:
|
if offset_shape_arr is None and hull_shape_arr is None:
|
||||||
Message(self._i18n_catalog.i18nc("@info:status", "The selected model was too small to load."),
|
Message(self._i18n_catalog.i18nc("@info:status", "The selected model was too small to load."),
|
||||||
title=self._i18n_catalog.i18nc("@info:title", "Warning")).show()
|
title=self._i18n_catalog.i18nc("@info:title", "Warning")
|
||||||
|
).show()
|
||||||
return
|
return
|
||||||
|
|
||||||
# Step is for skipping tests to make it a lot faster. it also makes the outcome somewhat rougher
|
# Step is for skipping tests to make it a lot faster. it also makes the outcome somewhat rougher
|
||||||
|
@ -16,6 +16,7 @@ import math
|
|||||||
import os.path
|
import os.path
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import json
|
import json
|
||||||
|
import re #To create abbreviations for printer names.
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
@ -316,15 +317,14 @@ class PrintInformation(QObject):
|
|||||||
return
|
return
|
||||||
|
|
||||||
global_stack_name = global_container_stack.getName()
|
global_stack_name = global_container_stack.getName()
|
||||||
split_name = global_stack_name.split(" ")
|
|
||||||
abbr_machine = ""
|
abbr_machine = ""
|
||||||
for word in split_name:
|
for word in re.findall(r"[\w']+", global_stack_name):
|
||||||
if word.lower() == "ultimaker":
|
if word.lower() == "ultimaker":
|
||||||
abbr_machine += "UM"
|
abbr_machine += "UM"
|
||||||
elif word.isdigit():
|
elif word.isdigit():
|
||||||
abbr_machine += word
|
abbr_machine += word
|
||||||
else:
|
else:
|
||||||
stripped_word = self._stripAccents(word.strip("()[]{}#").upper())
|
stripped_word = self._stripAccents(word.upper())
|
||||||
# - use only the first character if the word is too long (> 3 characters)
|
# - 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)
|
# - use the whole word if it's not too long (<= 3 characters)
|
||||||
if len(stripped_word) > 3:
|
if len(stripped_word) > 3:
|
||||||
|
@ -36,6 +36,11 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# We don't have all the machines loaded in the beginning, so in order to add the missing extruder stack
|
||||||
|
# for single extrusion machines, we subscribe to the containerAdded signal, and whenever a global stack
|
||||||
|
# is added, we check to see if an extruder stack needs to be added.
|
||||||
|
self.containerAdded.connect(self._onContainerAdded)
|
||||||
|
|
||||||
## Overridden from ContainerRegistry
|
## Overridden from ContainerRegistry
|
||||||
#
|
#
|
||||||
# Adds a container to the registry.
|
# Adds a container to the registry.
|
||||||
@ -410,6 +415,17 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
if not extruder_stacks:
|
if not extruder_stacks:
|
||||||
self.addExtruderStackForSingleExtrusionMachine(machine, "fdmextruder")
|
self.addExtruderStackForSingleExtrusionMachine(machine, "fdmextruder")
|
||||||
|
|
||||||
|
def _onContainerAdded(self, container):
|
||||||
|
# We don't have all the machines loaded in the beginning, so in order to add the missing extruder stack
|
||||||
|
# for single extrusion machines, we subscribe to the containerAdded signal, and whenever a global stack
|
||||||
|
# is added, we check to see if an extruder stack needs to be added.
|
||||||
|
if not isinstance(container, ContainerStack) or container.getMetaDataEntry("type") != "machine":
|
||||||
|
return
|
||||||
|
|
||||||
|
extruder_stacks = self.findContainerStacks(type = "extruder_train", machine = container.getId())
|
||||||
|
if not extruder_stacks:
|
||||||
|
self.addExtruderStackForSingleExtrusionMachine(container, "fdmextruder")
|
||||||
|
|
||||||
def addExtruderStackForSingleExtrusionMachine(self, machine, extruder_id):
|
def addExtruderStackForSingleExtrusionMachine(self, machine, extruder_id):
|
||||||
new_extruder_id = extruder_id
|
new_extruder_id = extruder_id
|
||||||
|
|
||||||
@ -425,7 +441,6 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
extruder_stack.setName(extruder_definition.getName())
|
extruder_stack.setName(extruder_definition.getName())
|
||||||
extruder_stack.setDefinition(extruder_definition)
|
extruder_stack.setDefinition(extruder_definition)
|
||||||
extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
|
extruder_stack.addMetaDataEntry("position", extruder_definition.getMetaDataEntry("position"))
|
||||||
extruder_stack.setNextStack(machine)
|
|
||||||
|
|
||||||
# create empty user changes container otherwise
|
# create empty user changes container otherwise
|
||||||
user_container = InstanceContainer(extruder_stack.id + "_user")
|
user_container = InstanceContainer(extruder_stack.id + "_user")
|
||||||
@ -433,7 +448,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
user_container.addMetaDataEntry("machine", extruder_stack.getId())
|
user_container.addMetaDataEntry("machine", extruder_stack.getId())
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
|
user_container.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
|
||||||
user_container.setDefinition(machine.definition)
|
user_container.setDefinition(machine.definition.getId())
|
||||||
|
|
||||||
if machine.userChanges:
|
if machine.userChanges:
|
||||||
# for the newly created extruder stack, we need to move all "per-extruder" settings to the user changes
|
# for the newly created extruder stack, we need to move all "per-extruder" settings to the user changes
|
||||||
@ -444,8 +459,8 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
user_container.addInstance(machine.userChanges.getInstance(user_setting_key))
|
user_container.addInstance(machine.userChanges.getInstance(user_setting_key))
|
||||||
machine.userChanges.removeInstance(user_setting_key, postpone_emit = True)
|
machine.userChanges.removeInstance(user_setting_key, postpone_emit = True)
|
||||||
|
|
||||||
extruder_stack.setUserChanges(user_container)
|
|
||||||
self.addContainer(user_container)
|
self.addContainer(user_container)
|
||||||
|
extruder_stack.setUserChanges(user_container)
|
||||||
|
|
||||||
variant_id = "default"
|
variant_id = "default"
|
||||||
if machine.variant.getId() not in ("empty", "empty_variant"):
|
if machine.variant.getId() not in ("empty", "empty_variant"):
|
||||||
@ -491,6 +506,9 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
|
|
||||||
self.addContainer(extruder_stack)
|
self.addContainer(extruder_stack)
|
||||||
|
|
||||||
|
# Set next stack at the end
|
||||||
|
extruder_stack.setNextStack(machine)
|
||||||
|
|
||||||
return extruder_stack
|
return extruder_stack
|
||||||
|
|
||||||
def _findQualityChangesContainerInCuraFolder(self, name):
|
def _findQualityChangesContainerInCuraFolder(self, name):
|
||||||
|
@ -377,7 +377,7 @@ class CuraContainerStack(ContainerStack):
|
|||||||
if not container or not isinstance(container, DefinitionContainer):
|
if not container or not isinstance(container, DefinitionContainer):
|
||||||
definition = self.findContainer(container_type = DefinitionContainer)
|
definition = self.findContainer(container_type = DefinitionContainer)
|
||||||
if not definition:
|
if not definition:
|
||||||
raise InvalidContainerStackError("Stack {id} does not have a definition!".format(id = self._id))
|
raise InvalidContainerStackError("Stack {id} does not have a definition!".format(id = self.getId()))
|
||||||
|
|
||||||
new_containers[index] = definition
|
new_containers[index] = definition
|
||||||
continue
|
continue
|
||||||
@ -508,7 +508,7 @@ class CuraContainerStack(ContainerStack):
|
|||||||
def findDefaultQuality(self) -> Optional[ContainerInterface]:
|
def findDefaultQuality(self) -> Optional[ContainerInterface]:
|
||||||
definition = self._getMachineDefinition()
|
definition = self._getMachineDefinition()
|
||||||
registry = ContainerRegistry.getInstance()
|
registry = ContainerRegistry.getInstance()
|
||||||
material_container = self.material if self.material != self._empty_instance_container else None
|
material_container = self.material if self.material.getId() not in (self._empty_material.getId(), self._empty_instance_container.getId()) else None
|
||||||
|
|
||||||
search_criteria = {"type": "quality"}
|
search_criteria = {"type": "quality"}
|
||||||
|
|
||||||
@ -552,7 +552,7 @@ class CuraContainerStack(ContainerStack):
|
|||||||
material_search_criteria = {"type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"}
|
material_search_criteria = {"type": "material", "material": material_container.getMetaDataEntry("material"), "color_name": "Generic"}
|
||||||
if definition.getMetaDataEntry("has_machine_quality"):
|
if definition.getMetaDataEntry("has_machine_quality"):
|
||||||
if self.material != self._empty_instance_container:
|
if self.material != self._empty_instance_container:
|
||||||
material_search_criteria["definition"] = material_container.getDefinition().id
|
material_search_criteria["definition"] = material_container.getMetaDataEntry("definition")
|
||||||
|
|
||||||
if definition.getMetaDataEntry("has_variants"):
|
if definition.getMetaDataEntry("has_variants"):
|
||||||
material_search_criteria["variant"] = material_container.getMetaDataEntry("variant")
|
material_search_criteria["variant"] = material_container.getMetaDataEntry("variant")
|
||||||
|
@ -32,6 +32,7 @@ from .CuraStackBuilder import CuraStackBuilder
|
|||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
from cura.Settings.ProfilesModel import ProfilesModel
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -60,9 +61,11 @@ class MachineManager(QObject):
|
|||||||
self._instance_container_timer = QTimer()
|
self._instance_container_timer = QTimer()
|
||||||
self._instance_container_timer.setInterval(250)
|
self._instance_container_timer.setInterval(250)
|
||||||
self._instance_container_timer.setSingleShot(True)
|
self._instance_container_timer.setSingleShot(True)
|
||||||
self._instance_container_timer.timeout.connect(self.__onInstanceContainersChanged)
|
self._instance_container_timer.timeout.connect(self.__emitChangedSignals)
|
||||||
|
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
|
||||||
|
Application.getInstance().getContainerRegistry().containerLoadComplete.connect(self._onInstanceContainersChanged)
|
||||||
|
self._connected_to_profiles_model = False
|
||||||
|
|
||||||
## 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)
|
||||||
@ -333,14 +336,24 @@ class MachineManager(QObject):
|
|||||||
# on _active_container_stack. If it changes, then the properties change.
|
# on _active_container_stack. If it changes, then the properties change.
|
||||||
self.activeQualityChanged.emit()
|
self.activeQualityChanged.emit()
|
||||||
|
|
||||||
def __onInstanceContainersChanged(self):
|
def __emitChangedSignals(self):
|
||||||
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._updateStacksHaveErrors() # Prevents unwanted re-slices after changing machine
|
||||||
self._error_check_timer.start()
|
self._error_check_timer.start()
|
||||||
|
|
||||||
|
def _onProfilesModelChanged(self, *args):
|
||||||
|
self.__emitChangedSignals()
|
||||||
|
|
||||||
def _onInstanceContainersChanged(self, container):
|
def _onInstanceContainersChanged(self, container):
|
||||||
|
# This should not trigger the ProfilesModel to be created, or there will be an infinite recursion
|
||||||
|
if not self._connected_to_profiles_model and ProfilesModel.hasInstance():
|
||||||
|
# This triggers updating the qualityModel in SidebarSimple whenever ProfilesModel is updated
|
||||||
|
Logger.log("d", "Connecting profiles model...")
|
||||||
|
ProfilesModel.getInstance().itemsChanged.connect(self._onProfilesModelChanged)
|
||||||
|
self._connected_to_profiles_model = True
|
||||||
|
|
||||||
self._instance_container_timer.start()
|
self._instance_container_timer.start()
|
||||||
|
|
||||||
def _onPropertyChanged(self, key: str, property_name: str):
|
def _onPropertyChanged(self, key: str, property_name: str):
|
||||||
@ -356,11 +369,13 @@ class MachineManager(QObject):
|
|||||||
self.blurSettings.emit() # Ensure no-one has focus.
|
self.blurSettings.emit() # Ensure no-one has focus.
|
||||||
self._cancelDelayedActiveContainerStackChanges()
|
self._cancelDelayedActiveContainerStackChanges()
|
||||||
|
|
||||||
containers = ContainerRegistry.getInstance().findContainerStacks(id = stack_id)
|
container_registry = ContainerRegistry.getInstance()
|
||||||
|
|
||||||
|
containers = container_registry.findContainerStacks(id = stack_id)
|
||||||
if containers:
|
if containers:
|
||||||
Application.getInstance().setGlobalContainerStack(containers[0])
|
Application.getInstance().setGlobalContainerStack(containers[0])
|
||||||
|
|
||||||
self.__onInstanceContainersChanged()
|
self.__emitChangedSignals()
|
||||||
|
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
def addMachine(self, name: str, definition_id: str) -> None:
|
def addMachine(self, name: str, definition_id: str) -> None:
|
||||||
|
@ -49,6 +49,10 @@ class ProfilesModel(InstanceContainersModel):
|
|||||||
ProfilesModel.__instance = cls()
|
ProfilesModel.__instance = cls()
|
||||||
return ProfilesModel.__instance
|
return ProfilesModel.__instance
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def hasInstance(cls) -> bool:
|
||||||
|
return ProfilesModel.__instance is not None
|
||||||
|
|
||||||
__instance = None # type: "ProfilesModel"
|
__instance = None # type: "ProfilesModel"
|
||||||
|
|
||||||
## Fetch the list of containers to display.
|
## Fetch the list of containers to display.
|
||||||
@ -91,7 +95,6 @@ class ProfilesModel(InstanceContainersModel):
|
|||||||
|
|
||||||
## 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:
|
||||||
|
52
cura_app.py
52
cura_app.py
@ -2,13 +2,40 @@
|
|||||||
|
|
||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2015 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 argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import platform
|
|
||||||
import faulthandler
|
|
||||||
|
|
||||||
from UM.Platform import Platform
|
from UM.Platform import Platform
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(prog = "cura",
|
||||||
|
add_help = False)
|
||||||
|
parser.add_argument('--debug',
|
||||||
|
action='store_true',
|
||||||
|
default = False,
|
||||||
|
help = "Turn on the debug mode by setting this option."
|
||||||
|
)
|
||||||
|
known_args = vars(parser.parse_known_args()[0])
|
||||||
|
|
||||||
|
if not known_args["debug"]:
|
||||||
|
def get_cura_dir_path():
|
||||||
|
if Platform.isWindows():
|
||||||
|
return os.path.expanduser("~/AppData/Roaming/cura/")
|
||||||
|
elif Platform.isLinux():
|
||||||
|
return os.path.expanduser("~/.local/share/cura")
|
||||||
|
elif Platform.isOSX():
|
||||||
|
return os.path.expanduser("~/Library/Logs/cura")
|
||||||
|
|
||||||
|
if hasattr(sys, "frozen"):
|
||||||
|
dirpath = get_cura_dir_path()
|
||||||
|
os.makedirs(dirpath, exist_ok = True)
|
||||||
|
sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w")
|
||||||
|
sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w")
|
||||||
|
|
||||||
|
import platform
|
||||||
|
import faulthandler
|
||||||
|
|
||||||
#WORKAROUND: GITHUB-88 GITHUB-385 GITHUB-612
|
#WORKAROUND: GITHUB-88 GITHUB-385 GITHUB-612
|
||||||
if Platform.isLinux(): # Needed for platform.linux_distribution, which is not available on Windows and OSX
|
if Platform.isLinux(): # Needed for platform.linux_distribution, which is not available on Windows and OSX
|
||||||
# For Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
|
# For Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
|
||||||
@ -47,7 +74,7 @@ def exceptHook(hook_type, value, traceback):
|
|||||||
_crash_handler = CrashHandler(hook_type, value, traceback)
|
_crash_handler = CrashHandler(hook_type, value, traceback)
|
||||||
_crash_handler.show()
|
_crash_handler.show()
|
||||||
|
|
||||||
|
if not known_args["debug"]:
|
||||||
sys.excepthook = exceptHook
|
sys.excepthook = exceptHook
|
||||||
|
|
||||||
# Workaround for a race condition on certain systems where there
|
# Workaround for a race condition on certain systems where there
|
||||||
@ -58,29 +85,14 @@ import Arcus #@UnusedImport
|
|||||||
import cura.CuraApplication
|
import cura.CuraApplication
|
||||||
import cura.Settings.CuraContainerRegistry
|
import cura.Settings.CuraContainerRegistry
|
||||||
|
|
||||||
def get_cura_dir_path():
|
|
||||||
if Platform.isWindows():
|
|
||||||
return os.path.expanduser("~/AppData/Local/cura/")
|
|
||||||
elif Platform.isLinux():
|
|
||||||
return os.path.expanduser("~/.local/share/cura")
|
|
||||||
elif Platform.isOSX():
|
|
||||||
return os.path.expanduser("~/Library/Logs/cura")
|
|
||||||
|
|
||||||
|
|
||||||
if hasattr(sys, "frozen"):
|
|
||||||
dirpath = get_cura_dir_path()
|
|
||||||
os.makedirs(dirpath, exist_ok = True)
|
|
||||||
sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w")
|
|
||||||
sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w")
|
|
||||||
|
|
||||||
faulthandler.enable()
|
faulthandler.enable()
|
||||||
|
|
||||||
# Force an instance of CuraContainerRegistry to be created and reused later.
|
# Force an instance of CuraContainerRegistry to be created and reused later.
|
||||||
cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance()
|
cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance()
|
||||||
|
|
||||||
# This pre-start up check is needed to determine if we should start the application at all.
|
# This pre-start up check is needed to determine if we should start the application at all.
|
||||||
if not cura.CuraApplication.CuraApplication.preStartUp():
|
if not cura.CuraApplication.CuraApplication.preStartUp(parser = parser, parsed_command_line = known_args):
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
app = cura.CuraApplication.CuraApplication.getInstance()
|
app = cura.CuraApplication.CuraApplication.getInstance(parser = parser, parsed_command_line = known_args)
|
||||||
app.run()
|
app.run()
|
||||||
|
@ -86,6 +86,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||||||
#
|
#
|
||||||
self._global_container_stack = None
|
self._global_container_stack = None
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||||
|
Application.getInstance().getExtruderManager().activeExtruderChanged.connect(self._onGlobalStackChanged)
|
||||||
self._onGlobalStackChanged()
|
self._onGlobalStackChanged()
|
||||||
|
|
||||||
Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
|
Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
|
||||||
|
@ -131,12 +131,21 @@ class StartSliceJob(Job):
|
|||||||
Logger.log("w", "No objects suitable for one at a time found, or no correct order found")
|
Logger.log("w", "No objects suitable for one at a time found, or no correct order found")
|
||||||
else:
|
else:
|
||||||
temp_list = []
|
temp_list = []
|
||||||
|
has_printing_mesh = False
|
||||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||||
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
||||||
if not getattr(node, "_outside_buildarea", False) or getattr(node, "_non_printing_mesh", False):
|
_non_printing_mesh = getattr(node, "_non_printing_mesh", False)
|
||||||
|
if not getattr(node, "_outside_buildarea", False) or _non_printing_mesh:
|
||||||
temp_list.append(node)
|
temp_list.append(node)
|
||||||
|
if not _non_printing_mesh:
|
||||||
|
has_printing_mesh = True
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
|
|
||||||
|
#If the list doesn't have any model with suitable settings then clean the list
|
||||||
|
# otherwise CuraEngine will crash
|
||||||
|
if not has_printing_mesh:
|
||||||
|
temp_list.clear()
|
||||||
|
|
||||||
if temp_list:
|
if temp_list:
|
||||||
object_groups.append(temp_list)
|
object_groups.append(temp_list)
|
||||||
|
|
||||||
@ -260,18 +269,23 @@ class StartSliceJob(Job):
|
|||||||
def _buildGlobalSettingsMessage(self, stack):
|
def _buildGlobalSettingsMessage(self, stack):
|
||||||
settings = self._buildReplacementTokens(stack)
|
settings = self._buildReplacementTokens(stack)
|
||||||
|
|
||||||
start_gcode = settings["machine_start_gcode"]
|
|
||||||
# Pre-compute material material_bed_temp_prepend and material_print_temp_prepend
|
# Pre-compute material material_bed_temp_prepend and material_print_temp_prepend
|
||||||
|
start_gcode = settings["machine_start_gcode"]
|
||||||
bed_temperature_settings = {"material_bed_temperature", "material_bed_temperature_layer_0"}
|
bed_temperature_settings = {"material_bed_temperature", "material_bed_temperature_layer_0"}
|
||||||
settings["material_bed_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in bed_temperature_settings))
|
settings["material_bed_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in bed_temperature_settings))
|
||||||
print_temperature_settings = {"material_print_temperature", "material_print_temperature_layer_0", "default_material_print_temperature", "material_initial_print_temperature", "material_final_print_temperature", "material_standby_temperature"}
|
print_temperature_settings = {"material_print_temperature", "material_print_temperature_layer_0", "default_material_print_temperature", "material_initial_print_temperature", "material_final_print_temperature", "material_standby_temperature"}
|
||||||
settings["material_print_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in print_temperature_settings))
|
settings["material_print_temp_prepend"] = all(("{" + setting + "}" not in start_gcode for setting in print_temperature_settings))
|
||||||
|
|
||||||
#Replace the setting tokens in start and end g-code.
|
# Find the correct temperatures from the first used extruder
|
||||||
settings["machine_start_gcode"] = self._expandGcodeTokens(settings["machine_start_gcode"], settings)
|
extruder_stack = Application.getInstance().getExtruderManager().getUsedExtruderStacks()[0]
|
||||||
settings["machine_end_gcode"] = self._expandGcodeTokens(settings["machine_end_gcode"], settings)
|
extruder_0_settings = self._buildReplacementTokens(extruder_stack)
|
||||||
|
|
||||||
for key, value in settings.items(): #Add all submessages for each individual setting.
|
# Replace the setting tokens in start and end g-code.
|
||||||
|
settings["machine_start_gcode"] = self._expandGcodeTokens(settings["machine_start_gcode"], extruder_0_settings)
|
||||||
|
settings["machine_end_gcode"] = self._expandGcodeTokens(settings["machine_end_gcode"], extruder_0_settings)
|
||||||
|
|
||||||
|
# Add all sub-messages for each individual setting.
|
||||||
|
for key, value in settings.items():
|
||||||
setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings")
|
setting_message = self._slice_message.getMessage("global_settings").addRepeatedMessage("settings")
|
||||||
setting_message.name = key
|
setting_message.name = key
|
||||||
setting_message.value = str(value).encode("utf-8")
|
setting_message.value = str(value).encode("utf-8")
|
||||||
|
@ -92,7 +92,7 @@ class SimulationPass(RenderPass):
|
|||||||
|
|
||||||
self.bind()
|
self.bind()
|
||||||
|
|
||||||
tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay)
|
tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay, backface_cull = True)
|
||||||
head_position = None # Indicates the current position of the print head
|
head_position = None # Indicates the current position of the print head
|
||||||
nozzle_node = None
|
nozzle_node = None
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ class SimulationPass(RenderPass):
|
|||||||
self._current_shader = self._layer_shader
|
self._current_shader = self._layer_shader
|
||||||
self._switching_layers = True
|
self._switching_layers = True
|
||||||
|
|
||||||
layers_batch = RenderBatch(self._current_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end))
|
layers_batch = RenderBatch(self._current_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end), backface_cull = True)
|
||||||
layers_batch.addItem(node.getWorldTransformation(), layer_data)
|
layers_batch.addItem(node.getWorldTransformation(), layer_data)
|
||||||
layers_batch.render(self._scene.getActiveCamera())
|
layers_batch.render(self._scene.getActiveCamera())
|
||||||
|
|
||||||
|
@ -187,20 +187,27 @@ geometry41core =
|
|||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head + g_vertex_offset_vert));
|
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz_head + g_vertex_offset_vert));
|
||||||
|
//And reverse so that the line is also visible from the back side.
|
||||||
|
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
||||||
|
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
||||||
|
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
||||||
|
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz + g_vertex_offset_vert));
|
||||||
|
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz_head + g_vertex_offset_vert));
|
||||||
|
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz + g_vertex_offset_vert));
|
||||||
|
|
||||||
EndPrimitive();
|
EndPrimitive();
|
||||||
} else {
|
} else {
|
||||||
// All normal lines are rendered as 3d tubes.
|
// All normal lines are rendered as 3d tubes.
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert));
|
|
||||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
|
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
|
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
|
||||||
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
|
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_vert));
|
||||||
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert));
|
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_vert));
|
||||||
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
myEmitVertex(v_vertex[0], v_color[0], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position + g_vertex_offset_horz));
|
||||||
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
myEmitVertex(v_vertex[1], v_color[1], g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position + g_vertex_offset_horz));
|
||||||
|
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_vert));
|
||||||
|
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_vert, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_vert));
|
||||||
|
myEmitVertex(v_vertex[0], v_color[0], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[0].gl_Position - g_vertex_offset_horz));
|
||||||
|
myEmitVertex(v_vertex[1], v_color[1], -g_vertex_normal_horz, u_viewProjectionMatrix * (gl_in[1].gl_Position - g_vertex_offset_horz));
|
||||||
|
|
||||||
EndPrimitive();
|
EndPrimitive();
|
||||||
|
|
||||||
|
@ -99,7 +99,9 @@ class SliceInfo(Extension):
|
|||||||
"type": extruder.material.getMetaData().get("material", ""),
|
"type": extruder.material.getMetaData().get("material", ""),
|
||||||
"brand": extruder.material.getMetaData().get("brand", "")
|
"brand": extruder.material.getMetaData().get("brand", "")
|
||||||
}
|
}
|
||||||
extruder_dict["material_used"] = print_information.materialLengths[int(extruder.getMetaDataEntry("position", "0"))]
|
extruder_position = int(extruder.getMetaDataEntry("position", "0"))
|
||||||
|
if extruder_position in print_information.materialLengths:
|
||||||
|
extruder_dict["material_used"] = print_information.materialLengths[extruder_position]
|
||||||
extruder_dict["variant"] = extruder.variant.getName()
|
extruder_dict["variant"] = extruder.variant.getName()
|
||||||
extruder_dict["nozzle_size"] = extruder.getProperty("machine_nozzle_size", "value")
|
extruder_dict["nozzle_size"] = extruder.getProperty("machine_nozzle_size", "value")
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
|||||||
# List of old printer names. This is used to ensure that a refresh of zeroconf does not needlessly forces
|
# List of old printer names. This is used to ensure that a refresh of zeroconf does not needlessly forces
|
||||||
# authentication requests.
|
# authentication requests.
|
||||||
self._old_printers = []
|
self._old_printers = []
|
||||||
|
self._excluded_addresses = ["127.0.0.1"] # Adding a list of not allowed IP addresses. At this moment, just localhost
|
||||||
|
|
||||||
# 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.
|
||||||
self.addPrinterSignal.connect(self.addPrinter)
|
self.addPrinterSignal.connect(self.addPrinter)
|
||||||
@ -300,6 +301,9 @@ class NetworkPrinterOutputDevicePlugin(QObject, OutputDevicePlugin):
|
|||||||
if type_of_device:
|
if type_of_device:
|
||||||
if type_of_device == b"printer":
|
if type_of_device == b"printer":
|
||||||
address = '.'.join(map(lambda n: str(n), info.address))
|
address = '.'.join(map(lambda n: str(n), info.address))
|
||||||
|
if address in self._excluded_addresses:
|
||||||
|
Logger.log("d", "The IP address %s of the printer \'%s\' is not correct. Trying to reconnect.", address, name)
|
||||||
|
return False # When getting the localhost IP, then try to reconnect
|
||||||
self.addPrinterSignal.emit(str(name), address, info.properties)
|
self.addPrinterSignal.emit(str(name), address, info.properties)
|
||||||
else:
|
else:
|
||||||
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 )
|
||||||
|
@ -122,6 +122,21 @@ class VersionUpgrade30to31(VersionUpgrade):
|
|||||||
if len(all_quality_changes) <= 1 and not parser.has_option("metadata", "extruder"):
|
if len(all_quality_changes) <= 1 and not parser.has_option("metadata", "extruder"):
|
||||||
self._createExtruderQualityChangesForSingleExtrusionMachine(filename, parser)
|
self._createExtruderQualityChangesForSingleExtrusionMachine(filename, parser)
|
||||||
|
|
||||||
|
if parser["metadata"]["type"] == "definition_changes":
|
||||||
|
if parser["general"]["definition"] == "custom":
|
||||||
|
|
||||||
|
# We are only interested in machine_nozzle_size
|
||||||
|
if parser.has_option("values", "machine_nozzle_size"):
|
||||||
|
machine_nozzle_size = parser["values"]["machine_nozzle_size"]
|
||||||
|
|
||||||
|
definition_name = parser["general"]["name"]
|
||||||
|
machine_extruders = self._getSingleExtrusionMachineExtruders(definition_name)
|
||||||
|
|
||||||
|
#For single extuder machine we nee only first extruder
|
||||||
|
if len(machine_extruders) !=0:
|
||||||
|
if self._updateSingleExtuderDefinitionFile(machine_extruders, machine_nozzle_size):
|
||||||
|
parser.remove_option("values", "machine_nozzle_size")
|
||||||
|
|
||||||
# Update version numbers
|
# Update version numbers
|
||||||
parser["general"]["version"] = "2"
|
parser["general"]["version"] = "2"
|
||||||
parser["metadata"]["setting_version"] = "4"
|
parser["metadata"]["setting_version"] = "4"
|
||||||
@ -200,6 +215,133 @@ class VersionUpgrade30to31(VersionUpgrade):
|
|||||||
|
|
||||||
return quality_changes_containers
|
return quality_changes_containers
|
||||||
|
|
||||||
|
def _getSingleExtrusionMachineExtruders(self, definition_name):
|
||||||
|
|
||||||
|
machine_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.MachineStack)
|
||||||
|
|
||||||
|
machine_instances = []
|
||||||
|
|
||||||
|
#Find all machine instances
|
||||||
|
for item in os.listdir(machine_instances_dir):
|
||||||
|
file_path = os.path.join(machine_instances_dir, item)
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
parser = configparser.ConfigParser(interpolation=None)
|
||||||
|
try:
|
||||||
|
parser.read([file_path])
|
||||||
|
except:
|
||||||
|
# skip, it is not a valid stack file
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not parser.has_option("metadata", "type"):
|
||||||
|
continue
|
||||||
|
if "machine" != parser["metadata"]["type"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not parser.has_option("general", "id"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
machine_instances.append(parser)
|
||||||
|
|
||||||
|
#Find for extruders
|
||||||
|
extruders_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack)
|
||||||
|
#"machine",[extruders]
|
||||||
|
extruder_instances_per_machine = {}
|
||||||
|
|
||||||
|
#Find all custom extruders for founded machines
|
||||||
|
for item in os.listdir(extruders_instances_dir):
|
||||||
|
file_path = os.path.join(extruders_instances_dir, item)
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
parser = configparser.ConfigParser(interpolation=None)
|
||||||
|
try:
|
||||||
|
parser.read([file_path])
|
||||||
|
except:
|
||||||
|
# skip, it is not a valid stack file
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not parser.has_option("metadata", "type"):
|
||||||
|
continue
|
||||||
|
if "extruder_train" != parser["metadata"]["type"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not parser.has_option("metadata", "machine"):
|
||||||
|
continue
|
||||||
|
if not parser.has_option("metadata", "position"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
for machine_instace in machine_instances:
|
||||||
|
|
||||||
|
machine_id = machine_instace["general"]["id"]
|
||||||
|
if machine_id != parser["metadata"]["machine"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if machine_id + "_settings" != definition_name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if extruder_instances_per_machine.get(machine_id) is None:
|
||||||
|
extruder_instances_per_machine.update({machine_id:[]})
|
||||||
|
|
||||||
|
extruder_instances_per_machine.get(machine_id).append(parser)
|
||||||
|
#the extruder can be related only to one machine
|
||||||
|
break
|
||||||
|
|
||||||
|
return extruder_instances_per_machine
|
||||||
|
|
||||||
|
#Find extruder defition at index 0 and update its values
|
||||||
|
def _updateSingleExtuderDefinitionFile(self, extruder_instances_per_machine, machine_nozzle_size):
|
||||||
|
|
||||||
|
defintion_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.DefinitionChangesContainer)
|
||||||
|
|
||||||
|
for item in os.listdir(defintion_instances_dir):
|
||||||
|
file_path = os.path.join(defintion_instances_dir, item)
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
parser = configparser.ConfigParser(interpolation=None)
|
||||||
|
try:
|
||||||
|
parser.read([file_path])
|
||||||
|
except:
|
||||||
|
# skip, it is not a valid stack file
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not parser.has_option("general", "name"):
|
||||||
|
continue
|
||||||
|
name = parser["general"]["name"]
|
||||||
|
custom_extruder_at_0_position = None
|
||||||
|
for machine_extruders in extruder_instances_per_machine:
|
||||||
|
for extruder_instance in extruder_instances_per_machine[machine_extruders]:
|
||||||
|
|
||||||
|
if extruder_instance["general"]["id"] + "_settings" == name:
|
||||||
|
defition_position = extruder_instance["metadata"]["position"]
|
||||||
|
|
||||||
|
if defition_position == "0":
|
||||||
|
custom_extruder_at_0_position = extruder_instance
|
||||||
|
break
|
||||||
|
if custom_extruder_at_0_position is not None:
|
||||||
|
break
|
||||||
|
|
||||||
|
#If not null, then parsed file is for first extuder and then can be updated. I need to update only
|
||||||
|
# first, because this update for single extuder machine
|
||||||
|
if custom_extruder_at_0_position is not None:
|
||||||
|
|
||||||
|
#Add new value
|
||||||
|
parser["values"]["machine_nozzle_size"] = machine_nozzle_size
|
||||||
|
|
||||||
|
definition_output = io.StringIO()
|
||||||
|
parser.write(definition_output)
|
||||||
|
|
||||||
|
with open(file_path, "w") as f:
|
||||||
|
f.write(definition_output.getvalue())
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _createExtruderQualityChangesForSingleExtrusionMachine(self, filename, global_quality_changes):
|
def _createExtruderQualityChangesForSingleExtrusionMachine(self, filename, global_quality_changes):
|
||||||
suffix = "_" + quote_plus(global_quality_changes["general"]["name"].lower())
|
suffix = "_" + quote_plus(global_quality_changes["general"]["name"].lower())
|
||||||
machine_name = os.path.os.path.basename(filename).replace(".inst.cfg", "").replace(suffix, "")
|
machine_name = os.path.os.path.basename(filename).replace(".inst.cfg", "").replace(suffix, "")
|
||||||
|
@ -212,11 +212,12 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
|
|
||||||
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:
|
|
||||||
product = UM.Dictionary.findKey(product_id_map, definition_id)
|
|
||||||
except ValueError:
|
|
||||||
# An unknown product id; export it anyway
|
|
||||||
product = definition_id
|
product = definition_id
|
||||||
|
for product_name, product_id_list in product_id_map.items():
|
||||||
|
if definition_id in product_id_list:
|
||||||
|
product = product_name
|
||||||
|
break
|
||||||
|
|
||||||
builder.start("machine")
|
builder.start("machine")
|
||||||
builder.start("machine_identifier", {
|
builder.start("machine_identifier", {
|
||||||
@ -530,16 +531,17 @@ 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 = product_id_map.get(identifier.get("product"), None)
|
machine_id_list = product_id_map.get(identifier.get("product"), [])
|
||||||
if machine_id is None:
|
if not machine_id_list:
|
||||||
# Lets try again with some naive heuristics.
|
machine_id_list = self.getPossibleDefinitionIDsFromName(identifier.get("product"))
|
||||||
machine_id = identifier.get("product").replace(" ", "").lower()
|
|
||||||
|
|
||||||
|
for machine_id in machine_id_list:
|
||||||
definitions = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
definitions = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
||||||
if not definitions:
|
if not definitions:
|
||||||
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
Logger.log("d", "Found definition for machine ID %s", machine_id)
|
||||||
definition = definitions[0]
|
definition = definitions[0]
|
||||||
|
|
||||||
machine_manufacturer = identifier.get("manufacturer", definition.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
machine_manufacturer = identifier.get("manufacturer", definition.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
||||||
@ -583,7 +585,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
|
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = hotend_id)
|
||||||
if not variant_containers:
|
if not variant_containers:
|
||||||
# It is not really properly defined what "ID" is so also search for variants by name.
|
# It is not really properly defined what "ID" is so also search for variants by name.
|
||||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = definition["id"], name = hotend_id)
|
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = hotend_id)
|
||||||
|
|
||||||
if not variant_containers:
|
if not variant_containers:
|
||||||
continue
|
continue
|
||||||
@ -616,6 +618,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
new_hotend_material.getMetaData()["id"] = new_hotend_id
|
new_hotend_material.getMetaData()["id"] = new_hotend_id
|
||||||
new_hotend_material.getMetaData()["name"] = self.getName()
|
new_hotend_material.getMetaData()["name"] = self.getName()
|
||||||
new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"]
|
new_hotend_material.getMetaData()["variant"] = variant_containers[0]["id"]
|
||||||
|
new_hotend_material.setDefinition(machine_id)
|
||||||
# Don't use setMetadata, as that overrides it for all materials with same base file
|
# Don't use setMetadata, as that overrides it for all materials with same base file
|
||||||
new_hotend_material.getMetaData()["compatible"] = hotend_compatibility
|
new_hotend_material.getMetaData()["compatible"] = hotend_compatibility
|
||||||
new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
|
new_hotend_material.getMetaData()["machine_manufacturer"] = machine_manufacturer
|
||||||
@ -631,6 +634,10 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
if is_new_material:
|
if is_new_material:
|
||||||
containers_to_add.append(new_hotend_material)
|
containers_to_add.append(new_hotend_material)
|
||||||
|
|
||||||
|
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
||||||
|
# a workable ID for that machine, so there is no need to continue
|
||||||
|
break
|
||||||
|
|
||||||
for container_to_add in containers_to_add:
|
for container_to_add in containers_to_add:
|
||||||
ContainerRegistry.getInstance().addContainer(container_to_add)
|
ContainerRegistry.getInstance().addContainer(container_to_add)
|
||||||
|
|
||||||
@ -720,14 +727,17 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
machine_compatibility = cls._parseCompatibleValue(entry.text)
|
machine_compatibility = cls._parseCompatibleValue(entry.text)
|
||||||
|
|
||||||
for identifier in machine.iterfind("./um:machine_identifier", cls.__namespaces):
|
for identifier in machine.iterfind("./um:machine_identifier", cls.__namespaces):
|
||||||
machine_id = product_id_map.get(identifier.get("product"), None)
|
machine_id_list = product_id_map.get(identifier.get("product"), [])
|
||||||
if machine_id is None:
|
if not machine_id_list:
|
||||||
# Lets try again with some naive heuristics.
|
machine_id_list = cls.getPossibleDefinitionIDsFromName(identifier.get("product"))
|
||||||
machine_id = identifier.get("product").replace(" ", "").lower()
|
|
||||||
|
for machine_id in machine_id_list:
|
||||||
definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = machine_id)
|
||||||
if not definition_metadata:
|
if not definition_metadata:
|
||||||
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
Logger.log("w", "No definition found for machine ID %s", machine_id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
Logger.log("d", "Found def for machine [%s]", machine_id)
|
||||||
definition_metadata = definition_metadata[0]
|
definition_metadata = definition_metadata[0]
|
||||||
|
|
||||||
machine_manufacturer = identifier.get("manufacturer", definition_metadata.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
machine_manufacturer = identifier.get("manufacturer", definition_metadata.get("manufacturer", "Unknown")) #If the XML material doesn't specify a manufacturer, use the one in the actual printer definition.
|
||||||
@ -794,6 +804,10 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
if len(found_materials) == 0:
|
if len(found_materials) == 0:
|
||||||
result_metadata.append(new_hotend_material_metadata)
|
result_metadata.append(new_hotend_material_metadata)
|
||||||
|
|
||||||
|
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
||||||
|
# a workable ID for that machine, so there is no need to continue
|
||||||
|
break
|
||||||
|
|
||||||
return result_metadata
|
return result_metadata
|
||||||
|
|
||||||
def _addSettingElement(self, builder, instance):
|
def _addSettingElement(self, builder, instance):
|
||||||
@ -813,15 +827,41 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
else:
|
else:
|
||||||
return material_name
|
return material_name
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getPossibleDefinitionIDsFromName(cls, name):
|
||||||
|
name_parts = name.lower().split(" ")
|
||||||
|
merged_name_parts = []
|
||||||
|
for part in name_parts:
|
||||||
|
if len(part) == 0:
|
||||||
|
continue
|
||||||
|
if len(merged_name_parts) == 0:
|
||||||
|
merged_name_parts.append(part)
|
||||||
|
continue
|
||||||
|
if part.isdigit():
|
||||||
|
# for names with digit(s) such as Ultimaker 3 Extended, we generate an ID like
|
||||||
|
# "ultimaker3_extended", ignoring the space between "Ultimaker" and "3".
|
||||||
|
merged_name_parts[-1] = merged_name_parts[-1] + part
|
||||||
|
else:
|
||||||
|
merged_name_parts.append(part)
|
||||||
|
|
||||||
|
id_list = [name.lower().replace(" ", ""), # simply removing all spaces
|
||||||
|
name.lower().replace(" ", "_"), # simply replacing all spaces with underscores
|
||||||
|
"_".join(merged_name_parts),
|
||||||
|
]
|
||||||
|
|
||||||
|
return id_list
|
||||||
|
|
||||||
## Gets a mapping from product names in the XML files to their definition
|
## Gets a mapping from product names in the XML files to their definition
|
||||||
# IDs.
|
# IDs.
|
||||||
#
|
#
|
||||||
# This loads the mapping from a file.
|
# This loads the mapping from a file.
|
||||||
@classmethod
|
@classmethod
|
||||||
def getProductIdMap(cls) -> Dict[str, str]:
|
def getProductIdMap(cls) -> Dict[str, List[str]]:
|
||||||
product_to_id_file = os.path.join(os.path.dirname(sys.modules[cls.__module__].__file__), "product_to_id.json")
|
product_to_id_file = os.path.join(os.path.dirname(sys.modules[cls.__module__].__file__), "product_to_id.json")
|
||||||
with open(product_to_id_file) as f:
|
with open(product_to_id_file) as f:
|
||||||
return json.load(f)
|
product_to_id_map = json.load(f)
|
||||||
|
product_to_id_map = {key: [value] for key, value in product_to_id_map.items()}
|
||||||
|
return product_to_id_map
|
||||||
|
|
||||||
## Parse the value of the "material compatible" property.
|
## Parse the value of the "material compatible" property.
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
"default_value": "RepRap (Marlin/Sprinter)"
|
"default_value": "RepRap (Marlin/Sprinter)"
|
||||||
},
|
},
|
||||||
"machine_start_gcode": {
|
"machine_start_gcode": {
|
||||||
"default_value": "G28 ; Home extruder\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\nM190 S{material_bed_temperature}\nM104 T0 S{material_print_temperature}\nM109 T0 S{material_print_temperature}\nM104 T1 S{material_print_temperature}\nM109 T1 S{material_print_temperature}\nG32 S3 ; auto level\nG92 E0 ; Reset extruder position"
|
"default_value": "G28 ; Home extruder\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\nM190 S{material_bed_temperature}\nM104 T0 S{material_print_temperature}\nM109 T0 S{material_print_temperature}\nM104 T1 S{material_print_temperature}\nM109 T1 S{material_print_temperature}\n;G32 S3 ; auto level\nG92 E0 ; Reset extruder position"
|
||||||
},
|
},
|
||||||
"machine_end_gcode": {
|
"machine_end_gcode": {
|
||||||
"default_value": "M104 S0 ; turn off extruders\nM140 S0 ; heated bed heater off\nG91 ; relative positioning\nG1 E-2 F5000; retract 2mm\nG28 Z; move bed down\nG90 ; absolute positioning\nM84 ; disable motors"
|
"default_value": "M104 S0 ; turn off extruders\nM140 S0 ; heated bed heater off\nG91 ; relative positioning\nG1 E-2 F5000; retract 2mm\nG28 Z; move bed down\nG90 ; absolute positioning\nM84 ; disable motors"
|
||||||
|
@ -18,6 +18,7 @@ Item
|
|||||||
property alias redo: redoAction;
|
property alias redo: redoAction;
|
||||||
|
|
||||||
property alias homeCamera: homeCameraAction;
|
property alias homeCamera: homeCameraAction;
|
||||||
|
property alias expandSidebar: expandSidebarAction;
|
||||||
|
|
||||||
property alias deleteSelection: deleteSelectionAction;
|
property alias deleteSelection: deleteSelectionAction;
|
||||||
property alias centerSelection: centerSelectionAction;
|
property alias centerSelection: centerSelectionAction;
|
||||||
@ -389,4 +390,11 @@ Item
|
|||||||
text: catalog.i18nc("@action:menu", "Installed plugins...");
|
text: catalog.i18nc("@action:menu", "Installed plugins...");
|
||||||
iconName: "plugins_configure"
|
iconName: "plugins_configure"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action
|
||||||
|
{
|
||||||
|
id: expandSidebarAction;
|
||||||
|
text: catalog.i18nc("@action:inmenu menubar:view","Expand/Collapse Sidebar");
|
||||||
|
shortcut: "Ctrl+E";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,24 @@ UM.MainWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onWidthChanged:
|
||||||
|
{
|
||||||
|
// If slidebar is collapsed then it should be invisible
|
||||||
|
// otherwise after the main_window resize the sidebar will be fully re-drawn
|
||||||
|
if (sidebar.collapsed){
|
||||||
|
if (sidebar.visible == true){
|
||||||
|
sidebar.visible = false
|
||||||
|
sidebar.initialWidth = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (sidebar.visible == false){
|
||||||
|
sidebar.visible = true
|
||||||
|
sidebar.initialWidth = UM.Theme.getSize("sidebar").width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted:
|
Component.onCompleted:
|
||||||
{
|
{
|
||||||
CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
|
CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
|
||||||
@ -369,16 +387,59 @@ UM.MainWindow
|
|||||||
{
|
{
|
||||||
id: sidebar
|
id: sidebar
|
||||||
|
|
||||||
anchors
|
property bool collapsed: false;
|
||||||
{
|
property var initialWidth: UM.Theme.getSize("sidebar").width;
|
||||||
top: topbar.bottom
|
|
||||||
bottom: parent.bottom
|
function callExpandOrCollapse() {
|
||||||
right: parent.right
|
if (collapsed) {
|
||||||
|
sidebar.visible = true;
|
||||||
|
sidebar.initialWidth = UM.Theme.getSize("sidebar").width;
|
||||||
|
viewportRect = Qt.rect(0, 0, (base.width - sidebar.width) / base.width, 1.0);
|
||||||
|
expandSidebarAnimation.start();
|
||||||
|
} else {
|
||||||
|
viewportRect = Qt.rect(0, 0, 1, 1.0);
|
||||||
|
collapseSidebarAnimation.start();
|
||||||
|
}
|
||||||
|
collapsed = !collapsed;
|
||||||
|
UM.Preferences.setValue("cura/sidebar_collapse", collapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
width: UM.Theme.getSize("sidebar").width
|
anchors
|
||||||
|
{
|
||||||
|
top: topbar.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
width: initialWidth
|
||||||
|
x: base.width - sidebar.width
|
||||||
source: UM.Controller.activeStage.sidebarComponent
|
source: UM.Controller.activeStage.sidebarComponent
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: collapseSidebarAnimation
|
||||||
|
target: sidebar
|
||||||
|
properties: "x"
|
||||||
|
to: base.width
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: expandSidebarAnimation
|
||||||
|
target: sidebar
|
||||||
|
properties: "x"
|
||||||
|
to: base.width - sidebar.width
|
||||||
|
duration: 100
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted:
|
||||||
|
{
|
||||||
|
var sidebarCollapsed = UM.Preferences.getValue("cura/sidebar_collapse");
|
||||||
|
|
||||||
|
if (sidebarCollapsed) {
|
||||||
|
sidebar.collapsed = true;
|
||||||
|
viewportRect = Qt.rect(0, 0, 1, 1.0)
|
||||||
|
collapseSidebarAnimation.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader
|
Loader
|
||||||
@ -417,6 +478,13 @@ UM.MainWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expand or collapse sidebar
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: Cura.Actions.expandSidebar
|
||||||
|
onTriggered: sidebar.callExpandOrCollapse()
|
||||||
|
}
|
||||||
|
|
||||||
UM.PreferencesDialog
|
UM.PreferencesDialog
|
||||||
{
|
{
|
||||||
id: preferences
|
id: preferences
|
||||||
|
71
resources/qml/MachineSelection.qml
Normal file
71
resources/qml/MachineSelection.qml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// 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.1
|
||||||
|
import QtQuick.Controls.Styles 1.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
|
||||||
|
import UM 1.2 as UM
|
||||||
|
import Cura 1.0 as Cura
|
||||||
|
import "Menus"
|
||||||
|
|
||||||
|
ToolButton
|
||||||
|
{
|
||||||
|
text: Cura.MachineManager.activeMachineName
|
||||||
|
|
||||||
|
tooltip: Cura.MachineManager.activeMachineName
|
||||||
|
|
||||||
|
style: ButtonStyle
|
||||||
|
{
|
||||||
|
background: Rectangle
|
||||||
|
{
|
||||||
|
color:
|
||||||
|
{
|
||||||
|
if(control.pressed)
|
||||||
|
{
|
||||||
|
return UM.Theme.getColor("sidebar_header_active");
|
||||||
|
}
|
||||||
|
else if(control.hovered)
|
||||||
|
{
|
||||||
|
return UM.Theme.getColor("sidebar_header_hover");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return UM.Theme.getColor("sidebar_header_bar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on color { ColorAnimation { duration: 50; } }
|
||||||
|
|
||||||
|
UM.RecolorImage
|
||||||
|
{
|
||||||
|
id: downArrow
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||||
|
width: UM.Theme.getSize("standard_arrow").width
|
||||||
|
height: UM.Theme.getSize("standard_arrow").height
|
||||||
|
sourceSize.width: width
|
||||||
|
sourceSize.height: width
|
||||||
|
color: UM.Theme.getColor("text_emphasis")
|
||||||
|
source: UM.Theme.getIcon("arrow_bottom")
|
||||||
|
}
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
id: sidebarComboBoxLabel
|
||||||
|
color: UM.Theme.getColor("sidebar_header_text_active")
|
||||||
|
text: control.text;
|
||||||
|
elide: Text.ElideRight;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2
|
||||||
|
anchors.right: downArrow.left;
|
||||||
|
anchors.rightMargin: control.rightMargin;
|
||||||
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
|
font: UM.Theme.getFont("large")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label: Label {}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu: PrinterMenu { }
|
||||||
|
}
|
@ -32,4 +32,5 @@ Menu
|
|||||||
|
|
||||||
MenuSeparator {}
|
MenuSeparator {}
|
||||||
MenuItem { action: Cura.Actions.homeCamera; }
|
MenuItem { action: Cura.Actions.homeCamera; }
|
||||||
|
MenuItem { action: Cura.Actions.expandSidebar; }
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,9 @@ Item {
|
|||||||
id: base;
|
id: base;
|
||||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||||
|
|
||||||
property real progress: UM.Backend.progress;
|
property real progress: UM.Backend.progress
|
||||||
property int backendState: UM.Backend.state;
|
property int backendState: UM.Backend.state
|
||||||
|
property bool activity: CuraApplication.platformActivity
|
||||||
property var backend: CuraApplication.getBackend();
|
|
||||||
property bool activity: CuraApplication.platformActivity;
|
|
||||||
|
|
||||||
property alias buttonRowWidth: saveRow.width
|
property alias buttonRowWidth: saveRow.width
|
||||||
|
|
||||||
@ -50,10 +48,14 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sliceOrStopSlicing() {
|
function sliceOrStopSlicing() {
|
||||||
if (backend != "undefined" && [1, 5].indexOf(UM.Backend.state) != -1) {
|
try {
|
||||||
backend.forceSlice();
|
if ([1, 5].indexOf(base.backendState) != -1) {
|
||||||
|
CuraApplication.backend.forceSlice();
|
||||||
} else {
|
} else {
|
||||||
backend.stopSlicing();
|
CuraApplication.backend.stopSlicing();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Could not start or stop slicing', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +168,7 @@ Item {
|
|||||||
Button {
|
Button {
|
||||||
id: prepareButton
|
id: prepareButton
|
||||||
|
|
||||||
tooltip: [1, 5].indexOf(UM.Backend.state) != -1 ? catalog.i18nc("@info:tooltip","Slice current printjob") : catalog.i18nc("@info:tooltip","Cancel slicing process")
|
tooltip: [1, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@info:tooltip","Slice current printjob") : catalog.i18nc("@info:tooltip","Cancel slicing process")
|
||||||
// 1 = not started, 2 = Processing
|
// 1 = not started, 2 = Processing
|
||||||
enabled: base.backendState != "undefined" && (base.backendState == 1 || base.backendState == 2) && base.activity == true
|
enabled: base.backendState != "undefined" && (base.backendState == 1 || base.backendState == 2) && base.activity == true
|
||||||
visible: base.backendState != "undefined" && !autoSlice && (base.backendState == 1 || base.backendState == 2) && base.activity == true
|
visible: base.backendState != "undefined" && !autoSlice && (base.backendState == 1 || base.backendState == 2) && base.activity == true
|
||||||
@ -178,7 +180,7 @@ Item {
|
|||||||
anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
|
anchors.rightMargin: UM.Theme.getSize("sidebar_margin").width
|
||||||
|
|
||||||
// 1 = not started, 5 = disabled
|
// 1 = not started, 5 = disabled
|
||||||
text: [1, 5].indexOf(UM.Backend.state) != -1 ? catalog.i18nc("@label:Printjob", "Prepare") : catalog.i18nc("@label:Printjob", "Cancel")
|
text: [1, 5].indexOf(base.backendState) != -1 ? catalog.i18nc("@label:Printjob", "Prepare") : catalog.i18nc("@label:Printjob", "Cancel")
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
sliceOrStopSlicing();
|
sliceOrStopSlicing();
|
||||||
|
@ -14,11 +14,13 @@ import "."
|
|||||||
Item {
|
Item {
|
||||||
id: base;
|
id: base;
|
||||||
|
|
||||||
height: UM.Theme.getSize("section").height;
|
height: UM.Theme.getSize("section").height
|
||||||
|
|
||||||
property alias contents: controlContainer.children;
|
property alias contents: controlContainer.children
|
||||||
property alias hovered: mouse.containsMouse
|
property alias hovered: mouse.containsMouse
|
||||||
|
|
||||||
|
property var resetHandler: false
|
||||||
|
|
||||||
property var showRevertButton: true
|
property var showRevertButton: true
|
||||||
property var showInheritButton: true
|
property var showInheritButton: true
|
||||||
property var showLinkedSettingIcon: true
|
property var showLinkedSettingIcon: true
|
||||||
@ -179,8 +181,13 @@ Item {
|
|||||||
iconSource: UM.Theme.getIcon("reset")
|
iconSource: UM.Theme.getIcon("reset")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
revertButton.focus = true;
|
revertButton.focus = true
|
||||||
Cura.MachineManager.clearUserSettingAllCurrentStacks(propertyProvider.key);
|
|
||||||
|
if (resetHandler) {
|
||||||
|
resetHandler(propertyProvider.key)
|
||||||
|
} else {
|
||||||
|
Cura.MachineManager.clearUserSettingAllCurrentStacks(propertyProvider.key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) }
|
onEntered: { hoverTimer.stop(); base.showTooltip(catalog.i18nc("@label", "This setting has a value that is different from the profile.\n\nClick to restore the value of the profile.")) }
|
||||||
|
@ -22,7 +22,6 @@ Rectangle
|
|||||||
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
||||||
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
|
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
|
||||||
property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
|
property var connectedPrinter: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
|
||||||
property int backendState: UM.Backend.state
|
|
||||||
|
|
||||||
property bool monitoringPrint: UM.Controller.activeStage.stageId == "MonitorStage"
|
property bool monitoringPrint: UM.Controller.activeStage.stageId == "MonitorStage"
|
||||||
|
|
||||||
@ -87,10 +86,19 @@ Rectangle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MachineSelection {
|
||||||
|
id: machineSelection
|
||||||
|
width: base.width
|
||||||
|
height: UM.Theme.getSize("sidebar_header").height
|
||||||
|
anchors.top: base.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
}
|
||||||
|
|
||||||
SidebarHeader {
|
SidebarHeader {
|
||||||
id: header
|
id: header
|
||||||
width: parent.width
|
width: parent.width
|
||||||
visible: machineExtruderCount.properties.value > 1 || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants
|
visible: machineExtruderCount.properties.value > 1 || Cura.MachineManager.hasMaterials || Cura.MachineManager.hasVariants
|
||||||
|
anchors.top: machineSelection.bottom
|
||||||
|
|
||||||
onShowTooltip: base.showTooltip(item, location, text)
|
onShowTooltip: base.showTooltip(item, location, text)
|
||||||
onHideTooltip: base.hideTooltip()
|
onHideTooltip: base.hideTooltip()
|
||||||
@ -263,7 +271,7 @@ Rectangle
|
|||||||
{
|
{
|
||||||
id: controlItem
|
id: controlItem
|
||||||
anchors.bottom: footerSeparator.top
|
anchors.bottom: footerSeparator.top
|
||||||
anchors.top: monitoringPrint ? base.top : headerSeparator.bottom
|
anchors.top: monitoringPrint ? machineSelection.bottom : headerSeparator.bottom
|
||||||
anchors.left: base.left
|
anchors.left: base.left
|
||||||
anchors.right: base.right
|
anchors.right: base.right
|
||||||
sourceComponent:
|
sourceComponent:
|
||||||
@ -282,7 +290,7 @@ Rectangle
|
|||||||
Loader
|
Loader
|
||||||
{
|
{
|
||||||
anchors.bottom: footerSeparator.top
|
anchors.bottom: footerSeparator.top
|
||||||
anchors.top: monitoringPrint ? base.top : headerSeparator.bottom
|
anchors.top: monitoringPrint ? machineSelection.bottom : headerSeparator.bottom
|
||||||
anchors.left: base.left
|
anchors.left: base.left
|
||||||
anchors.right: base.right
|
anchors.right: base.right
|
||||||
source:
|
source:
|
||||||
|
@ -21,6 +21,22 @@ Rectangle
|
|||||||
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
||||||
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
|
property bool printerAcceptsCommands: printerConnected && Cura.MachineManager.printerOutputDevices[0].acceptsCommands
|
||||||
|
|
||||||
|
property int rightMargin: UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width;
|
||||||
|
property int allItemsWidth: 0;
|
||||||
|
|
||||||
|
function updateMarginsAndSizes() {
|
||||||
|
if (UM.Preferences.getValue("cura/sidebar_collapse")) {
|
||||||
|
rightMargin = UM.Theme.getSize("default_margin").width;
|
||||||
|
} else {
|
||||||
|
rightMargin = UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width;
|
||||||
|
}
|
||||||
|
allItemsWidth = (
|
||||||
|
logo.width + UM.Theme.getSize("topbar_logo_right_margin").width +
|
||||||
|
UM.Theme.getSize("topbar_logo_right_margin").width + stagesMenuContainer.width +
|
||||||
|
UM.Theme.getSize("default_margin").width + viewModeButton.width +
|
||||||
|
rightMargin);
|
||||||
|
}
|
||||||
|
|
||||||
UM.I18nCatalog
|
UM.I18nCatalog
|
||||||
{
|
{
|
||||||
id: catalog
|
id: catalog
|
||||||
@ -44,10 +60,9 @@ Rectangle
|
|||||||
|
|
||||||
Row
|
Row
|
||||||
{
|
{
|
||||||
|
id: stagesMenuContainer
|
||||||
anchors.left: logo.right
|
anchors.left: logo.right
|
||||||
anchors.leftMargin: UM.Theme.getSize("topbar_logo_right_margin").width
|
anchors.leftMargin: UM.Theme.getSize("topbar_logo_right_margin").width
|
||||||
anchors.right: machineSelection.left
|
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
|
||||||
spacing: UM.Theme.getSize("default_margin").width
|
spacing: UM.Theme.getSize("default_margin").width
|
||||||
|
|
||||||
// The topbar is dynamically filled with all available stages
|
// The topbar is dynamically filled with all available stages
|
||||||
@ -76,71 +91,6 @@ Rectangle
|
|||||||
ExclusiveGroup { id: topbarMenuGroup }
|
ExclusiveGroup { id: topbarMenuGroup }
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolButton
|
|
||||||
{
|
|
||||||
id: machineSelection
|
|
||||||
text: Cura.MachineManager.activeMachineName
|
|
||||||
|
|
||||||
width: UM.Theme.getSize("sidebar").width
|
|
||||||
height: UM.Theme.getSize("sidebar_header").height
|
|
||||||
tooltip: Cura.MachineManager.activeMachineName
|
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.right: parent.right
|
|
||||||
style: ButtonStyle
|
|
||||||
{
|
|
||||||
background: Rectangle
|
|
||||||
{
|
|
||||||
color:
|
|
||||||
{
|
|
||||||
if(control.pressed)
|
|
||||||
{
|
|
||||||
return UM.Theme.getColor("sidebar_header_active");
|
|
||||||
}
|
|
||||||
else if(control.hovered)
|
|
||||||
{
|
|
||||||
return UM.Theme.getColor("sidebar_header_hover");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return UM.Theme.getColor("sidebar_header_bar");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on color { ColorAnimation { duration: 50; } }
|
|
||||||
|
|
||||||
UM.RecolorImage
|
|
||||||
{
|
|
||||||
id: downArrow
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
|
||||||
width: UM.Theme.getSize("standard_arrow").width
|
|
||||||
height: UM.Theme.getSize("standard_arrow").height
|
|
||||||
sourceSize.width: width
|
|
||||||
sourceSize.height: width
|
|
||||||
color: UM.Theme.getColor("text_emphasis")
|
|
||||||
source: UM.Theme.getIcon("arrow_bottom")
|
|
||||||
}
|
|
||||||
Label
|
|
||||||
{
|
|
||||||
id: sidebarComboBoxLabel
|
|
||||||
color: UM.Theme.getColor("sidebar_header_text_active")
|
|
||||||
text: control.text;
|
|
||||||
elide: Text.ElideRight;
|
|
||||||
anchors.left: parent.left;
|
|
||||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width * 2
|
|
||||||
anchors.right: downArrow.left;
|
|
||||||
anchors.rightMargin: control.rightMargin;
|
|
||||||
anchors.verticalCenter: parent.verticalCenter;
|
|
||||||
font: UM.Theme.getFont("large")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
label: Label {}
|
|
||||||
}
|
|
||||||
|
|
||||||
menu: PrinterMenu { }
|
|
||||||
}
|
|
||||||
|
|
||||||
// View orientation Item
|
// View orientation Item
|
||||||
Row
|
Row
|
||||||
{
|
{
|
||||||
@ -152,8 +102,8 @@ Rectangle
|
|||||||
anchors
|
anchors
|
||||||
{
|
{
|
||||||
verticalCenter: base.verticalCenter
|
verticalCenter: base.verticalCenter
|
||||||
right: viewModeButton.right
|
right: viewModeButton.left
|
||||||
rightMargin: UM.Theme.getSize("default_margin").width + viewModeButton.width
|
rightMargin: UM.Theme.getSize("default_margin").width
|
||||||
}
|
}
|
||||||
|
|
||||||
// #1 3d view
|
// #1 3d view
|
||||||
@ -165,7 +115,7 @@ Rectangle
|
|||||||
onClicked:{
|
onClicked:{
|
||||||
UM.Controller.rotateView("3d", 0);
|
UM.Controller.rotateView("3d", 0);
|
||||||
}
|
}
|
||||||
visible: base.width > 1100
|
visible: base.width - allItemsWidth - 4 * this.width > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #2 Front view
|
// #2 Front view
|
||||||
@ -177,7 +127,7 @@ Rectangle
|
|||||||
onClicked:{
|
onClicked:{
|
||||||
UM.Controller.rotateView("home", 0);
|
UM.Controller.rotateView("home", 0);
|
||||||
}
|
}
|
||||||
visible: base.width > 1130
|
visible: base.width - allItemsWidth - 3 * this.width > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #3 Top view
|
// #3 Top view
|
||||||
@ -189,7 +139,7 @@ Rectangle
|
|||||||
onClicked:{
|
onClicked:{
|
||||||
UM.Controller.rotateView("y", 90);
|
UM.Controller.rotateView("y", 90);
|
||||||
}
|
}
|
||||||
visible: base.width > 1160
|
visible: base.width - allItemsWidth - 2 * this.width > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #4 Left view
|
// #4 Left view
|
||||||
@ -201,7 +151,7 @@ Rectangle
|
|||||||
onClicked:{
|
onClicked:{
|
||||||
UM.Controller.rotateView("x", 90);
|
UM.Controller.rotateView("x", 90);
|
||||||
}
|
}
|
||||||
visible: base.width > 1190
|
visible: base.width - allItemsWidth - 1 * this.width > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #5 Left view
|
// #5 Left view
|
||||||
@ -213,7 +163,7 @@ Rectangle
|
|||||||
onClicked:{
|
onClicked:{
|
||||||
UM.Controller.rotateView("x", -90);
|
UM.Controller.rotateView("x", -90);
|
||||||
}
|
}
|
||||||
visible: base.width > 1210
|
visible: base.width - allItemsWidth > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +174,7 @@ Rectangle
|
|||||||
anchors {
|
anchors {
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
right: parent.right
|
right: parent.right
|
||||||
rightMargin: UM.Theme.getSize("sidebar").width + UM.Theme.getSize("default_margin").width
|
rightMargin: rightMargin
|
||||||
}
|
}
|
||||||
|
|
||||||
style: UM.Theme.styles.combobox
|
style: UM.Theme.styles.combobox
|
||||||
@ -284,4 +234,16 @@ Rectangle
|
|||||||
source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : "";
|
source: UM.ActiveView.valid ? UM.ActiveView.activeViewPanel : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expand or collapse sidebar
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: Cura.Actions.expandSidebar
|
||||||
|
onTriggered: updateMarginsAndSizes()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted:
|
||||||
|
{
|
||||||
|
updateMarginsAndSizes();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
[general]
|
||||||
|
version = 2
|
||||||
|
name = Fine
|
||||||
|
definition = ultimaker3
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
type = quality
|
||||||
|
quality_type = normal
|
||||||
|
material = generic_bam_ultimaker3_AA_0.4
|
||||||
|
weight = 0
|
||||||
|
setting_version = 4
|
||||||
|
|
||||||
|
[values]
|
||||||
|
cool_fan_full_at_height = =layer_height_0 + 2 * layer_height
|
||||||
|
cool_fan_speed_max = =cool_fan_speed
|
||||||
|
cool_min_speed = 7
|
||||||
|
machine_nozzle_cool_down_speed = 0.75
|
||||||
|
machine_nozzle_heat_up_speed = 1.6
|
||||||
|
material_print_temperature = =default_material_print_temperature - 10
|
||||||
|
prime_tower_enable = =min(extruderValues('material_surface_energy')) < 100
|
||||||
|
skin_overlap = 10
|
||||||
|
speed_layer_0 = 20
|
||||||
|
support_interface_enable = True
|
||||||
|
support_interface_density = =min(extruderValues('material_surface_energy'))
|
||||||
|
support_interface_pattern = ='lines' if support_interface_density < 100 else 'concentric'
|
||||||
|
support_top_distance = =math.ceil(min(extruderValues('material_adhesion_tendency')) / 1) * layer_height
|
||||||
|
support_bottom_distance = =math.ceil(min(extruderValues('material_adhesion_tendency')) / 2) * layer_height
|
||||||
|
support_angle = 45
|
||||||
|
support_join_distance = 5
|
||||||
|
support_offset = 2
|
||||||
|
support_pattern = triangles
|
||||||
|
support_infill_rate = 10
|
||||||
|
top_bottom_thickness = 1
|
||||||
|
wall_thickness = 1
|
@ -6,7 +6,9 @@ import pytest #This module contains unit tests.
|
|||||||
import shutil #To copy files to make a temporary file.
|
import shutil #To copy files to make a temporary file.
|
||||||
import unittest.mock #To mock and monkeypatch stuff.
|
import unittest.mock #To mock and monkeypatch stuff.
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
import copy
|
||||||
|
|
||||||
|
import cura.CuraApplication
|
||||||
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry #The class we're testing.
|
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry #The class we're testing.
|
||||||
from cura.Settings.ExtruderStack import ExtruderStack #Testing for returning the correct types of stacks.
|
from cura.Settings.ExtruderStack import ExtruderStack #Testing for returning the correct types of stacks.
|
||||||
from cura.Settings.GlobalStack import GlobalStack #Testing for returning the correct types of stacks.
|
from cura.Settings.GlobalStack import GlobalStack #Testing for returning the correct types of stacks.
|
||||||
@ -15,6 +17,32 @@ import UM.Settings.InstanceContainer #Creating instance containers to register.
|
|||||||
import UM.Settings.ContainerRegistry #Making empty container stacks.
|
import UM.Settings.ContainerRegistry #Making empty container stacks.
|
||||||
import UM.Settings.ContainerStack #Setting the container registry here properly.
|
import UM.Settings.ContainerStack #Setting the container registry here properly.
|
||||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||||
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
|
|
||||||
|
def creteEmptyContainers():
|
||||||
|
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
||||||
|
empty_variant_container = copy.deepcopy(empty_container)
|
||||||
|
empty_variant_container.setMetaDataEntry("id", "empty_variant")
|
||||||
|
empty_variant_container.addMetaDataEntry("type", "variant")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_variant_container)
|
||||||
|
|
||||||
|
empty_material_container = copy.deepcopy(empty_container)
|
||||||
|
empty_material_container.setMetaDataEntry("id", "empty_material")
|
||||||
|
empty_material_container.addMetaDataEntry("type", "material")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_material_container)
|
||||||
|
|
||||||
|
empty_quality_container = copy.deepcopy(empty_container)
|
||||||
|
empty_quality_container.setMetaDataEntry("id", "empty_quality")
|
||||||
|
empty_quality_container.setName("Not Supported")
|
||||||
|
empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
||||||
|
empty_quality_container.addMetaDataEntry("type", "quality")
|
||||||
|
empty_quality_container.addMetaDataEntry("supported", False)
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
||||||
|
|
||||||
|
empty_quality_changes_container = copy.deepcopy(empty_container)
|
||||||
|
empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
|
||||||
|
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
||||||
|
|
||||||
## Gives a fresh CuraContainerRegistry instance.
|
## Gives a fresh CuraContainerRegistry instance.
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
@ -37,6 +65,7 @@ def teardown():
|
|||||||
|
|
||||||
## Tests whether addContainer properly converts to ExtruderStack.
|
## Tests whether addContainer properly converts to ExtruderStack.
|
||||||
def test_addContainerExtruderStack(container_registry, definition_container):
|
def test_addContainerExtruderStack(container_registry, definition_container):
|
||||||
|
creteEmptyContainers()
|
||||||
container_registry.addContainer(definition_container)
|
container_registry.addContainer(definition_container)
|
||||||
|
|
||||||
container_stack = UM.Settings.ContainerStack.ContainerStack(stack_id = "Test Container Stack") #A container we're going to convert.
|
container_stack = UM.Settings.ContainerStack.ContainerStack(stack_id = "Test Container Stack") #A container we're going to convert.
|
||||||
@ -113,36 +142,36 @@ def test_addContainerBadSettingVersion(container_registry, definition_container)
|
|||||||
mock_super_add_container.assert_not_called() #Should not get passed on to UM.Settings.ContainerRegistry.addContainer, because the setting_version doesn't match its definition!
|
mock_super_add_container.assert_not_called() #Should not get passed on to UM.Settings.ContainerRegistry.addContainer, because the setting_version doesn't match its definition!
|
||||||
|
|
||||||
## Tests whether loading gives objects of the correct type.
|
## Tests whether loading gives objects of the correct type.
|
||||||
@pytest.mark.parametrize("filename, output_class", [
|
# @pytest.mark.parametrize("filename, output_class", [
|
||||||
("ExtruderLegacy.stack.cfg", ExtruderStack),
|
# ("ExtruderLegacy.stack.cfg", ExtruderStack),
|
||||||
("MachineLegacy.stack.cfg", GlobalStack),
|
# ("MachineLegacy.stack.cfg", GlobalStack),
|
||||||
("Left.extruder.cfg", ExtruderStack),
|
# ("Left.extruder.cfg", ExtruderStack),
|
||||||
("Global.global.cfg", GlobalStack),
|
# ("Global.global.cfg", GlobalStack),
|
||||||
("Global.stack.cfg", GlobalStack)
|
# ("Global.stack.cfg", GlobalStack)
|
||||||
])
|
# ])
|
||||||
def test_loadTypes(filename, output_class, container_registry):
|
# def test_loadTypes(filename, output_class, container_registry):
|
||||||
#Mock some dependencies.
|
# #Mock some dependencies.
|
||||||
Resources.getAllResourcesOfType = unittest.mock.MagicMock(return_value = [os.path.join(os.path.dirname(os.path.abspath(__file__)), "stacks", filename)]) #Return just this tested file.
|
# Resources.getAllResourcesOfType = unittest.mock.MagicMock(return_value = [os.path.join(os.path.dirname(os.path.abspath(__file__)), "stacks", filename)]) #Return just this tested file.
|
||||||
|
#
|
||||||
def findContainers(container_type = 0, id = None):
|
# def findContainers(container_type = 0, id = None):
|
||||||
if id == "some_instance":
|
# if id == "some_instance":
|
||||||
return [UM.Settings.ContainerRegistry._EmptyInstanceContainer(id)]
|
# return [UM.Settings.ContainerRegistry._EmptyInstanceContainer(id)]
|
||||||
elif id == "some_definition":
|
# elif id == "some_definition":
|
||||||
return [DefinitionContainer(container_id = id)]
|
# return [DefinitionContainer(container_id = id)]
|
||||||
else:
|
# else:
|
||||||
return []
|
# return []
|
||||||
|
#
|
||||||
container_registry.findContainers = findContainers
|
# container_registry.findContainers = findContainers
|
||||||
|
#
|
||||||
with unittest.mock.patch("cura.Settings.GlobalStack.GlobalStack.findContainer"):
|
# with unittest.mock.patch("cura.Settings.GlobalStack.GlobalStack.findContainer"):
|
||||||
with unittest.mock.patch("os.remove"):
|
# with unittest.mock.patch("os.remove"):
|
||||||
container_registry.load()
|
# container_registry.load()
|
||||||
|
#
|
||||||
#Check whether the resulting type was correct.
|
# #Check whether the resulting type was correct.
|
||||||
stack_id = filename.split(".")[0]
|
# stack_id = filename.split(".")[0]
|
||||||
for container_id, container in container_registry._containers.items(): #Stupid ContainerRegistry class doesn't expose any way of getting at this except by prodding the privates.
|
# for container_id, container in container_registry._containers.items(): #Stupid ContainerRegistry class doesn't expose any way of getting at this except by prodding the privates.
|
||||||
if container_id == stack_id: #This is the one we're testing.
|
# if container_id == stack_id: #This is the one we're testing.
|
||||||
assert type(container) == output_class
|
# assert type(container) == output_class
|
||||||
break
|
# break
|
||||||
else:
|
# else:
|
||||||
assert False #Container stack with specified ID was not loaded.
|
# assert False #Container stack with specified ID was not loaded.
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
import pytest #This module contains automated tests.
|
import pytest #This module contains automated tests.
|
||||||
import unittest.mock #For the mocking and monkeypatching functionality.
|
import unittest.mock #For the mocking and monkeypatching functionality.
|
||||||
|
import copy
|
||||||
|
|
||||||
|
import cura.CuraApplication
|
||||||
import UM.Settings.ContainerRegistry #To create empty instance containers.
|
import UM.Settings.ContainerRegistry #To create empty instance containers.
|
||||||
import UM.Settings.ContainerStack #To set the container registry the container stacks use.
|
import UM.Settings.ContainerStack #To set the container registry the container stacks use.
|
||||||
from UM.Settings.DefinitionContainer import DefinitionContainer #To check against the class of DefinitionContainer.
|
from UM.Settings.DefinitionContainer import DefinitionContainer #To check against the class of DefinitionContainer.
|
||||||
@ -12,6 +14,7 @@ import cura.Settings.ExtruderStack #The module we're testing.
|
|||||||
from cura.Settings.Exceptions import InvalidContainerError, InvalidOperationError #To check whether the correct exceptions are raised.
|
from cura.Settings.Exceptions import InvalidContainerError, InvalidOperationError #To check whether the correct exceptions are raised.
|
||||||
|
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
|
|
||||||
## Fake container registry that always provides all containers you ask of.
|
## Fake container registry that always provides all containers you ask of.
|
||||||
@pytest.yield_fixture()
|
@pytest.yield_fixture()
|
||||||
@ -32,6 +35,7 @@ def container_registry():
|
|||||||
## An empty extruder stack to test with.
|
## An empty extruder stack to test with.
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def extruder_stack() -> cura.Settings.ExtruderStack.ExtruderStack:
|
def extruder_stack() -> cura.Settings.ExtruderStack.ExtruderStack:
|
||||||
|
creteEmptyContainers()
|
||||||
return cura.Settings.ExtruderStack.ExtruderStack("TestStack")
|
return cura.Settings.ExtruderStack.ExtruderStack("TestStack")
|
||||||
|
|
||||||
## Gets an instance container with a specified container type.
|
## Gets an instance container with a specified container type.
|
||||||
@ -43,6 +47,31 @@ def getInstanceContainer(container_type) -> InstanceContainer:
|
|||||||
container.addMetaDataEntry("type", container_type)
|
container.addMetaDataEntry("type", container_type)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
|
def creteEmptyContainers():
|
||||||
|
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
||||||
|
empty_variant_container = copy.deepcopy(empty_container)
|
||||||
|
empty_variant_container.setMetaDataEntry("id", "empty_variant")
|
||||||
|
empty_variant_container.addMetaDataEntry("type", "variant")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_variant_container)
|
||||||
|
|
||||||
|
empty_material_container = copy.deepcopy(empty_container)
|
||||||
|
empty_material_container.setMetaDataEntry("id", "empty_material")
|
||||||
|
empty_material_container.addMetaDataEntry("type", "material")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_material_container)
|
||||||
|
|
||||||
|
empty_quality_container = copy.deepcopy(empty_container)
|
||||||
|
empty_quality_container.setMetaDataEntry("id", "empty_quality")
|
||||||
|
empty_quality_container.setName("Not Supported")
|
||||||
|
empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
||||||
|
empty_quality_container.addMetaDataEntry("type", "quality")
|
||||||
|
empty_quality_container.addMetaDataEntry("supported", False)
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
||||||
|
|
||||||
|
empty_quality_changes_container = copy.deepcopy(empty_container)
|
||||||
|
empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
|
||||||
|
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
||||||
|
|
||||||
class DefinitionContainerSubClass(DefinitionContainer):
|
class DefinitionContainerSubClass(DefinitionContainer):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(container_id = "SubDefinitionContainer")
|
super().__init__(container_id = "SubDefinitionContainer")
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
import pytest #This module contains unit tests.
|
import pytest #This module contains unit tests.
|
||||||
import unittest.mock #To monkeypatch some mocks in place of dependencies.
|
import unittest.mock #To monkeypatch some mocks in place of dependencies.
|
||||||
|
import copy
|
||||||
|
|
||||||
|
import cura.CuraApplication
|
||||||
import cura.Settings.GlobalStack #The module we're testing.
|
import cura.Settings.GlobalStack #The module we're testing.
|
||||||
import cura.Settings.CuraContainerStack #To get the list of container types.
|
import cura.Settings.CuraContainerStack #To get the list of container types.
|
||||||
from cura.Settings.Exceptions import TooManyExtrudersError, InvalidContainerError, InvalidOperationError #To test raising these errors.
|
from cura.Settings.Exceptions import TooManyExtrudersError, InvalidContainerError, InvalidOperationError #To test raising these errors.
|
||||||
@ -13,6 +15,7 @@ from UM.Settings.SettingInstance import InstanceState
|
|||||||
import UM.Settings.ContainerRegistry
|
import UM.Settings.ContainerRegistry
|
||||||
import UM.Settings.ContainerStack
|
import UM.Settings.ContainerStack
|
||||||
import UM.Settings.SettingDefinition #To add settings to the definition.
|
import UM.Settings.SettingDefinition #To add settings to the definition.
|
||||||
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
|
|
||||||
## Fake container registry that always provides all containers you ask of.
|
## Fake container registry that always provides all containers you ask of.
|
||||||
@pytest.yield_fixture()
|
@pytest.yield_fixture()
|
||||||
@ -33,6 +36,7 @@ def container_registry():
|
|||||||
#An empty global stack to test with.
|
#An empty global stack to test with.
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def global_stack() -> cura.Settings.GlobalStack.GlobalStack:
|
def global_stack() -> cura.Settings.GlobalStack.GlobalStack:
|
||||||
|
creteEmptyContainers()
|
||||||
return cura.Settings.GlobalStack.GlobalStack("TestStack")
|
return cura.Settings.GlobalStack.GlobalStack("TestStack")
|
||||||
|
|
||||||
## Gets an instance container with a specified container type.
|
## Gets an instance container with a specified container type.
|
||||||
@ -44,6 +48,31 @@ def getInstanceContainer(container_type) -> InstanceContainer:
|
|||||||
container.addMetaDataEntry("type", container_type)
|
container.addMetaDataEntry("type", container_type)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
|
def creteEmptyContainers():
|
||||||
|
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
||||||
|
empty_variant_container = copy.deepcopy(empty_container)
|
||||||
|
empty_variant_container.setMetaDataEntry("id", "empty_variant")
|
||||||
|
empty_variant_container.addMetaDataEntry("type", "variant")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_variant_container)
|
||||||
|
|
||||||
|
empty_material_container = copy.deepcopy(empty_container)
|
||||||
|
empty_material_container.setMetaDataEntry("id", "empty_material")
|
||||||
|
empty_material_container.addMetaDataEntry("type", "material")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_material_container)
|
||||||
|
|
||||||
|
empty_quality_container = copy.deepcopy(empty_container)
|
||||||
|
empty_quality_container.setMetaDataEntry("id", "empty_quality")
|
||||||
|
empty_quality_container.setName("Not Supported")
|
||||||
|
empty_quality_container.addMetaDataEntry("quality_type", "not_supported")
|
||||||
|
empty_quality_container.addMetaDataEntry("type", "quality")
|
||||||
|
empty_quality_container.addMetaDataEntry("supported", False)
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_quality_container)
|
||||||
|
|
||||||
|
empty_quality_changes_container = copy.deepcopy(empty_container)
|
||||||
|
empty_quality_changes_container.setMetaDataEntry("id", "empty_quality_changes")
|
||||||
|
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
||||||
|
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
||||||
|
|
||||||
class DefinitionContainerSubClass(DefinitionContainer):
|
class DefinitionContainerSubClass(DefinitionContainer):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(container_id = "SubDefinitionContainer")
|
super().__init__(container_id = "SubDefinitionContainer")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user