mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 04:36:01 +08:00
Merge branch 'master' into feature_custom_gcode_commands
This commit is contained in:
commit
5ee30e0c99
@ -136,6 +136,7 @@ class BuildVolume(SceneNode):
|
|||||||
if active_extruder_changed is not None:
|
if active_extruder_changed is not None:
|
||||||
node.callDecoration("getActiveExtruderChangedSignal").disconnect(self._updateDisallowedAreasAndRebuild)
|
node.callDecoration("getActiveExtruderChangedSignal").disconnect(self._updateDisallowedAreasAndRebuild)
|
||||||
node.decoratorsChanged.disconnect(self._updateNodeListeners)
|
node.decoratorsChanged.disconnect(self._updateNodeListeners)
|
||||||
|
self._updateDisallowedAreasAndRebuild() # make sure we didn't miss anything before we updated the node listeners
|
||||||
|
|
||||||
self._scene_objects = new_scene_objects
|
self._scene_objects = new_scene_objects
|
||||||
self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered.
|
self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered.
|
||||||
@ -150,7 +151,6 @@ class BuildVolume(SceneNode):
|
|||||||
active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal")
|
active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal")
|
||||||
if active_extruder_changed is not None:
|
if active_extruder_changed is not None:
|
||||||
active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild)
|
active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild)
|
||||||
self._updateDisallowedAreasAndRebuild()
|
|
||||||
|
|
||||||
def setWidth(self, width):
|
def setWidth(self, width):
|
||||||
if width is not None:
|
if width is not None:
|
||||||
|
@ -109,10 +109,6 @@ class CuraActions(QObject):
|
|||||||
|
|
||||||
nodes_to_change = []
|
nodes_to_change = []
|
||||||
for node in Selection.getAllSelectedObjects():
|
for node in Selection.getAllSelectedObjects():
|
||||||
# Do not change any nodes that already have the right extruder set.
|
|
||||||
if node.callDecoration("getActiveExtruder") == extruder_id:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# If the node is a group, apply the active extruder to all children of the group.
|
# If the node is a group, apply the active extruder to all children of the group.
|
||||||
if node.callDecoration("isGroup"):
|
if node.callDecoration("isGroup"):
|
||||||
for grouped_node in BreadthFirstIterator(node):
|
for grouped_node in BreadthFirstIterator(node):
|
||||||
@ -125,6 +121,10 @@ class CuraActions(QObject):
|
|||||||
nodes_to_change.append(grouped_node)
|
nodes_to_change.append(grouped_node)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Do not change any nodes that already have the right extruder set.
|
||||||
|
if node.callDecoration("getActiveExtruder") == extruder_id:
|
||||||
|
continue
|
||||||
|
|
||||||
nodes_to_change.append(node)
|
nodes_to_change.append(node)
|
||||||
|
|
||||||
if not nodes_to_change:
|
if not nodes_to_change:
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
#Type hinting.
|
from PyQt5.QtCore import QObject, QTimer
|
||||||
from typing import Dict
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject
|
|
||||||
from PyQt5.QtNetwork import QLocalServer
|
from PyQt5.QtNetwork import QLocalServer
|
||||||
from PyQt5.QtNetwork import QLocalSocket
|
from PyQt5.QtNetwork import QLocalSocket
|
||||||
|
|
||||||
@ -68,6 +65,8 @@ from cura.Machines.Models.QualityManagementModel import QualityManagementModel
|
|||||||
from cura.Machines.Models.QualitySettingsModel import QualitySettingsModel
|
from cura.Machines.Models.QualitySettingsModel import QualitySettingsModel
|
||||||
from cura.Machines.Models.MachineManagementModel import MachineManagementModel
|
from cura.Machines.Models.MachineManagementModel import MachineManagementModel
|
||||||
|
|
||||||
|
from cura.Machines.Models.SettingVisibilityPresetsModel import SettingVisibilityPresetsModel
|
||||||
|
|
||||||
from cura.Machines.MachineErrorChecker import MachineErrorChecker
|
from cura.Machines.MachineErrorChecker import MachineErrorChecker
|
||||||
|
|
||||||
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
||||||
@ -100,7 +99,6 @@ from PyQt5.QtGui import QColor, QIcon
|
|||||||
from PyQt5.QtWidgets import QMessageBox
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
|
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
|
||||||
|
|
||||||
from configparser import ConfigParser
|
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
import numpy
|
import numpy
|
||||||
@ -140,6 +138,7 @@ class CuraApplication(QtApplication):
|
|||||||
MachineStack = Resources.UserType + 7
|
MachineStack = Resources.UserType + 7
|
||||||
ExtruderStack = Resources.UserType + 8
|
ExtruderStack = Resources.UserType + 8
|
||||||
DefinitionChangesContainer = Resources.UserType + 9
|
DefinitionChangesContainer = Resources.UserType + 9
|
||||||
|
SettingVisibilityPreset = Resources.UserType + 10
|
||||||
|
|
||||||
Q_ENUMS(ResourceTypes)
|
Q_ENUMS(ResourceTypes)
|
||||||
|
|
||||||
@ -187,6 +186,7 @@ class CuraApplication(QtApplication):
|
|||||||
Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders")
|
Resources.addStorageType(self.ResourceTypes.ExtruderStack, "extruders")
|
||||||
Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances")
|
Resources.addStorageType(self.ResourceTypes.MachineStack, "machine_instances")
|
||||||
Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
Resources.addStorageType(self.ResourceTypes.DefinitionChangesContainer, "definition_changes")
|
||||||
|
Resources.addStorageType(self.ResourceTypes.SettingVisibilityPreset, "setting_visibility")
|
||||||
|
|
||||||
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality")
|
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality")
|
||||||
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality_changes")
|
ContainerRegistry.getInstance().addResourceType(self.ResourceTypes.QualityInstanceContainer, "quality_changes")
|
||||||
@ -223,6 +223,7 @@ class CuraApplication(QtApplication):
|
|||||||
self._object_manager = None
|
self._object_manager = None
|
||||||
self._build_plate_model = None
|
self._build_plate_model = None
|
||||||
self._multi_build_plate_model = None
|
self._multi_build_plate_model = None
|
||||||
|
self._setting_visibility_presets_model = None
|
||||||
self._setting_inheritance_manager = None
|
self._setting_inheritance_manager = None
|
||||||
self._simple_mode_settings_manager = None
|
self._simple_mode_settings_manager = None
|
||||||
self._cura_scene_controller = None
|
self._cura_scene_controller = None
|
||||||
@ -283,10 +284,15 @@ class CuraApplication(QtApplication):
|
|||||||
self._preferred_mimetype = ""
|
self._preferred_mimetype = ""
|
||||||
self._i18n_catalog = i18nCatalog("cura")
|
self._i18n_catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity)
|
self._update_platform_activity_timer = QTimer()
|
||||||
|
self._update_platform_activity_timer.setInterval(500)
|
||||||
|
self._update_platform_activity_timer.setSingleShot(True)
|
||||||
|
self._update_platform_activity_timer.timeout.connect(self.updatePlatformActivity)
|
||||||
|
|
||||||
|
self.getController().getScene().sceneChanged.connect(self.updatePlatformActivityDelayed)
|
||||||
self.getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
self.getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
||||||
self.getController().contextMenuRequested.connect(self._onContextMenuRequested)
|
self.getController().contextMenuRequested.connect(self._onContextMenuRequested)
|
||||||
self.getCuraSceneController().activeBuildPlateChanged.connect(self.updatePlatformActivity)
|
self.getCuraSceneController().activeBuildPlateChanged.connect(self.updatePlatformActivityDelayed)
|
||||||
|
|
||||||
Resources.addType(self.ResourceTypes.QmlFiles, "qml")
|
Resources.addType(self.ResourceTypes.QmlFiles, "qml")
|
||||||
Resources.addType(self.ResourceTypes.Firmware, "firmware")
|
Resources.addType(self.ResourceTypes.Firmware, "firmware")
|
||||||
@ -373,20 +379,6 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
preferences.setDefault("local_file/last_used_type", "text/x-gcode")
|
preferences.setDefault("local_file/last_used_type", "text/x-gcode")
|
||||||
|
|
||||||
setting_visibily_preset_names = self.getVisibilitySettingPresetTypes()
|
|
||||||
preferences.setDefault("general/visible_settings_preset", setting_visibily_preset_names)
|
|
||||||
|
|
||||||
preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice")
|
|
||||||
|
|
||||||
default_preset_visibility_group_name = "Basic"
|
|
||||||
if preset_setting_visibility_choice == "" or preset_setting_visibility_choice is None:
|
|
||||||
if preset_setting_visibility_choice not in setting_visibily_preset_names:
|
|
||||||
preset_setting_visibility_choice = default_preset_visibility_group_name
|
|
||||||
|
|
||||||
visible_settings = self.getVisibilitySettingPreset(settings_preset_name = preset_setting_visibility_choice)
|
|
||||||
preferences.setDefault("general/visible_settings", visible_settings)
|
|
||||||
preferences.setDefault("general/preset_setting_visibility_choice", preset_setting_visibility_choice)
|
|
||||||
|
|
||||||
self.applicationShuttingDown.connect(self.saveSettings)
|
self.applicationShuttingDown.connect(self.saveSettings)
|
||||||
self.engineCreatedSignal.connect(self._onEngineCreated)
|
self.engineCreatedSignal.connect(self._onEngineCreated)
|
||||||
|
|
||||||
@ -402,91 +394,6 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
CuraApplication.Created = True
|
CuraApplication.Created = True
|
||||||
|
|
||||||
@pyqtSlot(str, result = str)
|
|
||||||
def getVisibilitySettingPreset(self, settings_preset_name) -> str:
|
|
||||||
result = self._loadPresetSettingVisibilityGroup(settings_preset_name)
|
|
||||||
formatted_preset_settings = self._serializePresetSettingVisibilityData(result)
|
|
||||||
|
|
||||||
return formatted_preset_settings
|
|
||||||
|
|
||||||
## Serialise the given preset setting visibitlity group dictionary into a string which is concatenated by ";"
|
|
||||||
#
|
|
||||||
def _serializePresetSettingVisibilityData(self, settings_data: dict) -> str:
|
|
||||||
result_string = ""
|
|
||||||
|
|
||||||
for key in settings_data:
|
|
||||||
result_string += key + ";"
|
|
||||||
for value in settings_data[key]:
|
|
||||||
result_string += value + ";"
|
|
||||||
|
|
||||||
return result_string
|
|
||||||
|
|
||||||
## Load the preset setting visibility group with the given name
|
|
||||||
#
|
|
||||||
def _loadPresetSettingVisibilityGroup(self, visibility_preset_name) -> Dict[str, str]:
|
|
||||||
preset_dir = Resources.getPath(Resources.PresetSettingVisibilityGroups)
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
right_preset_found = False
|
|
||||||
|
|
||||||
for item in os.listdir(preset_dir):
|
|
||||||
file_path = os.path.join(preset_dir, item)
|
|
||||||
if not os.path.isfile(file_path):
|
|
||||||
continue
|
|
||||||
|
|
||||||
parser = ConfigParser(allow_no_value = True) # accept options without any value,
|
|
||||||
|
|
||||||
try:
|
|
||||||
parser.read([file_path])
|
|
||||||
|
|
||||||
if not parser.has_option("general", "name"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if parser["general"]["name"] == visibility_preset_name:
|
|
||||||
right_preset_found = True
|
|
||||||
for section in parser.sections():
|
|
||||||
if section == 'general':
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
section_settings = []
|
|
||||||
for option in parser[section].keys():
|
|
||||||
section_settings.append(option)
|
|
||||||
|
|
||||||
result[section] = section_settings
|
|
||||||
|
|
||||||
if right_preset_found:
|
|
||||||
break
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
Logger.log("e", "Failed to load setting visibility preset %s: %s", file_path, str(e))
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
## Check visibility setting preset folder and returns available types
|
|
||||||
#
|
|
||||||
def getVisibilitySettingPresetTypes(self):
|
|
||||||
preset_dir = Resources.getPath(Resources.PresetSettingVisibilityGroups)
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
for item in os.listdir(preset_dir):
|
|
||||||
file_path = os.path.join(preset_dir, item)
|
|
||||||
if not os.path.isfile(file_path):
|
|
||||||
continue
|
|
||||||
|
|
||||||
parser = ConfigParser(allow_no_value=True) # accept options without any value,
|
|
||||||
|
|
||||||
try:
|
|
||||||
parser.read([file_path])
|
|
||||||
|
|
||||||
if not parser.has_option("general", "name") and not parser.has_option("general", "weight"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
result[parser["general"]["weight"]] = parser["general"]["name"]
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
Logger.log("e", "Failed to load setting preset %s: %s", file_path, str(e))
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _onEngineCreated(self):
|
def _onEngineCreated(self):
|
||||||
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
||||||
@ -774,6 +681,11 @@ class CuraApplication(QtApplication):
|
|||||||
self._print_information = PrintInformation.PrintInformation()
|
self._print_information = PrintInformation.PrintInformation()
|
||||||
self._cura_actions = CuraActions.CuraActions(self)
|
self._cura_actions = CuraActions.CuraActions(self)
|
||||||
|
|
||||||
|
# Initialize setting visibility presets model
|
||||||
|
self._setting_visibility_presets_model = SettingVisibilityPresetsModel(self)
|
||||||
|
default_visibility_profile = self._setting_visibility_presets_model.getItem(0)
|
||||||
|
Preferences.getInstance().setDefault("general/visible_settings", ";".join(default_visibility_profile["settings"]))
|
||||||
|
|
||||||
# Detect in which mode to run and execute that mode
|
# Detect in which mode to run and execute that mode
|
||||||
if self.getCommandLineOption("headless", False):
|
if self.getCommandLineOption("headless", False):
|
||||||
self.runWithoutGUI()
|
self.runWithoutGUI()
|
||||||
@ -856,6 +768,10 @@ class CuraApplication(QtApplication):
|
|||||||
def hasGui(self):
|
def hasGui(self):
|
||||||
return self._use_gui
|
return self._use_gui
|
||||||
|
|
||||||
|
@pyqtSlot(result = QObject)
|
||||||
|
def getSettingVisibilityPresetsModel(self, *args) -> SettingVisibilityPresetsModel:
|
||||||
|
return self._setting_visibility_presets_model
|
||||||
|
|
||||||
def getMachineErrorChecker(self, *args) -> MachineErrorChecker:
|
def getMachineErrorChecker(self, *args) -> MachineErrorChecker:
|
||||||
return self._machine_error_checker
|
return self._machine_error_checker
|
||||||
|
|
||||||
@ -982,6 +898,7 @@ class CuraApplication(QtApplication):
|
|||||||
qmlRegisterType(NozzleModel, "Cura", 1, 0, "NozzleModel")
|
qmlRegisterType(NozzleModel, "Cura", 1, 0, "NozzleModel")
|
||||||
|
|
||||||
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
|
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
|
||||||
|
qmlRegisterType(SettingVisibilityPresetsModel, "Cura", 1, 0, "SettingVisibilityPresetsModel")
|
||||||
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
|
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
|
||||||
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
|
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
|
||||||
qmlRegisterType(UserChangesModel, "Cura", 1, 0, "UserChangesModel")
|
qmlRegisterType(UserChangesModel, "Cura", 1, 0, "UserChangesModel")
|
||||||
@ -1061,6 +978,10 @@ class CuraApplication(QtApplication):
|
|||||||
def getSceneBoundingBoxString(self):
|
def getSceneBoundingBoxString(self):
|
||||||
return self._i18n_catalog.i18nc("@info 'width', 'depth' and 'height' are variable names that must NOT be translated; just translate the format of ##x##x## mm.", "%(width).1f x %(depth).1f x %(height).1f mm") % {'width' : self._scene_bounding_box.width.item(), 'depth': self._scene_bounding_box.depth.item(), 'height' : self._scene_bounding_box.height.item()}
|
return self._i18n_catalog.i18nc("@info 'width', 'depth' and 'height' are variable names that must NOT be translated; just translate the format of ##x##x## mm.", "%(width).1f x %(depth).1f x %(height).1f mm") % {'width' : self._scene_bounding_box.width.item(), 'depth': self._scene_bounding_box.depth.item(), 'height' : self._scene_bounding_box.height.item()}
|
||||||
|
|
||||||
|
def updatePlatformActivityDelayed(self, node = None):
|
||||||
|
if node is not None and node.getMeshData() is not None:
|
||||||
|
self._update_platform_activity_timer.start()
|
||||||
|
|
||||||
## Update scene bounding box for current build plate
|
## Update scene bounding box for current build plate
|
||||||
def updatePlatformActivity(self, node = None):
|
def updatePlatformActivity(self, node = None):
|
||||||
count = 0
|
count = 0
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt, pyqtSignal
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
from UM.Settings.ContainerStack import ContainerStack
|
from UM.Settings.ContainerStack import ContainerStack
|
||||||
@ -11,6 +11,7 @@ from UM.Settings.ContainerStack import ContainerStack
|
|||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# This the QML model for the quality management page.
|
# This the QML model for the quality management page.
|
||||||
#
|
#
|
||||||
@ -39,7 +40,7 @@ class MachineManagementModel(ListModel):
|
|||||||
## Handler for container added/removed events from registry
|
## Handler for container added/removed events from registry
|
||||||
def _onContainerChanged(self, container):
|
def _onContainerChanged(self, container):
|
||||||
# We only need to update when the added / removed container is a stack.
|
# We only need to update when the added / removed container is a stack.
|
||||||
if isinstance(container, ContainerStack):
|
if isinstance(container, ContainerStack) and container.getMetaDataEntry("type") == "machine":
|
||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
## Private convenience function to reset & repopulate the model.
|
## Private convenience function to reset & repopulate the model.
|
||||||
@ -47,7 +48,9 @@ class MachineManagementModel(ListModel):
|
|||||||
items = []
|
items = []
|
||||||
|
|
||||||
# Get first the network enabled printers
|
# Get first the network enabled printers
|
||||||
network_filter_printers = {"type": "machine", "um_network_key": "*", "hidden": "False"}
|
network_filter_printers = {"type": "machine",
|
||||||
|
"um_network_key": "*",
|
||||||
|
"hidden": "False"}
|
||||||
self._network_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**network_filter_printers)
|
self._network_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**network_filter_printers)
|
||||||
self._network_container_stacks.sort(key = lambda i: i.getMetaDataEntry("connect_group_name"))
|
self._network_container_stacks.sort(key = lambda i: i.getMetaDataEntry("connect_group_name"))
|
||||||
|
|
||||||
@ -61,7 +64,7 @@ class MachineManagementModel(ListModel):
|
|||||||
"metadata": metadata,
|
"metadata": metadata,
|
||||||
"group": catalog.i18nc("@info:title", "Network enabled printers")})
|
"group": catalog.i18nc("@info:title", "Network enabled printers")})
|
||||||
|
|
||||||
# Get now the local printes
|
# Get now the local printers
|
||||||
local_filter_printers = {"type": "machine", "um_network_key": None}
|
local_filter_printers = {"type": "machine", "um_network_key": None}
|
||||||
self._local_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**local_filter_printers)
|
self._local_container_stacks = ContainerRegistry.getInstance().findContainerStacks(**local_filter_printers)
|
||||||
self._local_container_stacks.sort(key = lambda i: i.getName())
|
self._local_container_stacks.sort(key = lambda i: i.getName())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, pyqtProperty
|
from PyQt5.QtCore import QTimer, pyqtSignal, pyqtProperty
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Scene.Selection import Selection
|
from UM.Scene.Selection import Selection
|
||||||
@ -21,8 +21,13 @@ class MultiBuildPlateModel(ListModel):
|
|||||||
def __init__(self, parent = None):
|
def __init__(self, parent = None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self._update_timer = QTimer()
|
||||||
|
self._update_timer.setInterval(100)
|
||||||
|
self._update_timer.setSingleShot(True)
|
||||||
|
self._update_timer.timeout.connect(self._updateSelectedObjectBuildPlateNumbers)
|
||||||
|
|
||||||
self._application = Application.getInstance()
|
self._application = Application.getInstance()
|
||||||
self._application.getController().getScene().sceneChanged.connect(self._updateSelectedObjectBuildPlateNumbers)
|
self._application.getController().getScene().sceneChanged.connect(self._updateSelectedObjectBuildPlateNumbersDelayed)
|
||||||
Selection.selectionChanged.connect(self._updateSelectedObjectBuildPlateNumbers)
|
Selection.selectionChanged.connect(self._updateSelectedObjectBuildPlateNumbers)
|
||||||
|
|
||||||
self._max_build_plate = 1 # default
|
self._max_build_plate = 1 # default
|
||||||
@ -45,6 +50,9 @@ class MultiBuildPlateModel(ListModel):
|
|||||||
def activeBuildPlate(self):
|
def activeBuildPlate(self):
|
||||||
return self._active_build_plate
|
return self._active_build_plate
|
||||||
|
|
||||||
|
def _updateSelectedObjectBuildPlateNumbersDelayed(self, *args):
|
||||||
|
self._update_timer.start()
|
||||||
|
|
||||||
def _updateSelectedObjectBuildPlateNumbers(self, *args):
|
def _updateSelectedObjectBuildPlateNumbers(self, *args):
|
||||||
result = set()
|
result = set()
|
||||||
for node in Selection.getAllSelectedObjects():
|
for node in Selection.getAllSelectedObjects():
|
||||||
|
@ -87,9 +87,11 @@ class QualitySettingsModel(ListModel):
|
|||||||
if self._selected_position == self.GLOBAL_STACK_POSITION:
|
if self._selected_position == self.GLOBAL_STACK_POSITION:
|
||||||
quality_node = quality_group.node_for_global
|
quality_node = quality_group.node_for_global
|
||||||
else:
|
else:
|
||||||
quality_node = quality_group.nodes_for_extruders.get(self._selected_position)
|
quality_node = quality_group.nodes_for_extruders.get(str(self._selected_position))
|
||||||
settings_keys = quality_group.getAllKeys()
|
settings_keys = quality_group.getAllKeys()
|
||||||
quality_containers = [quality_node.getContainer()]
|
quality_containers = []
|
||||||
|
if quality_node is not None:
|
||||||
|
quality_containers.append(quality_node.getContainer())
|
||||||
|
|
||||||
# Here, if the user has selected a quality changes, then "quality_changes_group" will not be None, and we fetch
|
# Here, if the user has selected a quality changes, then "quality_changes_group" will not be None, and we fetch
|
||||||
# the settings in that quality_changes_group.
|
# the settings in that quality_changes_group.
|
||||||
@ -97,7 +99,7 @@ class QualitySettingsModel(ListModel):
|
|||||||
if self._selected_position == self.GLOBAL_STACK_POSITION:
|
if self._selected_position == self.GLOBAL_STACK_POSITION:
|
||||||
quality_changes_node = quality_changes_group.node_for_global
|
quality_changes_node = quality_changes_group.node_for_global
|
||||||
else:
|
else:
|
||||||
quality_changes_node = quality_changes_group.nodes_for_extruders.get(self._selected_position)
|
quality_changes_node = quality_changes_group.nodes_for_extruders.get(str(self._selected_position))
|
||||||
if quality_changes_node is not None: # it can be None if number of extruders are changed during runtime
|
if quality_changes_node is not None: # it can be None if number of extruders are changed during runtime
|
||||||
try:
|
try:
|
||||||
quality_containers.insert(0, quality_changes_node.getContainer())
|
quality_containers.insert(0, quality_changes_node.getContainer())
|
||||||
|
176
cura/Machines/Models/SettingVisibilityPresetsModel.py
Normal file
176
cura/Machines/Models/SettingVisibilityPresetsModel.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
import os
|
||||||
|
import urllib.parse
|
||||||
|
from configparser import ConfigParser
|
||||||
|
|
||||||
|
from PyQt5.QtCore import pyqtProperty, Qt, pyqtSignal, pyqtSlot
|
||||||
|
|
||||||
|
from UM.Logger import Logger
|
||||||
|
from UM.Qt.ListModel import ListModel
|
||||||
|
from UM.Preferences import Preferences
|
||||||
|
from UM.Resources import Resources
|
||||||
|
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeTypeNotFoundError
|
||||||
|
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
|
class SettingVisibilityPresetsModel(ListModel):
|
||||||
|
IdRole = Qt.UserRole + 1
|
||||||
|
NameRole = Qt.UserRole + 2
|
||||||
|
SettingsRole = Qt.UserRole + 3
|
||||||
|
|
||||||
|
def __init__(self, parent = None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.addRoleName(self.IdRole, "id")
|
||||||
|
self.addRoleName(self.NameRole, "name")
|
||||||
|
self.addRoleName(self.SettingsRole, "settings")
|
||||||
|
|
||||||
|
self._populate()
|
||||||
|
basic_item = self.items[1]
|
||||||
|
basic_visibile_settings = ";".join(basic_item["settings"])
|
||||||
|
|
||||||
|
self._preferences = Preferences.getInstance()
|
||||||
|
# Preference to store which preset is currently selected
|
||||||
|
self._preferences.addPreference("cura/active_setting_visibility_preset", "basic")
|
||||||
|
# Preference that stores the "custom" set so it can always be restored (even after a restart)
|
||||||
|
self._preferences.addPreference("cura/custom_visible_settings", basic_visibile_settings)
|
||||||
|
self._preferences.preferenceChanged.connect(self._onPreferencesChanged)
|
||||||
|
|
||||||
|
self._active_preset_item = self._getItem(self._preferences.getValue("cura/active_setting_visibility_preset"))
|
||||||
|
# Initialize visible settings if it is not done yet
|
||||||
|
visible_settings = self._preferences.getValue("general/visible_settings")
|
||||||
|
if not visible_settings:
|
||||||
|
self._preferences.setValue("general/visible_settings", ";".join(self._active_preset_item["settings"]))
|
||||||
|
|
||||||
|
self.activePresetChanged.emit()
|
||||||
|
|
||||||
|
def _getItem(self, item_id: str) -> Optional[dict]:
|
||||||
|
result = None
|
||||||
|
for item in self.items:
|
||||||
|
if item["id"] == item_id:
|
||||||
|
result = item
|
||||||
|
break
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _populate(self):
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
items = []
|
||||||
|
for file_path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.SettingVisibilityPreset):
|
||||||
|
try:
|
||||||
|
mime_type = MimeTypeDatabase.getMimeTypeForFile(file_path)
|
||||||
|
except MimeTypeNotFoundError:
|
||||||
|
Logger.log("e", "Could not determine mime type of file %s", file_path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
item_id = urllib.parse.unquote_plus(mime_type.stripExtension(os.path.basename(file_path)))
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
Logger.log("e", "[%s] is not a file", file_path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
parser = ConfigParser(allow_no_value = True) # accept options without any value,
|
||||||
|
try:
|
||||||
|
parser.read([file_path])
|
||||||
|
if not parser.has_option("general", "name") or not parser.has_option("general", "weight"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
settings = []
|
||||||
|
for section in parser.sections():
|
||||||
|
if section == 'general':
|
||||||
|
continue
|
||||||
|
|
||||||
|
settings.append(section)
|
||||||
|
for option in parser[section].keys():
|
||||||
|
settings.append(option)
|
||||||
|
|
||||||
|
items.append({
|
||||||
|
"id": item_id,
|
||||||
|
"name": catalog.i18nc("@action:inmenu", parser["general"]["name"]),
|
||||||
|
"weight": parser["general"]["weight"],
|
||||||
|
"settings": settings,
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
Logger.logException("e", "Failed to load setting preset %s", file_path)
|
||||||
|
|
||||||
|
items.sort(key = lambda k: (int(k["weight"]), k["id"]))
|
||||||
|
# Put "custom" at the top
|
||||||
|
items.insert(0, {"id": "custom",
|
||||||
|
"name": "Custom selection",
|
||||||
|
"weight": -100,
|
||||||
|
"settings": []})
|
||||||
|
|
||||||
|
self.setItems(items)
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def setActivePreset(self, preset_id: str):
|
||||||
|
if preset_id == self._active_preset_item["id"]:
|
||||||
|
Logger.log("d", "Same setting visibility preset [%s] selected, do nothing.", preset_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
preset_item = None
|
||||||
|
for item in self.items:
|
||||||
|
if item["id"] == preset_id:
|
||||||
|
preset_item = item
|
||||||
|
break
|
||||||
|
if preset_item is None:
|
||||||
|
Logger.log("w", "Tried to set active preset to unknown id [%s]", preset_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
need_to_save_to_custom = self._active_preset_item["id"] == "custom" and preset_id != "custom"
|
||||||
|
if need_to_save_to_custom:
|
||||||
|
# Save the current visibility settings to custom
|
||||||
|
current_visibility_string = self._preferences.getValue("general/visible_settings")
|
||||||
|
if current_visibility_string:
|
||||||
|
self._preferences.setValue("cura/custom_visible_settings", current_visibility_string)
|
||||||
|
|
||||||
|
new_visibility_string = ";".join(preset_item["settings"])
|
||||||
|
if preset_id == "custom":
|
||||||
|
# Get settings from the stored custom data
|
||||||
|
new_visibility_string = self._preferences.getValue("cura/custom_visible_settings")
|
||||||
|
if new_visibility_string is None:
|
||||||
|
new_visibility_string = self._preferences.getValue("general/visible_settings")
|
||||||
|
self._preferences.setValue("general/visible_settings", new_visibility_string)
|
||||||
|
|
||||||
|
self._preferences.setValue("cura/active_setting_visibility_preset", preset_id)
|
||||||
|
self._active_preset_item = preset_item
|
||||||
|
self.activePresetChanged.emit()
|
||||||
|
|
||||||
|
activePresetChanged = pyqtSignal()
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify = activePresetChanged)
|
||||||
|
def activePreset(self) -> str:
|
||||||
|
return self._active_preset_item["id"]
|
||||||
|
|
||||||
|
def _onPreferencesChanged(self, name: str):
|
||||||
|
if name != "general/visible_settings":
|
||||||
|
return
|
||||||
|
|
||||||
|
# Find the preset that matches with the current visible settings setup
|
||||||
|
visibility_string = self._preferences.getValue("general/visible_settings")
|
||||||
|
if not visibility_string:
|
||||||
|
return
|
||||||
|
|
||||||
|
visibility_set = set(visibility_string.split(";"))
|
||||||
|
matching_preset_item = None
|
||||||
|
for item in self.items:
|
||||||
|
if item["id"] == "custom":
|
||||||
|
continue
|
||||||
|
if set(item["settings"]) == visibility_set:
|
||||||
|
matching_preset_item = item
|
||||||
|
break
|
||||||
|
|
||||||
|
if matching_preset_item is None:
|
||||||
|
# The new visibility setup is "custom" should be custom
|
||||||
|
if self._active_preset_item["id"] == "custom":
|
||||||
|
# We are already in custom, just save the settings
|
||||||
|
self._preferences.setValue("cura/custom_visible_settings", visibility_string)
|
||||||
|
else:
|
||||||
|
self._active_preset_item = self.items[0] # 0 is custom
|
||||||
|
self.activePresetChanged.emit()
|
||||||
|
else:
|
||||||
|
self._active_preset_item = matching_preset_item
|
||||||
|
self.activePresetChanged.emit()
|
@ -16,6 +16,7 @@ from .QualityGroup import QualityGroup
|
|||||||
from .QualityNode import QualityNode
|
from .QualityNode import QualityNode
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
from cura.Settings.GlobalStack import GlobalStack
|
||||||
from .QualityChangesGroup import QualityChangesGroup
|
from .QualityChangesGroup import QualityChangesGroup
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ class QualityManager(QObject):
|
|||||||
|
|
||||||
# Returns a dict of "custom profile name" -> QualityChangesGroup
|
# Returns a dict of "custom profile name" -> QualityChangesGroup
|
||||||
def getQualityChangesGroups(self, machine: "GlobalStack") -> dict:
|
def getQualityChangesGroups(self, machine: "GlobalStack") -> dict:
|
||||||
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
|
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition)
|
||||||
|
|
||||||
machine_node = self._machine_quality_type_to_quality_changes_dict.get(machine_definition_id)
|
machine_node = self._machine_quality_type_to_quality_changes_dict.get(machine_definition_id)
|
||||||
if not machine_node:
|
if not machine_node:
|
||||||
@ -206,7 +207,7 @@ class QualityManager(QObject):
|
|||||||
# For more details, see QualityGroup.
|
# For more details, see QualityGroup.
|
||||||
#
|
#
|
||||||
def getQualityGroups(self, machine: "GlobalStack") -> dict:
|
def getQualityGroups(self, machine: "GlobalStack") -> dict:
|
||||||
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
|
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition)
|
||||||
|
|
||||||
# This determines if we should only get the global qualities for the global stack and skip the global qualities for the extruder stacks
|
# This determines if we should only get the global qualities for the global stack and skip the global qualities for the extruder stacks
|
||||||
has_variant_materials = parseBool(machine.getMetaDataEntry("has_variant_materials", False))
|
has_variant_materials = parseBool(machine.getMetaDataEntry("has_variant_materials", False))
|
||||||
@ -315,7 +316,7 @@ class QualityManager(QObject):
|
|||||||
return quality_group_dict
|
return quality_group_dict
|
||||||
|
|
||||||
def getQualityGroupsForMachineDefinition(self, machine: "GlobalStack") -> dict:
|
def getQualityGroupsForMachineDefinition(self, machine: "GlobalStack") -> dict:
|
||||||
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
|
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition)
|
||||||
|
|
||||||
# To find the quality container for the GlobalStack, check in the following fall-back manner:
|
# To find the quality container for the GlobalStack, check in the following fall-back manner:
|
||||||
# (1) the machine-specific node
|
# (1) the machine-specific node
|
||||||
@ -460,7 +461,7 @@ class QualityManager(QObject):
|
|||||||
quality_changes.addMetaDataEntry("position", extruder_stack.getMetaDataEntry("position"))
|
quality_changes.addMetaDataEntry("position", extruder_stack.getMetaDataEntry("position"))
|
||||||
|
|
||||||
# If the machine specifies qualities should be filtered, ensure we match the current criteria.
|
# If the machine specifies qualities should be filtered, ensure we match the current criteria.
|
||||||
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine)
|
machine_definition_id = getMachineDefinitionIDForQualitySearch(machine.definition)
|
||||||
quality_changes.setDefinition(machine_definition_id)
|
quality_changes.setDefinition(machine_definition_id)
|
||||||
|
|
||||||
quality_changes.addMetaDataEntry("setting_version", self._application.SettingVersion)
|
quality_changes.addMetaDataEntry("setting_version", self._application.SettingVersion)
|
||||||
@ -480,12 +481,13 @@ class QualityManager(QObject):
|
|||||||
# Example: for an Ultimaker 3 Extended, it has "quality_definition = ultimaker3". This means Ultimaker 3 Extended
|
# Example: for an Ultimaker 3 Extended, it has "quality_definition = ultimaker3". This means Ultimaker 3 Extended
|
||||||
# shares the same set of qualities profiles as Ultimaker 3.
|
# shares the same set of qualities profiles as Ultimaker 3.
|
||||||
#
|
#
|
||||||
def getMachineDefinitionIDForQualitySearch(machine: "GlobalStack", default_definition_id: str = "fdmprinter") -> str:
|
def getMachineDefinitionIDForQualitySearch(machine_definition: "DefinitionContainer",
|
||||||
|
default_definition_id: str = "fdmprinter") -> str:
|
||||||
machine_definition_id = default_definition_id
|
machine_definition_id = default_definition_id
|
||||||
if parseBool(machine.getMetaDataEntry("has_machine_quality", False)):
|
if parseBool(machine_definition.getMetaDataEntry("has_machine_quality", False)):
|
||||||
# Only use the machine's own quality definition ID if this machine has machine quality.
|
# Only use the machine's own quality definition ID if this machine has machine quality.
|
||||||
machine_definition_id = machine.getMetaDataEntry("quality_definition")
|
machine_definition_id = machine_definition.getMetaDataEntry("quality_definition")
|
||||||
if machine_definition_id is None:
|
if machine_definition_id is None:
|
||||||
machine_definition_id = machine.definition.getId()
|
machine_definition_id = machine_definition.getId()
|
||||||
|
|
||||||
return machine_definition_id
|
return machine_definition_id
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QTimer
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
@ -14,8 +19,13 @@ class ObjectsModel(ListModel):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
Application.getInstance().getController().getScene().sceneChanged.connect(self._update)
|
Application.getInstance().getController().getScene().sceneChanged.connect(self._updateDelayed)
|
||||||
Preferences.getInstance().preferenceChanged.connect(self._update)
|
Preferences.getInstance().preferenceChanged.connect(self._updateDelayed)
|
||||||
|
|
||||||
|
self._update_timer = QTimer()
|
||||||
|
self._update_timer.setInterval(100)
|
||||||
|
self._update_timer.setSingleShot(True)
|
||||||
|
self._update_timer.timeout.connect(self._update)
|
||||||
|
|
||||||
self._build_plate_number = -1
|
self._build_plate_number = -1
|
||||||
|
|
||||||
@ -23,6 +33,9 @@ class ObjectsModel(ListModel):
|
|||||||
self._build_plate_number = nr
|
self._build_plate_number = nr
|
||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
|
def _updateDelayed(self, *args):
|
||||||
|
self._update_timer.start()
|
||||||
|
|
||||||
def _update(self, *args):
|
def _update(self, *args):
|
||||||
nodes = []
|
nodes = []
|
||||||
filter_current_build_plate = Preferences.getInstance().getValue("view/filter_current_build_plate")
|
filter_current_build_plate = Preferences.getInstance().getValue("view/filter_current_build_plate")
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
|
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
|
||||||
|
|
||||||
@ -56,12 +58,15 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
self._connection_state_before_timeout = None # type: Optional[ConnectionState]
|
self._connection_state_before_timeout = None # type: Optional[ConnectionState]
|
||||||
|
|
||||||
printer_type = self._properties.get(b"machine", b"").decode("utf-8")
|
printer_type = self._properties.get(b"machine", b"").decode("utf-8")
|
||||||
if printer_type.startswith("9511"):
|
printer_type_identifiers = {
|
||||||
self._printer_type = "ultimaker3_extended"
|
"9066": "ultimaker3",
|
||||||
elif printer_type.startswith("9066"):
|
"9511": "ultimaker3_extended"
|
||||||
self._printer_type = "ultimaker3"
|
}
|
||||||
else:
|
self._printer_type = "Unknown"
|
||||||
self._printer_type = "unknown"
|
for key, value in printer_type_identifiers.items():
|
||||||
|
if printer_type.startswith(key):
|
||||||
|
self._printer_type = value
|
||||||
|
break
|
||||||
|
|
||||||
def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs) -> None:
|
def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs) -> None:
|
||||||
raise NotImplementedError("requestWrite needs to be implemented")
|
raise NotImplementedError("requestWrite needs to be implemented")
|
||||||
@ -251,6 +256,9 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
self._last_manager_create_time = time()
|
self._last_manager_create_time = time()
|
||||||
self._manager.authenticationRequired.connect(self._onAuthenticationRequired)
|
self._manager.authenticationRequired.connect(self._onAuthenticationRequired)
|
||||||
|
|
||||||
|
machine_manager = CuraApplication.getInstance().getMachineManager()
|
||||||
|
machine_manager.checkCorrectGroupName(self.getId(), self.name)
|
||||||
|
|
||||||
def _registerOnFinishedCallback(self, reply: QNetworkReply, onFinished: Optional[Callable[[Any, QNetworkReply], None]]) -> None:
|
def _registerOnFinishedCallback(self, reply: QNetworkReply, onFinished: Optional[Callable[[Any, QNetworkReply], None]]) -> None:
|
||||||
if onFinished is not None:
|
if onFinished is not None:
|
||||||
self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
|
self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
# Copyright (c) 2016 Ultimaker B.V.
|
# Copyright (c) 2016 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QTimer
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Math.Polygon import Polygon
|
from UM.Math.Polygon import Polygon
|
||||||
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
|
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
|
||||||
@ -22,6 +24,10 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||||||
|
|
||||||
self._global_stack = None
|
self._global_stack = None
|
||||||
|
|
||||||
|
# Make sure the timer is created on the main thread
|
||||||
|
self._recompute_convex_hull_timer = None
|
||||||
|
Application.getInstance().callLater(self.createRecomputeConvexHullTimer)
|
||||||
|
|
||||||
self._raft_thickness = 0.0
|
self._raft_thickness = 0.0
|
||||||
# For raft thickness, DRY
|
# For raft thickness, DRY
|
||||||
self._build_volume = Application.getInstance().getBuildVolume()
|
self._build_volume = Application.getInstance().getBuildVolume()
|
||||||
@ -33,6 +39,12 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||||||
|
|
||||||
self._onGlobalStackChanged()
|
self._onGlobalStackChanged()
|
||||||
|
|
||||||
|
def createRecomputeConvexHullTimer(self):
|
||||||
|
self._recompute_convex_hull_timer = QTimer()
|
||||||
|
self._recompute_convex_hull_timer.setInterval(200)
|
||||||
|
self._recompute_convex_hull_timer.setSingleShot(True)
|
||||||
|
self._recompute_convex_hull_timer.timeout.connect(self.recomputeConvexHull)
|
||||||
|
|
||||||
def setNode(self, node):
|
def setNode(self, node):
|
||||||
previous_node = self._node
|
previous_node = self._node
|
||||||
# Disconnect from previous node signals
|
# Disconnect from previous node signals
|
||||||
@ -99,6 +111,12 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||||||
return self._compute2DConvexHull()
|
return self._compute2DConvexHull()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def recomputeConvexHullDelayed(self):
|
||||||
|
if self._recompute_convex_hull_timer is not None:
|
||||||
|
self._recompute_convex_hull_timer.start()
|
||||||
|
else:
|
||||||
|
self.recomputeConvexHull()
|
||||||
|
|
||||||
def recomputeConvexHull(self):
|
def recomputeConvexHull(self):
|
||||||
controller = Application.getInstance().getController()
|
controller = Application.getInstance().getController()
|
||||||
root = controller.getScene().getRoot()
|
root = controller.getScene().getRoot()
|
||||||
@ -279,7 +297,8 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
|||||||
|
|
||||||
def _onChanged(self, *args):
|
def _onChanged(self, *args):
|
||||||
self._raft_thickness = self._build_volume.getRaftThickness()
|
self._raft_thickness = self._build_volume.getRaftThickness()
|
||||||
self.recomputeConvexHull()
|
if not args or args[0] == self._node:
|
||||||
|
self.recomputeConvexHullDelayed()
|
||||||
|
|
||||||
def _onGlobalStackChanged(self):
|
def _onGlobalStackChanged(self):
|
||||||
if self._global_stack:
|
if self._global_stack:
|
||||||
|
@ -173,12 +173,13 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
plugin_registry = PluginRegistry.getInstance()
|
plugin_registry = PluginRegistry.getInstance()
|
||||||
extension = file_name.split(".")[-1]
|
extension = file_name.split(".")[-1]
|
||||||
|
|
||||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
if not global_container_stack:
|
if not global_stack:
|
||||||
return
|
return
|
||||||
|
|
||||||
machine_extruders = list(ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()))
|
machine_extruders = []
|
||||||
machine_extruders.sort(key = lambda k: k.getMetaDataEntry("position"))
|
for position in sorted(global_stack.extruders):
|
||||||
|
machine_extruders.append(global_stack.extruders[position])
|
||||||
|
|
||||||
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
|
for plugin_id, meta_data in self._getIOPlugins("profile_reader"):
|
||||||
if meta_data["profile_reader"][0]["extension"] != extension:
|
if meta_data["profile_reader"][0]["extension"] != extension:
|
||||||
@ -200,28 +201,51 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
|
|
||||||
# First check if this profile is suitable for this machine
|
# First check if this profile is suitable for this machine
|
||||||
global_profile = None
|
global_profile = None
|
||||||
|
extruder_profiles = []
|
||||||
if len(profile_or_list) == 1:
|
if len(profile_or_list) == 1:
|
||||||
global_profile = profile_or_list[0]
|
global_profile = profile_or_list[0]
|
||||||
else:
|
else:
|
||||||
for profile in profile_or_list:
|
for profile in profile_or_list:
|
||||||
if not profile.getMetaDataEntry("extruder"):
|
if not profile.getMetaDataEntry("position"):
|
||||||
global_profile = profile
|
global_profile = profile
|
||||||
break
|
else:
|
||||||
|
extruder_profiles.append(profile)
|
||||||
|
extruder_profiles = sorted(extruder_profiles, key = lambda x: int(x.getMetaDataEntry("position")))
|
||||||
|
profile_or_list = [global_profile] + extruder_profiles
|
||||||
|
|
||||||
if not global_profile:
|
if not global_profile:
|
||||||
Logger.log("e", "Incorrect profile [%s]. Could not find global profile", file_name)
|
Logger.log("e", "Incorrect profile [%s]. Could not find global profile", file_name)
|
||||||
return { "status": "error",
|
return { "status": "error",
|
||||||
"message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name)}
|
"message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name)}
|
||||||
profile_definition = global_profile.getMetaDataEntry("definition")
|
profile_definition = global_profile.getMetaDataEntry("definition")
|
||||||
expected_machine_definition = "fdmprinter"
|
|
||||||
if parseBool(global_container_stack.getMetaDataEntry("has_machine_quality", "False")):
|
# Make sure we have a profile_definition in the file:
|
||||||
expected_machine_definition = global_container_stack.getMetaDataEntry("quality_definition")
|
if profile_definition is None:
|
||||||
if not expected_machine_definition:
|
break
|
||||||
expected_machine_definition = global_container_stack.definition.getId()
|
machine_definition = self.findDefinitionContainers(id = profile_definition)
|
||||||
if expected_machine_definition is not None and profile_definition is not None and profile_definition != expected_machine_definition:
|
if not machine_definition:
|
||||||
|
Logger.log("e", "Incorrect profile [%s]. Unknown machine type [%s]", file_name, profile_definition)
|
||||||
|
return {"status": "error",
|
||||||
|
"message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "This profile <filename>{0}</filename> contains incorrect data, could not import it.", file_name)
|
||||||
|
}
|
||||||
|
machine_definition = machine_definition[0]
|
||||||
|
|
||||||
|
# Get the expected machine definition.
|
||||||
|
# i.e.: We expect gcode for a UM2 Extended to be defined as normal UM2 gcode...
|
||||||
|
profile_definition = getMachineDefinitionIDForQualitySearch(machine_definition)
|
||||||
|
expected_machine_definition = getMachineDefinitionIDForQualitySearch(global_stack.definition)
|
||||||
|
|
||||||
|
# And check if the profile_definition matches either one (showing error if not):
|
||||||
|
if profile_definition != expected_machine_definition:
|
||||||
Logger.log("e", "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile", file_name, profile_definition, expected_machine_definition)
|
Logger.log("e", "Profile [%s] is for machine [%s] but the current active machine is [%s]. Will not import the profile", file_name, profile_definition, expected_machine_definition)
|
||||||
return { "status": "error",
|
return { "status": "error",
|
||||||
"message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "The machine defined in profile <filename>{0}</filename> ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition)}
|
"message": catalog.i18nc("@info:status Don't translate the XML tags <filename> or <message>!", "The machine defined in profile <filename>{0}</filename> ({1}) doesn't match with your current machine ({2}), could not import it.", file_name, profile_definition, expected_machine_definition)}
|
||||||
|
|
||||||
|
# Fix the global quality profile's definition field in case it's not correct
|
||||||
|
global_profile.setMetaDataEntry("definition", expected_machine_definition)
|
||||||
|
quality_name = global_profile.getName()
|
||||||
|
quality_type = global_profile.getMetaDataEntry("quality_type")
|
||||||
|
|
||||||
name_seed = os.path.splitext(os.path.basename(file_name))[0]
|
name_seed = os.path.splitext(os.path.basename(file_name))[0]
|
||||||
new_name = self.uniqueName(name_seed)
|
new_name = self.uniqueName(name_seed)
|
||||||
|
|
||||||
@ -233,25 +257,25 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
if len(profile_or_list) == 1:
|
if len(profile_or_list) == 1:
|
||||||
global_profile = profile_or_list[0]
|
global_profile = profile_or_list[0]
|
||||||
extruder_profiles = []
|
extruder_profiles = []
|
||||||
for idx, extruder in enumerate(global_container_stack.extruders.values()):
|
for idx, extruder in enumerate(global_stack.extruders.values()):
|
||||||
profile_id = ContainerRegistry.getInstance().uniqueName(global_container_stack.getId() + "_extruder_" + str(idx + 1))
|
profile_id = ContainerRegistry.getInstance().uniqueName(global_stack.getId() + "_extruder_" + str(idx + 1))
|
||||||
profile = InstanceContainer(profile_id)
|
profile = InstanceContainer(profile_id)
|
||||||
profile.setName(global_profile.getName())
|
profile.setName(quality_name)
|
||||||
profile.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
|
profile.addMetaDataEntry("setting_version", CuraApplication.SettingVersion)
|
||||||
profile.addMetaDataEntry("type", "quality_changes")
|
profile.addMetaDataEntry("type", "quality_changes")
|
||||||
profile.addMetaDataEntry("definition", global_profile.getMetaDataEntry("definition"))
|
profile.addMetaDataEntry("definition", expected_machine_definition)
|
||||||
profile.addMetaDataEntry("quality_type", global_profile.getMetaDataEntry("quality_type"))
|
profile.addMetaDataEntry("quality_type", quality_type)
|
||||||
profile.addMetaDataEntry("position", "0")
|
profile.addMetaDataEntry("position", "0")
|
||||||
profile.setDirty(True)
|
profile.setDirty(True)
|
||||||
if idx == 0:
|
if idx == 0:
|
||||||
# move all per-extruder settings to the first extruder's quality_changes
|
# move all per-extruder settings to the first extruder's quality_changes
|
||||||
for qc_setting_key in global_profile.getAllKeys():
|
for qc_setting_key in global_profile.getAllKeys():
|
||||||
settable_per_extruder = global_container_stack.getProperty(qc_setting_key,
|
settable_per_extruder = global_stack.getProperty(qc_setting_key,
|
||||||
"settable_per_extruder")
|
"settable_per_extruder")
|
||||||
if settable_per_extruder:
|
if settable_per_extruder:
|
||||||
setting_value = global_profile.getProperty(qc_setting_key, "value")
|
setting_value = global_profile.getProperty(qc_setting_key, "value")
|
||||||
|
|
||||||
setting_definition = global_container_stack.getSettingDefinition(qc_setting_key)
|
setting_definition = global_stack.getSettingDefinition(qc_setting_key)
|
||||||
new_instance = SettingInstance(setting_definition, profile)
|
new_instance = SettingInstance(setting_definition, profile)
|
||||||
new_instance.setProperty("value", setting_value)
|
new_instance.setProperty("value", setting_value)
|
||||||
new_instance.resetState() # Ensure that the state is not seen as a user state.
|
new_instance.resetState() # Ensure that the state is not seen as a user state.
|
||||||
@ -268,7 +292,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
for profile_index, profile in enumerate(profile_or_list):
|
for profile_index, profile in enumerate(profile_or_list):
|
||||||
if profile_index == 0:
|
if profile_index == 0:
|
||||||
# This is assumed to be the global profile
|
# This is assumed to be the global profile
|
||||||
profile_id = (global_container_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
|
profile_id = (global_stack.getBottom().getId() + "_" + name_seed).lower().replace(" ", "_")
|
||||||
|
|
||||||
elif profile_index < len(machine_extruders) + 1:
|
elif profile_index < len(machine_extruders) + 1:
|
||||||
# This is assumed to be an extruder profile
|
# This is assumed to be an extruder profile
|
||||||
@ -283,7 +307,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
else: #More extruders in the imported file than in the machine.
|
else: #More extruders in the imported file than in the machine.
|
||||||
continue #Delete the additional profiles.
|
continue #Delete the additional profiles.
|
||||||
|
|
||||||
result = self._configureProfile(profile, profile_id, new_name)
|
result = self._configureProfile(profile, profile_id, new_name, expected_machine_definition)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return {"status": "error", "message": catalog.i18nc(
|
return {"status": "error", "message": catalog.i18nc(
|
||||||
"@info:status Don't translate the XML tags <filename> or <message>!",
|
"@info:status Don't translate the XML tags <filename> or <message>!",
|
||||||
@ -311,7 +335,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
# \param new_name The new name for the profile.
|
# \param new_name The new name for the profile.
|
||||||
#
|
#
|
||||||
# \return None if configuring was successful or an error message if an error occurred.
|
# \return None if configuring was successful or an error message if an error occurred.
|
||||||
def _configureProfile(self, profile: InstanceContainer, id_seed: str, new_name: str) -> Optional[str]:
|
def _configureProfile(self, profile: InstanceContainer, id_seed: str, new_name: str, machine_definition_id: str) -> Optional[str]:
|
||||||
profile.setDirty(True) # Ensure the profiles are correctly saved
|
profile.setDirty(True) # Ensure the profiles are correctly saved
|
||||||
|
|
||||||
new_id = self.createUniqueName("quality_changes", "", id_seed, catalog.i18nc("@label", "Custom profile"))
|
new_id = self.createUniqueName("quality_changes", "", id_seed, catalog.i18nc("@label", "Custom profile"))
|
||||||
@ -321,6 +345,7 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
# Set the unique Id to the profile, so it's generating a new one even if the user imports the same profile
|
# Set the unique Id to the profile, so it's generating a new one even if the user imports the same profile
|
||||||
# It also solves an issue with importing profiles from G-Codes
|
# It also solves an issue with importing profiles from G-Codes
|
||||||
profile.setMetaDataEntry("id", new_id)
|
profile.setMetaDataEntry("id", new_id)
|
||||||
|
profile.setMetaDataEntry("definition", machine_definition_id)
|
||||||
|
|
||||||
if "type" in profile.getMetaData():
|
if "type" in profile.getMetaData():
|
||||||
profile.setMetaDataEntry("type", "quality_changes")
|
profile.setMetaDataEntry("type", "quality_changes")
|
||||||
@ -331,9 +356,8 @@ class CuraContainerRegistry(ContainerRegistry):
|
|||||||
if not quality_type:
|
if not quality_type:
|
||||||
return catalog.i18nc("@info:status", "Profile is missing a quality type.")
|
return catalog.i18nc("@info:status", "Profile is missing a quality type.")
|
||||||
|
|
||||||
quality_type_criteria = {"quality_type": quality_type}
|
|
||||||
global_stack = Application.getInstance().getGlobalContainerStack()
|
global_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
definition_id = getMachineDefinitionIDForQualitySearch(global_stack)
|
definition_id = getMachineDefinitionIDForQualitySearch(global_stack.definition)
|
||||||
profile.setDefinition(definition_id)
|
profile.setDefinition(definition_id)
|
||||||
|
|
||||||
# Check to make sure the imported profile actually makes sense in context of the current configuration.
|
# Check to make sure the imported profile actually makes sense in context of the current configuration.
|
||||||
|
@ -210,6 +210,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
|
|||||||
item = {
|
item = {
|
||||||
"id": "",
|
"id": "",
|
||||||
"name": catalog.i18nc("@menuitem", "Not overridden"),
|
"name": catalog.i18nc("@menuitem", "Not overridden"),
|
||||||
|
"enabled": True,
|
||||||
"color": "#ffffff",
|
"color": "#ffffff",
|
||||||
"index": -1,
|
"index": -1,
|
||||||
"definition": ""
|
"definition": ""
|
||||||
|
@ -10,7 +10,6 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
|||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer
|
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer
|
||||||
import UM.FlameProfiler
|
|
||||||
from UM.FlameProfiler import pyqtSlot
|
from UM.FlameProfiler import pyqtSlot
|
||||||
from UM import Util
|
from UM import Util
|
||||||
|
|
||||||
@ -24,7 +23,6 @@ from UM.Settings.SettingFunction import SettingFunction
|
|||||||
from UM.Signal import postponeSignals, CompressTechnique
|
from UM.Signal import postponeSignals, CompressTechnique
|
||||||
|
|
||||||
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
|
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
|
||||||
from cura.Machines.VariantManager import VariantType
|
|
||||||
from cura.PrinterOutputDevice import PrinterOutputDevice
|
from cura.PrinterOutputDevice import PrinterOutputDevice
|
||||||
from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
|
from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
|
||||||
from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel
|
from cura.PrinterOutput.ExtruderConfigurationModel import ExtruderConfigurationModel
|
||||||
@ -147,6 +145,7 @@ class MachineManager(QObject):
|
|||||||
activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed.
|
activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed.
|
||||||
activeStackValidationChanged = pyqtSignal() # Emitted whenever a validation inside active container is changed
|
activeStackValidationChanged = pyqtSignal() # Emitted whenever a validation inside active container is changed
|
||||||
stacksValidationChanged = pyqtSignal() # Emitted whenever a validation is changed
|
stacksValidationChanged = pyqtSignal() # Emitted whenever a validation is changed
|
||||||
|
numberExtrudersEnabledChanged = pyqtSignal() # Emitted when the number of extruders that are enabled changed
|
||||||
|
|
||||||
blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly
|
blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly
|
||||||
|
|
||||||
@ -467,16 +466,16 @@ class MachineManager(QObject):
|
|||||||
return self._global_container_stack.getId()
|
return self._global_container_stack.getId()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@pyqtProperty(str, notify = globalContainerChanged)
|
@pyqtProperty(str, notify = outputDevicesChanged)
|
||||||
def activeMachineNetworkKey(self) -> str:
|
def activeMachineNetworkKey(self) -> str:
|
||||||
if self._global_container_stack:
|
if self._global_container_stack:
|
||||||
return self._global_container_stack.getMetaDataEntry("um_network_key")
|
return self._global_container_stack.getMetaDataEntry("um_network_key", "")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@pyqtProperty(str, notify = globalContainerChanged)
|
@pyqtProperty(str, notify = outputDevicesChanged)
|
||||||
def activeMachineNetworkGroupName(self) -> str:
|
def activeMachineNetworkGroupName(self) -> str:
|
||||||
if self._global_container_stack:
|
if self._global_container_stack:
|
||||||
return self._global_container_stack.getMetaDataEntry("connect_group_name")
|
return self._global_container_stack.getMetaDataEntry("connect_group_name", "")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@pyqtProperty(QObject, notify = globalContainerChanged)
|
@pyqtProperty(QObject, notify = globalContainerChanged)
|
||||||
@ -628,7 +627,7 @@ class MachineManager(QObject):
|
|||||||
@pyqtProperty(str, notify = globalContainerChanged)
|
@pyqtProperty(str, notify = globalContainerChanged)
|
||||||
def activeQualityDefinitionId(self) -> str:
|
def activeQualityDefinitionId(self) -> str:
|
||||||
if self._global_container_stack:
|
if self._global_container_stack:
|
||||||
return getMachineDefinitionIDForQualitySearch(self._global_container_stack)
|
return getMachineDefinitionIDForQualitySearch(self._global_container_stack.definition)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
## Gets how the active definition calls variants
|
## Gets how the active definition calls variants
|
||||||
@ -662,12 +661,22 @@ class MachineManager(QObject):
|
|||||||
if other_machine_stacks:
|
if other_machine_stacks:
|
||||||
self.setActiveMachine(other_machine_stacks[0]["id"])
|
self.setActiveMachine(other_machine_stacks[0]["id"])
|
||||||
|
|
||||||
|
metadata = ContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id)[0]
|
||||||
|
network_key = metadata["um_network_key"] if "um_network_key" in metadata else None
|
||||||
ExtruderManager.getInstance().removeMachineExtruders(machine_id)
|
ExtruderManager.getInstance().removeMachineExtruders(machine_id)
|
||||||
containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id)
|
containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(type = "user", machine = machine_id)
|
||||||
for container in containers:
|
for container in containers:
|
||||||
ContainerRegistry.getInstance().removeContainer(container["id"])
|
ContainerRegistry.getInstance().removeContainer(container["id"])
|
||||||
ContainerRegistry.getInstance().removeContainer(machine_id)
|
ContainerRegistry.getInstance().removeContainer(machine_id)
|
||||||
|
|
||||||
|
# If the printer that is being removed is a network printer, the hidden printers have to be also removed
|
||||||
|
if network_key:
|
||||||
|
metadata_filter = {"um_network_key": network_key}
|
||||||
|
hidden_containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter)
|
||||||
|
if hidden_containers:
|
||||||
|
# This reuses the method and remove all printers recursively
|
||||||
|
self.removeMachine(hidden_containers[0].getId())
|
||||||
|
|
||||||
@pyqtProperty(bool, notify = globalContainerChanged)
|
@pyqtProperty(bool, notify = globalContainerChanged)
|
||||||
def hasMaterials(self) -> bool:
|
def hasMaterials(self) -> bool:
|
||||||
if self._global_container_stack:
|
if self._global_container_stack:
|
||||||
@ -872,7 +881,13 @@ class MachineManager(QObject):
|
|||||||
for position, extruder in self._global_container_stack.extruders.items():
|
for position, extruder in self._global_container_stack.extruders.items():
|
||||||
if extruder.isEnabled:
|
if extruder.isEnabled:
|
||||||
extruder_count += 1
|
extruder_count += 1
|
||||||
|
if self.numberExtrudersEnabled != extruder_count:
|
||||||
definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count)
|
definition_changes_container.setProperty("extruders_enabled_count", "value", extruder_count)
|
||||||
|
self.numberExtrudersEnabledChanged.emit()
|
||||||
|
|
||||||
|
@pyqtProperty(int, notify = numberExtrudersEnabledChanged)
|
||||||
|
def numberExtrudersEnabled(self):
|
||||||
|
return self._global_container_stack.definitionChanges.getProperty("extruders_enabled_count", "value")
|
||||||
|
|
||||||
@pyqtProperty(str, notify = extruderChanged)
|
@pyqtProperty(str, notify = extruderChanged)
|
||||||
def defaultExtruderPosition(self):
|
def defaultExtruderPosition(self):
|
||||||
@ -882,7 +897,7 @@ class MachineManager(QObject):
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def forceUpdateAllSettings(self):
|
def forceUpdateAllSettings(self):
|
||||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
property_names = ["value", "resolve"]
|
property_names = ["value", "resolve", "validationState"]
|
||||||
for container in [self._global_container_stack] + list(self._global_container_stack.extruders.values()):
|
for container in [self._global_container_stack] + list(self._global_container_stack.extruders.values()):
|
||||||
for setting_key in container.getAllKeys():
|
for setting_key in container.getAllKeys():
|
||||||
container.propertiesChanged.emit(setting_key, property_names)
|
container.propertiesChanged.emit(setting_key, property_names)
|
||||||
@ -1193,6 +1208,18 @@ class MachineManager(QObject):
|
|||||||
if machine.getMetaDataEntry(key) == value:
|
if machine.getMetaDataEntry(key) == value:
|
||||||
machine.setMetaDataEntry(key, new_value)
|
machine.setMetaDataEntry(key, new_value)
|
||||||
|
|
||||||
|
## This method checks if the name of the group stored in the definition container is correct.
|
||||||
|
# After updating from 3.2 to 3.3 some group names may be temporary. If there is a mismatch in the name of the group
|
||||||
|
# then all the container stacks are updated, both the current and the hidden ones.
|
||||||
|
def checkCorrectGroupName(self, device_id: str, group_name: str):
|
||||||
|
if self._global_container_stack and device_id == self.activeMachineNetworkKey:
|
||||||
|
# Check if the connect_group_name is correct. If not, update all the containers connected to the same printer
|
||||||
|
if self.activeMachineNetworkGroupName != group_name:
|
||||||
|
metadata_filter = {"um_network_key": self.activeMachineNetworkKey}
|
||||||
|
hidden_containers = ContainerRegistry.getInstance().findContainerStacks(type = "machine", **metadata_filter)
|
||||||
|
for container in hidden_containers:
|
||||||
|
container.setMetaDataEntry("connect_group_name", group_name)
|
||||||
|
|
||||||
@pyqtSlot("QVariant")
|
@pyqtSlot("QVariant")
|
||||||
def setGlobalVariant(self, container_node):
|
def setGlobalVariant(self, container_node):
|
||||||
self.blurSettings.emit()
|
self.blurSettings.emit()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
|
from PyQt5.QtCore import QObject, QTimer, pyqtProperty, pyqtSignal
|
||||||
from UM.FlameProfiler import pyqtSlot
|
from UM.FlameProfiler import pyqtSlot
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
@ -30,6 +30,11 @@ class SettingInheritanceManager(QObject):
|
|||||||
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
|
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
|
||||||
self._onActiveExtruderChanged()
|
self._onActiveExtruderChanged()
|
||||||
|
|
||||||
|
self._update_timer = QTimer()
|
||||||
|
self._update_timer.setInterval(500)
|
||||||
|
self._update_timer.setSingleShot(True)
|
||||||
|
self._update_timer.timeout.connect(self._update)
|
||||||
|
|
||||||
settingsWithIntheritanceChanged = pyqtSignal()
|
settingsWithIntheritanceChanged = pyqtSignal()
|
||||||
|
|
||||||
## Get the keys of all children settings with an override.
|
## Get the keys of all children settings with an override.
|
||||||
@ -226,9 +231,7 @@ class SettingInheritanceManager(QObject):
|
|||||||
self._onActiveExtruderChanged()
|
self._onActiveExtruderChanged()
|
||||||
|
|
||||||
def _onContainersChanged(self, container):
|
def _onContainersChanged(self, container):
|
||||||
# TODO: Multiple container changes in sequence now cause quite a few recalculations.
|
self._update_timer.start()
|
||||||
# This isn't that big of an issue, but it could be in the future.
|
|
||||||
self._update()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def createSettingInheritanceManager(engine=None, script_engine=None):
|
def createSettingInheritanceManager(engine=None, script_engine=None):
|
||||||
|
@ -66,7 +66,7 @@ class Snapshot:
|
|||||||
size = max(bbox.width, bbox.height, bbox.depth * 0.5)
|
size = max(bbox.width, bbox.height, bbox.depth * 0.5)
|
||||||
|
|
||||||
# Looking from this direction (x, y, z) in OGL coordinates
|
# Looking from this direction (x, y, z) in OGL coordinates
|
||||||
looking_from_offset = Vector(1, 1, -2)
|
looking_from_offset = Vector(-1, 1, 2)
|
||||||
if size > 0:
|
if size > 0:
|
||||||
# determine the watch distance depending on the size
|
# determine the watch distance depending on the size
|
||||||
looking_from_offset = looking_from_offset * size * 1.3
|
looking_from_offset = looking_from_offset * size * 1.3
|
||||||
|
@ -122,7 +122,7 @@ class ThreeMFReader(MeshReader):
|
|||||||
um_node.callDecoration("setActiveExtruder", default_stack.getId())
|
um_node.callDecoration("setActiveExtruder", default_stack.getId())
|
||||||
|
|
||||||
# Get the definition & set it
|
# Get the definition & set it
|
||||||
definition_id = getMachineDefinitionIDForQualitySearch(global_container_stack)
|
definition_id = getMachineDefinitionIDForQualitySearch(global_container_stack.definition)
|
||||||
um_node.callDecoration("getStack").getTop().setDefinition(definition_id)
|
um_node.callDecoration("getStack").getTop().setDefinition(definition_id)
|
||||||
|
|
||||||
setting_container = um_node.callDecoration("getStack").getTop()
|
setting_container = um_node.callDecoration("getStack").getTop()
|
||||||
|
@ -594,7 +594,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
Logger.log("w", "Workspace did not contain visible settings. Leaving visibility unchanged")
|
Logger.log("w", "Workspace did not contain visible settings. Leaving visibility unchanged")
|
||||||
else:
|
else:
|
||||||
global_preferences.setValue("general/visible_settings", visible_settings)
|
global_preferences.setValue("general/visible_settings", visible_settings)
|
||||||
global_preferences.setValue("general/preset_setting_visibility_choice", "Custom")
|
global_preferences.setValue("cura/active_setting_visibility_preset", "custom")
|
||||||
|
|
||||||
categories_expanded = temp_preferences.getValue("cura/categories_expanded")
|
categories_expanded = temp_preferences.getValue("cura/categories_expanded")
|
||||||
if categories_expanded is None:
|
if categories_expanded is None:
|
||||||
@ -719,7 +719,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
|
|
||||||
# Get the correct extruder definition IDs for quality changes
|
# Get the correct extruder definition IDs for quality changes
|
||||||
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
|
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
|
||||||
machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack)
|
machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack.definition)
|
||||||
machine_definition_for_quality = self._container_registry.findDefinitionContainers(id = machine_definition_id_for_quality)[0]
|
machine_definition_for_quality = self._container_registry.findDefinitionContainers(id = machine_definition_id_for_quality)[0]
|
||||||
|
|
||||||
quality_changes_info = self._machine_info.quality_changes_info
|
quality_changes_info = self._machine_info.quality_changes_info
|
||||||
|
@ -158,6 +158,7 @@ class SimulationView(View):
|
|||||||
return self._nozzle_node
|
return self._nozzle_node
|
||||||
|
|
||||||
def _onSceneChanged(self, node):
|
def _onSceneChanged(self, node):
|
||||||
|
if node.getMeshData() is not None:
|
||||||
self.setActivity(False)
|
self.setActivity(False)
|
||||||
self.calculateMaxLayers()
|
self.calculateMaxLayers()
|
||||||
self.calculateMaxPathsOnLayer(self._current_layer_num)
|
self.calculateMaxPathsOnLayer(self._current_layer_num)
|
||||||
|
@ -22,7 +22,7 @@ from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QObject
|
|||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional, Dict, List
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@ -79,7 +79,6 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
|
|
||||||
self._latest_reply_handler = None
|
self._latest_reply_handler = None
|
||||||
|
|
||||||
|
|
||||||
def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs):
|
def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs):
|
||||||
self.writeStarted.emit(self)
|
self.writeStarted.emit(self)
|
||||||
|
|
||||||
@ -116,7 +115,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def sendPrintJob(self, target_printer = ""):
|
def sendPrintJob(self, target_printer: str = ""):
|
||||||
Logger.log("i", "Sending print job to printer.")
|
Logger.log("i", "Sending print job to printer.")
|
||||||
if self._sending_gcode:
|
if self._sending_gcode:
|
||||||
self._error_message = Message(
|
self._error_message = Message(
|
||||||
@ -157,11 +156,11 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@pyqtProperty(QObject, notify=activePrinterChanged)
|
@pyqtProperty(QObject, notify=activePrinterChanged)
|
||||||
def activePrinter(self) -> Optional["PrinterOutputModel"]:
|
def activePrinter(self) -> Optional[PrinterOutputModel]:
|
||||||
return self._active_printer
|
return self._active_printer
|
||||||
|
|
||||||
@pyqtSlot(QObject)
|
@pyqtSlot(QObject)
|
||||||
def setActivePrinter(self, printer):
|
def setActivePrinter(self, printer: Optional[PrinterOutputModel]):
|
||||||
if self._active_printer != printer:
|
if self._active_printer != printer:
|
||||||
if self._active_printer and self._active_printer.camera:
|
if self._active_printer and self._active_printer.camera:
|
||||||
self._active_printer.camera.stop()
|
self._active_printer.camera.stop()
|
||||||
@ -173,7 +172,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
self._compressing_gcode = False
|
self._compressing_gcode = False
|
||||||
self._sending_gcode = False
|
self._sending_gcode = False
|
||||||
|
|
||||||
def _onUploadPrintJobProgress(self, bytes_sent, bytes_total):
|
def _onUploadPrintJobProgress(self, bytes_sent:int, bytes_total:int):
|
||||||
if bytes_total > 0:
|
if bytes_total > 0:
|
||||||
new_progress = bytes_sent / bytes_total * 100
|
new_progress = bytes_sent / bytes_total * 100
|
||||||
# Treat upload progress as response. Uploading can take more than 10 seconds, so if we don't, we can get
|
# Treat upload progress as response. Uploading can take more than 10 seconds, so if we don't, we can get
|
||||||
@ -186,7 +185,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
self._progress_message.setProgress(0)
|
self._progress_message.setProgress(0)
|
||||||
self._progress_message.hide()
|
self._progress_message.hide()
|
||||||
|
|
||||||
def _progressMessageActionTriggered(self, message_id=None, action_id=None):
|
def _progressMessageActionTriggered(self, message_id: Optional[str]=None, action_id: Optional[str]=None) -> None:
|
||||||
if action_id == "Abort":
|
if action_id == "Abort":
|
||||||
Logger.log("d", "User aborted sending print to remote.")
|
Logger.log("d", "User aborted sending print to remote.")
|
||||||
self._progress_message.hide()
|
self._progress_message.hide()
|
||||||
@ -202,29 +201,29 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def openPrintJobControlPanel(self):
|
def openPrintJobControlPanel(self) -> None:
|
||||||
Logger.log("d", "Opening print job control panel...")
|
Logger.log("d", "Opening print job control panel...")
|
||||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/print_jobs"))
|
QDesktopServices.openUrl(QUrl("http://" + self._address + "/print_jobs"))
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def openPrinterControlPanel(self):
|
def openPrinterControlPanel(self) -> None:
|
||||||
Logger.log("d", "Opening printer control panel...")
|
Logger.log("d", "Opening printer control panel...")
|
||||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
|
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
|
||||||
|
|
||||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
||||||
def printJobs(self):
|
def printJobs(self)-> List[PrintJobOutputModel] :
|
||||||
return self._print_jobs
|
return self._print_jobs
|
||||||
|
|
||||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
||||||
def queuedPrintJobs(self):
|
def queuedPrintJobs(self) -> List[PrintJobOutputModel]:
|
||||||
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is None or print_job.state == "queued"]
|
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is None or print_job.state == "queued"]
|
||||||
|
|
||||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
||||||
def activePrintJobs(self):
|
def activePrintJobs(self) -> List[PrintJobOutputModel]:
|
||||||
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None and print_job.state != "queued"]
|
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None and print_job.state != "queued"]
|
||||||
|
|
||||||
@pyqtProperty("QVariantList", notify=clusterPrintersChanged)
|
@pyqtProperty("QVariantList", notify=clusterPrintersChanged)
|
||||||
def connectedPrintersTypeCount(self):
|
def connectedPrintersTypeCount(self) -> List[PrinterOutputModel]:
|
||||||
printer_count = {}
|
printer_count = {}
|
||||||
for printer in self._printers:
|
for printer in self._printers:
|
||||||
if printer.type in printer_count:
|
if printer.type in printer_count:
|
||||||
@ -237,22 +236,22 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
@pyqtSlot(int, result=str)
|
@pyqtSlot(int, result=str)
|
||||||
def formatDuration(self, seconds):
|
def formatDuration(self, seconds: int) -> str:
|
||||||
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
|
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
|
||||||
|
|
||||||
@pyqtSlot(int, result=str)
|
@pyqtSlot(int, result=str)
|
||||||
def getTimeCompleted(self, time_remaining):
|
def getTimeCompleted(self, time_remaining: int) -> str:
|
||||||
current_time = time()
|
current_time = time()
|
||||||
datetime_completed = datetime.fromtimestamp(current_time + time_remaining)
|
datetime_completed = datetime.fromtimestamp(current_time + time_remaining)
|
||||||
return "{hour:02d}:{minute:02d}".format(hour=datetime_completed.hour, minute=datetime_completed.minute)
|
return "{hour:02d}:{minute:02d}".format(hour=datetime_completed.hour, minute=datetime_completed.minute)
|
||||||
|
|
||||||
@pyqtSlot(int, result=str)
|
@pyqtSlot(int, result=str)
|
||||||
def getDateCompleted(self, time_remaining):
|
def getDateCompleted(self, time_remaining: int) -> str:
|
||||||
current_time = time()
|
current_time = time()
|
||||||
datetime_completed = datetime.fromtimestamp(current_time + time_remaining)
|
datetime_completed = datetime.fromtimestamp(current_time + time_remaining)
|
||||||
return (datetime_completed.strftime("%a %b ") + "{day}".format(day=datetime_completed.day)).upper()
|
return (datetime_completed.strftime("%a %b ") + "{day}".format(day=datetime_completed.day)).upper()
|
||||||
|
|
||||||
def _printJobStateChanged(self):
|
def _printJobStateChanged(self) -> None:
|
||||||
username = self._getUserName()
|
username = self._getUserName()
|
||||||
|
|
||||||
if username is None:
|
if username is None:
|
||||||
@ -275,13 +274,13 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
# Keep a list of all completed jobs so we know if something changed next time.
|
# Keep a list of all completed jobs so we know if something changed next time.
|
||||||
self._finished_jobs = finished_jobs
|
self._finished_jobs = finished_jobs
|
||||||
|
|
||||||
def _update(self):
|
def _update(self) -> None:
|
||||||
if not super()._update():
|
if not super()._update():
|
||||||
return
|
return
|
||||||
self.get("printers/", onFinished=self._onGetPrintersDataFinished)
|
self.get("printers/", onFinished=self._onGetPrintersDataFinished)
|
||||||
self.get("print_jobs/", onFinished=self._onGetPrintJobsFinished)
|
self.get("print_jobs/", onFinished=self._onGetPrintJobsFinished)
|
||||||
|
|
||||||
def _onGetPrintJobsFinished(self, reply: QNetworkReply):
|
def _onGetPrintJobsFinished(self, reply: QNetworkReply) -> None:
|
||||||
if not checkValidGetReply(reply):
|
if not checkValidGetReply(reply):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -323,7 +322,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
if job_list_changed:
|
if job_list_changed:
|
||||||
self.printJobsChanged.emit() # Do a single emit for all print job changes.
|
self.printJobsChanged.emit() # Do a single emit for all print job changes.
|
||||||
|
|
||||||
def _onGetPrintersDataFinished(self, reply: QNetworkReply):
|
def _onGetPrintersDataFinished(self, reply: QNetworkReply) -> None:
|
||||||
if not checkValidGetReply(reply):
|
if not checkValidGetReply(reply):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -352,31 +351,37 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
if removed_printers or printer_list_changed:
|
if removed_printers or printer_list_changed:
|
||||||
self.printersChanged.emit()
|
self.printersChanged.emit()
|
||||||
|
|
||||||
def _createPrinterModel(self, data):
|
def _createPrinterModel(self, data: Dict) -> PrinterOutputModel:
|
||||||
printer = PrinterOutputModel(output_controller=ClusterUM3PrinterOutputController(self),
|
printer = PrinterOutputModel(output_controller=ClusterUM3PrinterOutputController(self),
|
||||||
number_of_extruders=self._number_of_extruders)
|
number_of_extruders=self._number_of_extruders)
|
||||||
printer.setCamera(NetworkCamera("http://" + data["ip_address"] + ":8080/?action=stream"))
|
printer.setCamera(NetworkCamera("http://" + data["ip_address"] + ":8080/?action=stream"))
|
||||||
self._printers.append(printer)
|
self._printers.append(printer)
|
||||||
return printer
|
return printer
|
||||||
|
|
||||||
def _createPrintJobModel(self, data):
|
def _createPrintJobModel(self, data: Dict) -> PrintJobOutputModel:
|
||||||
print_job = PrintJobOutputModel(output_controller=ClusterUM3PrinterOutputController(self),
|
print_job = PrintJobOutputModel(output_controller=ClusterUM3PrinterOutputController(self),
|
||||||
key=data["uuid"], name= data["name"])
|
key=data["uuid"], name= data["name"])
|
||||||
print_job.stateChanged.connect(self._printJobStateChanged)
|
print_job.stateChanged.connect(self._printJobStateChanged)
|
||||||
self._print_jobs.append(print_job)
|
self._print_jobs.append(print_job)
|
||||||
return print_job
|
return print_job
|
||||||
|
|
||||||
def _updatePrintJob(self, print_job, data):
|
def _updatePrintJob(self, print_job: PrintJobOutputModel, data: Dict) -> None:
|
||||||
print_job.updateTimeTotal(data["time_total"])
|
print_job.updateTimeTotal(data["time_total"])
|
||||||
print_job.updateTimeElapsed(data["time_elapsed"])
|
print_job.updateTimeElapsed(data["time_elapsed"])
|
||||||
print_job.updateState(data["status"])
|
print_job.updateState(data["status"])
|
||||||
print_job.updateOwner(data["owner"])
|
print_job.updateOwner(data["owner"])
|
||||||
|
|
||||||
def _updatePrinter(self, printer, data):
|
def _updatePrinter(self, printer: PrinterOutputModel, data: Dict) -> None:
|
||||||
# For some unknown reason the cluster wants UUID for everything, except for sending a job directly to a printer.
|
# For some unknown reason the cluster wants UUID for everything, except for sending a job directly to a printer.
|
||||||
# Then we suddenly need the unique name. So in order to not have to mess up all the other code, we save a mapping.
|
# Then we suddenly need the unique name. So in order to not have to mess up all the other code, we save a mapping.
|
||||||
self._printer_uuid_to_unique_name_mapping[data["uuid"]] = data["unique_name"]
|
self._printer_uuid_to_unique_name_mapping[data["uuid"]] = data["unique_name"]
|
||||||
machine_definition = ContainerRegistry.getInstance().findDefinitionContainers(name = data["machine_variant"])[0]
|
|
||||||
|
definitions = ContainerRegistry.getInstance().findDefinitionContainers(name = data["machine_variant"])
|
||||||
|
if not definitions:
|
||||||
|
Logger.log("w", "Unable to find definition for machine variant %s", data["machine_variant"])
|
||||||
|
return
|
||||||
|
|
||||||
|
machine_definition = definitions[0]
|
||||||
|
|
||||||
printer.updateName(data["friendly_name"])
|
printer.updateName(data["friendly_name"])
|
||||||
printer.updateKey(data["uuid"])
|
printer.updateKey(data["uuid"])
|
||||||
@ -421,7 +426,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
brand=brand, color=color, name=name)
|
brand=brand, color=color, name=name)
|
||||||
extruder.updateActiveMaterial(material)
|
extruder.updateActiveMaterial(material)
|
||||||
|
|
||||||
def _removeJob(self, job):
|
def _removeJob(self, job: PrintJobOutputModel):
|
||||||
if job not in self._print_jobs:
|
if job not in self._print_jobs:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -432,7 +437,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _removePrinter(self, printer):
|
def _removePrinter(self, printer: PrinterOutputModel):
|
||||||
self._printers.remove(printer)
|
self._printers.remove(printer)
|
||||||
if self._active_printer == printer:
|
if self._active_printer == printer:
|
||||||
self._active_printer = None
|
self._active_printer = None
|
||||||
|
@ -82,6 +82,9 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
|
|||||||
self._zero_conf_browser.cancel()
|
self._zero_conf_browser.cancel()
|
||||||
self._zero_conf_browser = None # Force the old ServiceBrowser to be destroyed.
|
self._zero_conf_browser = None # Force the old ServiceBrowser to be destroyed.
|
||||||
|
|
||||||
|
for instance_name in list(self._discovered_devices):
|
||||||
|
self._onRemoveDevice(instance_name)
|
||||||
|
|
||||||
self._zero_conf = Zeroconf()
|
self._zero_conf = Zeroconf()
|
||||||
self._zero_conf_browser = ServiceBrowser(self._zero_conf, u'_ultimaker._tcp.local.',
|
self._zero_conf_browser = ServiceBrowser(self._zero_conf, u'_ultimaker._tcp.local.',
|
||||||
[self._appendServiceChangedRequest])
|
[self._appendServiceChangedRequest])
|
||||||
|
@ -22,6 +22,7 @@ class AutoDetectBaudJob(Job):
|
|||||||
def run(self):
|
def run(self):
|
||||||
Logger.log("d", "Auto detect baud rate started.")
|
Logger.log("d", "Auto detect baud rate started.")
|
||||||
timeout = 3
|
timeout = 3
|
||||||
|
tries = 2
|
||||||
|
|
||||||
programmer = Stk500v2()
|
programmer = Stk500v2()
|
||||||
serial = None
|
serial = None
|
||||||
@ -31,6 +32,7 @@ class AutoDetectBaudJob(Job):
|
|||||||
except:
|
except:
|
||||||
programmer.close()
|
programmer.close()
|
||||||
|
|
||||||
|
for retry in range(tries):
|
||||||
for baud_rate in self._all_baud_rates:
|
for baud_rate in self._all_baud_rates:
|
||||||
Logger.log("d", "Checking {serial} if baud rate {baud_rate} works".format(serial= self._serial_port, baud_rate = baud_rate))
|
Logger.log("d", "Checking {serial} if baud rate {baud_rate} works".format(serial= self._serial_port, baud_rate = baud_rate))
|
||||||
|
|
||||||
@ -63,4 +65,5 @@ class AutoDetectBaudJob(Job):
|
|||||||
return
|
return
|
||||||
|
|
||||||
serial.write(b"M105\n")
|
serial.write(b"M105\n")
|
||||||
|
sleep(15) # Give the printer some time to init and try again.
|
||||||
self.setResult(None) # Unable to detect the correct baudrate.
|
self.setResult(None) # Unable to detect the correct baudrate.
|
||||||
|
@ -116,7 +116,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def updateFirmware(self, file):
|
def updateFirmware(self, file):
|
||||||
self._firmware_location = file
|
# the file path is qurl encoded.
|
||||||
|
self._firmware_location = file.replace("file://", "")
|
||||||
self.showFirmwareInterface()
|
self.showFirmwareInterface()
|
||||||
self.setFirmwareUpdateState(FirmwareUpdateState.updating)
|
self.setFirmwareUpdateState(FirmwareUpdateState.updating)
|
||||||
self._update_firmware_thread.start()
|
self._update_firmware_thread.start()
|
||||||
@ -126,9 +127,11 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
if self._connection_state != ConnectionState.closed:
|
if self._connection_state != ConnectionState.closed:
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
try:
|
||||||
hex_file = intelHex.readHex(self._firmware_location)
|
hex_file = intelHex.readHex(self._firmware_location)
|
||||||
if len(hex_file) == 0:
|
assert len(hex_file) > 0
|
||||||
Logger.log("e", "Unable to read provided hex file. Could not update firmware")
|
except (FileNotFoundError, AssertionError):
|
||||||
|
Logger.log("e", "Unable to read provided hex file. Could not update firmware.")
|
||||||
self.setFirmwareUpdateState(FirmwareUpdateState.firmware_not_found_error)
|
self.setFirmwareUpdateState(FirmwareUpdateState.firmware_not_found_error)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -198,7 +201,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
# Reset line number. If this is not done, first line is sometimes ignored
|
# Reset line number. If this is not done, first line is sometimes ignored
|
||||||
self._gcode.insert(0, "M110")
|
self._gcode.insert(0, "M110")
|
||||||
self._gcode_position = 0
|
self._gcode_position = 0
|
||||||
self._is_printing = True
|
|
||||||
self._print_start_time = time()
|
self._print_start_time = time()
|
||||||
|
|
||||||
self._print_estimated_time = int(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.Seconds))
|
self._print_estimated_time = int(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.Seconds))
|
||||||
@ -206,6 +208,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
for i in range(0, 4): # Push first 4 entries before accepting other inputs
|
for i in range(0, 4): # Push first 4 entries before accepting other inputs
|
||||||
self._sendNextGcodeLine()
|
self._sendNextGcodeLine()
|
||||||
|
|
||||||
|
self._is_printing = True
|
||||||
self.writeFinished.emit(self)
|
self.writeFinished.emit(self)
|
||||||
|
|
||||||
def _autoDetectFinished(self, job: AutoDetectBaudJob):
|
def _autoDetectFinished(self, job: AutoDetectBaudJob):
|
||||||
@ -267,7 +270,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
if not command.endswith(b"\n"):
|
if not command.endswith(b"\n"):
|
||||||
command += b"\n"
|
command += b"\n"
|
||||||
try:
|
try:
|
||||||
self._serial.write(b"\n")
|
|
||||||
self._serial.write(command)
|
self._serial.write(command)
|
||||||
except SerialTimeoutException:
|
except SerialTimeoutException:
|
||||||
Logger.log("w", "Timeout when sending command to printer via USB.")
|
Logger.log("w", "Timeout when sending command to printer via USB.")
|
||||||
@ -284,7 +286,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
self.sendCommand("M105")
|
self.sendCommand("M105")
|
||||||
self._last_temperature_request = time()
|
self._last_temperature_request = time()
|
||||||
|
|
||||||
if b"ok T:" in line or line.startswith(b"T:"): # Temperature message
|
if b"ok T:" in line or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed
|
||||||
extruder_temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line)
|
extruder_temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line)
|
||||||
# Update all temperature values
|
# Update all temperature values
|
||||||
for match, extruder in zip(extruder_temperature_matches, self._printers[0].extruders):
|
for match, extruder in zip(extruder_temperature_matches, self._printers[0].extruders):
|
||||||
@ -302,6 +304,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||||||
self._printers[0].updateTargetBedTemperature(float(match[1]))
|
self._printers[0].updateTargetBedTemperature(float(match[1]))
|
||||||
|
|
||||||
if self._is_printing:
|
if self._is_printing:
|
||||||
|
if line.startswith(b'!!'):
|
||||||
|
Logger.log('e', "Printer signals fatal error. Cancelling print. {}".format(line))
|
||||||
|
self.cancelPrint()
|
||||||
if b"ok" in line:
|
if b"ok" in line:
|
||||||
if not self._command_queue.empty():
|
if not self._command_queue.empty():
|
||||||
self._sendCommand(self._command_queue.get())
|
self._sendCommand(self._command_queue.get())
|
||||||
|
@ -56,6 +56,8 @@ _EXTRUDER_TO_POSITION = {
|
|||||||
## Upgrades configurations from the state they were in at version 3.2 to the
|
## Upgrades configurations from the state they were in at version 3.2 to the
|
||||||
# state they should be in at version 3.3.
|
# state they should be in at version 3.3.
|
||||||
class VersionUpgrade32to33(VersionUpgrade):
|
class VersionUpgrade32to33(VersionUpgrade):
|
||||||
|
|
||||||
|
temporary_group_name_counter = 1
|
||||||
## Gets the version number from a CFG file in Uranium's 3.2 format.
|
## Gets the version number from a CFG file in Uranium's 3.2 format.
|
||||||
#
|
#
|
||||||
# Since the format may change, this is implemented for the 3.2 format only
|
# Since the format may change, this is implemented for the 3.2 format only
|
||||||
@ -74,6 +76,28 @@ class VersionUpgrade32to33(VersionUpgrade):
|
|||||||
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
|
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
|
||||||
return format_version * 1000000 + setting_version
|
return format_version * 1000000 + setting_version
|
||||||
|
|
||||||
|
## Upgrades a container stack from version 3.2 to 3.3.
|
||||||
|
#
|
||||||
|
# \param serialised The serialised form of a container stack.
|
||||||
|
# \param filename The name of the file to upgrade.
|
||||||
|
def upgradeStack(self, serialized, filename):
|
||||||
|
parser = configparser.ConfigParser(interpolation = None)
|
||||||
|
parser.read_string(serialized)
|
||||||
|
|
||||||
|
if "metadata" in parser and "um_network_key" in parser["metadata"]:
|
||||||
|
if "hidden" not in parser["metadata"]:
|
||||||
|
parser["metadata"]["hidden"] = "False"
|
||||||
|
if "connect_group_name" not in parser["metadata"]:
|
||||||
|
parser["metadata"]["connect_group_name"] = "Temporary group name #" + str(self.temporary_group_name_counter)
|
||||||
|
self.temporary_group_name_counter += 1
|
||||||
|
|
||||||
|
#Update version number.
|
||||||
|
parser["general"]["version"] = "4"
|
||||||
|
|
||||||
|
result = io.StringIO()
|
||||||
|
parser.write(result)
|
||||||
|
return [filename], [result.getvalue()]
|
||||||
|
|
||||||
## Upgrades non-quality-changes instance containers to have the new version
|
## Upgrades non-quality-changes instance containers to have the new version
|
||||||
# number.
|
# number.
|
||||||
def upgradeInstanceContainer(self, serialized, filename):
|
def upgradeInstanceContainer(self, serialized, filename):
|
||||||
|
@ -9,11 +9,22 @@ def getMetaData():
|
|||||||
return {
|
return {
|
||||||
"version_upgrade": {
|
"version_upgrade": {
|
||||||
# From To Upgrade function
|
# From To Upgrade function
|
||||||
|
("machine_stack", 3000004): ("machine_stack", 4000004, upgrade.upgradeStack),
|
||||||
|
("extruder_train", 3000004): ("extruder_train", 4000004, upgrade.upgradeStack),
|
||||||
|
|
||||||
("definition_changes", 2000004): ("definition_changes", 3000004, upgrade.upgradeInstanceContainer),
|
("definition_changes", 2000004): ("definition_changes", 3000004, upgrade.upgradeInstanceContainer),
|
||||||
("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges),
|
("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges),
|
||||||
("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer)
|
("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer)
|
||||||
},
|
},
|
||||||
"sources": {
|
"sources": {
|
||||||
|
"machine_stack": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"./machine_instances"}
|
||||||
|
},
|
||||||
|
"extruder_train": {
|
||||||
|
"get_version": upgrade.getCfgVersion,
|
||||||
|
"location": {"./extruders"}
|
||||||
|
},
|
||||||
"definition_changes": {
|
"definition_changes": {
|
||||||
"get_version": upgrade.getCfgVersion,
|
"get_version": upgrade.getCfgVersion,
|
||||||
"location": {"./definition_changes"}
|
"location": {"./definition_changes"}
|
||||||
|
@ -208,14 +208,9 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
machine_variant_map = {}
|
machine_variant_map = {}
|
||||||
|
|
||||||
variant_manager = CuraApplication.getInstance().getVariantManager()
|
variant_manager = CuraApplication.getInstance().getVariantManager()
|
||||||
material_manager = CuraApplication.getInstance().getMaterialManager()
|
|
||||||
|
|
||||||
root_material_id = self.getMetaDataEntry("base_file") # if basefile is self.getId, this is a basefile.
|
root_material_id = self.getMetaDataEntry("base_file") # if basefile is self.getId, this is a basefile.
|
||||||
material_group = material_manager.getMaterialGroup(root_material_id)
|
all_containers = registry.findInstanceContainers(base_file = root_material_id)
|
||||||
|
|
||||||
all_containers = []
|
|
||||||
for node in [material_group.root_material_node] + material_group.derived_material_node_list:
|
|
||||||
all_containers.append(node.getContainer())
|
|
||||||
|
|
||||||
for container in all_containers:
|
for container in all_containers:
|
||||||
definition_id = container.getMetaDataEntry("definition")
|
definition_id = container.getMetaDataEntry("definition")
|
||||||
@ -242,7 +237,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
|
|
||||||
for definition_id, container in machine_container_map.items():
|
for definition_id, container in machine_container_map.items():
|
||||||
definition_id = container.getMetaDataEntry("definition")
|
definition_id = container.getMetaDataEntry("definition")
|
||||||
definition_metadata = ContainerRegistry.getInstance().findDefinitionContainersMetadata(id = definition_id)[0]
|
definition_metadata = registry.findDefinitionContainersMetadata(id = definition_id)[0]
|
||||||
|
|
||||||
product = definition_id
|
product = definition_id
|
||||||
for product_name, product_id_list in product_id_map.items():
|
for product_name, product_id_list in product_id_map.items():
|
||||||
|
@ -632,6 +632,73 @@
|
|||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": false
|
"settable_per_meshgroup": false
|
||||||
},
|
},
|
||||||
|
"machine_steps_per_mm_x":
|
||||||
|
{
|
||||||
|
"label": "Steps per Millimeter (X)",
|
||||||
|
"description": "How many steps of the stepper motor will result in one millimeter of movement in the X direction.",
|
||||||
|
"type": "int",
|
||||||
|
"default_value": 50,
|
||||||
|
"minimum_value": "0.0000001",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"machine_steps_per_mm_y":
|
||||||
|
{
|
||||||
|
"label": "Steps per Millimeter (Y)",
|
||||||
|
"description": "How many steps of the stepper motor will result in one millimeter of movement in the Y direction.",
|
||||||
|
"type": "int",
|
||||||
|
"default_value": 50,
|
||||||
|
"minimum_value": "0.0000001",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"machine_steps_per_mm_z":
|
||||||
|
{
|
||||||
|
"label": "Steps per Millimeter (Z)",
|
||||||
|
"description": "How many steps of the stepper motor will result in one millimeter of movement in the Z direction.",
|
||||||
|
"type": "int",
|
||||||
|
"default_value": 50,
|
||||||
|
"minimum_value": "0.0000001",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"machine_steps_per_mm_e":
|
||||||
|
{
|
||||||
|
"label": "Steps per Millimeter (E)",
|
||||||
|
"description": "How many steps of the stepper motors will result in one millimeter of extrusion.",
|
||||||
|
"type": "int",
|
||||||
|
"default_value": 1600,
|
||||||
|
"minimum_value": "0.0000001",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"machine_endstop_positive_direction_x":
|
||||||
|
{
|
||||||
|
"label": "X Endstop in Positive Direction",
|
||||||
|
"description": "Whether the endstop of the X axis is in the positive direction (high X coordinate) or negative (low X coordinate).",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"machine_endstop_positive_direction_y":
|
||||||
|
{
|
||||||
|
"label": "Y Endstop in Positive Direction",
|
||||||
|
"description": "Whether the endstop of the Y axis is in the positive direction (high Y coordinate) or negative (low Y coordinate).",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"machine_endstop_positive_direction_z":
|
||||||
|
{
|
||||||
|
"label": "Z Endstop in Positive Direction",
|
||||||
|
"description": "Whether the endstop of the Z axis is in the positive direction (high Z coordinate) or negative (low Z coordinate).",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": true,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
"machine_minimum_feedrate":
|
"machine_minimum_feedrate":
|
||||||
{
|
{
|
||||||
"label": "Minimum Feedrate",
|
"label": "Minimum Feedrate",
|
||||||
@ -642,6 +709,16 @@
|
|||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": false
|
"settable_per_meshgroup": false
|
||||||
|
},
|
||||||
|
"machine_feeder_wheel_diameter":
|
||||||
|
{
|
||||||
|
"label": "Feeder Wheel Diameter",
|
||||||
|
"description": "The diameter of the wheel that drives the material in the feeder.",
|
||||||
|
"unit": "mm",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 10.0,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -25,8 +25,7 @@
|
|||||||
"default_value": true
|
"default_value": true
|
||||||
},
|
},
|
||||||
"machine_nozzle_size": {
|
"machine_nozzle_size": {
|
||||||
"default_value": 0.4,
|
"default_value": 0.4
|
||||||
"minimum_value": "0.001"
|
|
||||||
},
|
},
|
||||||
"machine_head_with_fans_polygon": {
|
"machine_head_with_fans_polygon": {
|
||||||
"default_value": [
|
"default_value": [
|
||||||
@ -36,6 +35,21 @@
|
|||||||
[ 18, 35 ]
|
[ 18, 35 ]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"machine_max_feedrate_z": {
|
||||||
|
"default_value": 400
|
||||||
|
},
|
||||||
|
"machine_steps_per_mm_x": {
|
||||||
|
"default_value": 93
|
||||||
|
},
|
||||||
|
"machine_steps_per_mm_y": {
|
||||||
|
"default_value": 93
|
||||||
|
},
|
||||||
|
"machine_steps_per_mm_z": {
|
||||||
|
"default_value": 1600
|
||||||
|
},
|
||||||
|
"machine_steps_per_mm_e": {
|
||||||
|
"default_value": 92
|
||||||
|
},
|
||||||
"gantry_height": {
|
"gantry_height": {
|
||||||
"default_value": 55
|
"default_value": 55
|
||||||
},
|
},
|
||||||
|
@ -217,6 +217,7 @@ UM.MainWindow
|
|||||||
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
|
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
|
||||||
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
|
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
|
||||||
visible: Cura.MachineManager.getExtruder(model.index).isEnabled
|
visible: Cura.MachineManager.getExtruder(model.index).isEnabled
|
||||||
|
enabled: Cura.MachineManager.numberExtrudersEnabled > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -653,9 +654,12 @@ UM.MainWindow
|
|||||||
{
|
{
|
||||||
preferences.visible = true;
|
preferences.visible = true;
|
||||||
preferences.setPage(1);
|
preferences.setPage(1);
|
||||||
|
if(source && source.key)
|
||||||
|
{
|
||||||
preferences.getCurrentItem().scrollToSection(source.key);
|
preferences.getCurrentItem().scrollToSection(source.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UM.ExtensionModel {
|
UM.ExtensionModel {
|
||||||
id: curaExtensions
|
id: curaExtensions
|
||||||
|
@ -10,17 +10,22 @@ import UM 1.2 as UM
|
|||||||
import Cura 1.0 as Cura
|
import Cura 1.0 as Cura
|
||||||
import "Menus"
|
import "Menus"
|
||||||
|
|
||||||
ToolButton {
|
ToolButton
|
||||||
|
{
|
||||||
id: base
|
id: base
|
||||||
property var isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != ""
|
property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != ""
|
||||||
|
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
||||||
property var printerStatus: Cura.MachineManager.printerOutputDevices.length != 0 ? "connected" : "disconnected"
|
property var printerStatus: Cura.MachineManager.printerOutputDevices.length != 0 ? "connected" : "disconnected"
|
||||||
text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName
|
text: isNetworkPrinter ? Cura.MachineManager.activeMachineNetworkGroupName : Cura.MachineManager.activeMachineName
|
||||||
|
|
||||||
tooltip: Cura.MachineManager.activeMachineName
|
tooltip: Cura.MachineManager.activeMachineName
|
||||||
|
|
||||||
style: ButtonStyle {
|
style: ButtonStyle
|
||||||
background: Rectangle {
|
{
|
||||||
color: {
|
background: Rectangle
|
||||||
|
{
|
||||||
|
color:
|
||||||
|
{
|
||||||
if (control.pressed) {
|
if (control.pressed) {
|
||||||
return UM.Theme.getColor("sidebar_header_active");
|
return UM.Theme.getColor("sidebar_header_active");
|
||||||
}
|
}
|
||||||
@ -33,7 +38,8 @@ ToolButton {
|
|||||||
}
|
}
|
||||||
Behavior on color { ColorAnimation { duration: 50; } }
|
Behavior on color { ColorAnimation { duration: 50; } }
|
||||||
|
|
||||||
UM.RecolorImage {
|
UM.RecolorImage
|
||||||
|
{
|
||||||
id: downArrow
|
id: downArrow
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@ -46,24 +52,27 @@ ToolButton {
|
|||||||
source: UM.Theme.getIcon("arrow_bottom")
|
source: UM.Theme.getIcon("arrow_bottom")
|
||||||
}
|
}
|
||||||
|
|
||||||
PrinterStatusIcon {
|
PrinterStatusIcon
|
||||||
|
{
|
||||||
id: printerStatusIcon
|
id: printerStatusIcon
|
||||||
visible: isNetworkPrinter
|
visible: printerConnected || isNetworkPrinter
|
||||||
status: printerStatus
|
status: printerStatus
|
||||||
anchors {
|
anchors
|
||||||
|
{
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.verticalCenter
|
||||||
left: parent.left
|
left: parent.left
|
||||||
leftMargin: UM.Theme.getSize("sidebar_margin").width
|
leftMargin: UM.Theme.getSize("sidebar_margin").width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label
|
||||||
|
{
|
||||||
id: sidebarComboBoxLabel
|
id: sidebarComboBoxLabel
|
||||||
color: UM.Theme.getColor("sidebar_header_text_active")
|
color: UM.Theme.getColor("sidebar_header_text_active")
|
||||||
text: control.text;
|
text: control.text;
|
||||||
elide: Text.ElideRight;
|
elide: Text.ElideRight;
|
||||||
anchors.left: isNetworkPrinter ? printerStatusIcon.right : parent.left;
|
anchors.left: printerStatusIcon.visible ? printerStatusIcon.right : parent.left;
|
||||||
anchors.leftMargin: isNetworkPrinter ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width
|
anchors.leftMargin: printerStatusIcon.visible ? UM.Theme.getSize("sidebar_lining").width : UM.Theme.getSize("sidebar_margin").width
|
||||||
anchors.right: downArrow.left;
|
anchors.right: downArrow.left;
|
||||||
anchors.rightMargin: control.rightMargin;
|
anchors.rightMargin: control.rightMargin;
|
||||||
anchors.verticalCenter: parent.verticalCenter;
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
@ -74,14 +83,4 @@ ToolButton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
menu: PrinterMenu { }
|
menu: PrinterMenu { }
|
||||||
|
|
||||||
// Make the toolbutton react when the outputdevice changes
|
|
||||||
Connections
|
|
||||||
{
|
|
||||||
target: Cura.MachineManager
|
|
||||||
onOutputDevicesChanged:
|
|
||||||
{
|
|
||||||
base.isNetworkPrinter = Cura.MachineManager.activeMachineNetworkKey != ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -59,13 +59,14 @@ Column
|
|||||||
section.criteria: ViewSection.FullString
|
section.criteria: ViewSection.FullString
|
||||||
section.delegate: sectionHeading
|
section.delegate: sectionHeading
|
||||||
|
|
||||||
model: (ouputDevice != null) ? outputDevice.uniqueConfigurations : []
|
model: (outputDevice != null) ? outputDevice.uniqueConfigurations : []
|
||||||
delegate: ConfigurationItem
|
delegate: ConfigurationItem
|
||||||
{
|
{
|
||||||
width: parent.width - UM.Theme.getSize("default_margin").width
|
width: parent.width - UM.Theme.getSize("default_margin").width
|
||||||
configuration: modelData
|
configuration: modelData
|
||||||
onActivateConfiguration:
|
onActivateConfiguration:
|
||||||
{
|
{
|
||||||
|
switchPopupState()
|
||||||
Cura.MachineManager.applyRemoteConfiguration(configuration)
|
Cura.MachineManager.applyRemoteConfiguration(configuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,54 +13,53 @@ Item
|
|||||||
id: configurationSelector
|
id: configurationSelector
|
||||||
property var connectedDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
|
property var connectedDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
|
||||||
property var panelWidth: control.width
|
property var panelWidth: control.width
|
||||||
property var panelVisible: false
|
|
||||||
|
|
||||||
SyncButton {
|
function switchPopupState()
|
||||||
onClicked: configurationSelector.state == "open" ? configurationSelector.state = "closed" : configurationSelector.state = "open"
|
{
|
||||||
|
popup.visible ? popup.close() : popup.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncButton
|
||||||
|
{
|
||||||
|
id: syncButton
|
||||||
|
onClicked: switchPopupState()
|
||||||
outputDevice: connectedDevice
|
outputDevice: connectedDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
Popup {
|
Popup
|
||||||
|
{
|
||||||
|
// TODO Change once updating to Qt5.10 - The 'opened' property is in 5.10 but the behavior is now implemented with the visible property
|
||||||
id: popup
|
id: popup
|
||||||
clip: true
|
clip: true
|
||||||
|
closePolicy: Popup.CloseOnPressOutsideParent
|
||||||
y: configurationSelector.height - UM.Theme.getSize("default_lining").height
|
y: configurationSelector.height - UM.Theme.getSize("default_lining").height
|
||||||
x: configurationSelector.width - width
|
x: configurationSelector.width - width
|
||||||
width: panelWidth
|
width: panelWidth
|
||||||
visible: panelVisible && connectedDevice != null
|
visible: false
|
||||||
padding: UM.Theme.getSize("default_lining").width
|
padding: UM.Theme.getSize("default_lining").width
|
||||||
contentItem: ConfigurationListView {
|
transformOrigin: Popup.Top
|
||||||
|
contentItem: ConfigurationListView
|
||||||
|
{
|
||||||
id: configList
|
id: configList
|
||||||
width: panelWidth - 2 * popup.padding
|
width: panelWidth - 2 * popup.padding
|
||||||
outputDevice: connectedDevice
|
outputDevice: connectedDevice
|
||||||
}
|
}
|
||||||
background: Rectangle {
|
background: Rectangle
|
||||||
|
{
|
||||||
color: UM.Theme.getColor("setting_control")
|
color: UM.Theme.getColor("setting_control")
|
||||||
border.color: UM.Theme.getColor("setting_control_border")
|
border.color: UM.Theme.getColor("setting_control_border")
|
||||||
}
|
}
|
||||||
}
|
exit: Transition
|
||||||
|
{
|
||||||
states: [
|
|
||||||
// This adds a second state to the container where the rectangle is farther to the right
|
|
||||||
State {
|
|
||||||
name: "open"
|
|
||||||
PropertyChanges {
|
|
||||||
target: popup
|
|
||||||
height: configList.computedHeight
|
|
||||||
}
|
|
||||||
},
|
|
||||||
State {
|
|
||||||
name: "closed"
|
|
||||||
PropertyChanges {
|
|
||||||
target: popup
|
|
||||||
height: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
transitions: [
|
|
||||||
// This adds a transition that defaults to applying to all state changes
|
|
||||||
Transition {
|
|
||||||
// This applies a default NumberAnimation to any changes a state change makes to x or y properties
|
// This applies a default NumberAnimation to any changes a state change makes to x or y properties
|
||||||
NumberAnimation { properties: "height"; duration: 200; easing.type: Easing.InOutQuad; }
|
NumberAnimation { property: "visible"; duration: 75; }
|
||||||
|
}
|
||||||
|
enter: Transition
|
||||||
|
{
|
||||||
|
// This applies a default NumberAnimation to any changes a state change makes to x or y properties
|
||||||
|
NumberAnimation { property: "visible"; duration: 75; }
|
||||||
|
}
|
||||||
|
onClosed: visible = false
|
||||||
|
onOpened: visible = true
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
}
|
@ -17,11 +17,15 @@ Button
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
function updateOnSync() {
|
function updateOnSync()
|
||||||
if (outputDevice != undefined) {
|
{
|
||||||
for (var index in outputDevice.uniqueConfigurations) {
|
if (outputDevice != undefined)
|
||||||
|
{
|
||||||
|
for (var index in outputDevice.uniqueConfigurations)
|
||||||
|
{
|
||||||
var configuration = outputDevice.uniqueConfigurations[index]
|
var configuration = outputDevice.uniqueConfigurations[index]
|
||||||
if (Cura.MachineManager.matchesConfiguration(configuration)) {
|
if (Cura.MachineManager.matchesConfiguration(configuration))
|
||||||
|
{
|
||||||
base.matched = true;
|
base.matched = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -82,11 +86,6 @@ Button
|
|||||||
label: Label {}
|
label: Label {}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked:
|
|
||||||
{
|
|
||||||
panelVisible = !panelVisible
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: outputDevice
|
target: outputDevice
|
||||||
onUniqueConfigurationsChanged: {
|
onUniqueConfigurationsChanged: {
|
||||||
|
@ -31,7 +31,7 @@ Menu
|
|||||||
MenuItem {
|
MenuItem {
|
||||||
text: "%1: %2 - %3".arg(model.name).arg(model.material).arg(model.variant)
|
text: "%1: %2 - %3".arg(model.name).arg(model.material).arg(model.variant)
|
||||||
visible: base.shouldShowExtruders
|
visible: base.shouldShowExtruders
|
||||||
enabled: UM.Selection.hasSelection
|
enabled: UM.Selection.hasSelection && model.enabled
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(model.id) != -1
|
checked: Cura.ExtruderManager.selectedObjectExtruders.indexOf(model.id) != -1
|
||||||
onTriggered: CuraActions.setExtruderForSelection(model.id)
|
onTriggered: CuraActions.setExtruderForSelection(model.id)
|
||||||
|
64
resources/qml/Menus/SettingVisibilityPresetsMenu.qml
Normal file
64
resources/qml/Menus/SettingVisibilityPresetsMenu.qml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
|
import UM 1.2 as UM
|
||||||
|
import Cura 1.0 as Cura
|
||||||
|
|
||||||
|
Menu
|
||||||
|
{
|
||||||
|
id: menu
|
||||||
|
title: catalog.i18nc("@action:inmenu", "Visible Settings")
|
||||||
|
|
||||||
|
property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel()
|
||||||
|
property bool showingSearchResults
|
||||||
|
property bool showingAllSettings
|
||||||
|
|
||||||
|
signal showAllSettings()
|
||||||
|
signal showSettingVisibilityProfile()
|
||||||
|
|
||||||
|
Instantiator
|
||||||
|
{
|
||||||
|
model: settingVisibilityPresetsModel
|
||||||
|
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: model.name
|
||||||
|
checkable: true
|
||||||
|
checked: model.id == settingVisibilityPresetsModel.activePreset
|
||||||
|
exclusiveGroup: group
|
||||||
|
onTriggered:
|
||||||
|
{
|
||||||
|
settingVisibilityPresetsModel.setActivePreset(model.id);
|
||||||
|
showSettingVisibilityProfile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onObjectAdded: menu.insertItem(index, object)
|
||||||
|
onObjectRemoved: menu.removeItem(object)
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuSeparator {}
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: catalog.i18nc("@action:inmenu", "All Settings")
|
||||||
|
checkable: true
|
||||||
|
checked: showingAllSettings
|
||||||
|
exclusiveGroup: group
|
||||||
|
onTriggered:
|
||||||
|
{
|
||||||
|
showAllSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MenuSeparator {}
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: catalog.i18nc("@action:inmenu", "Manage Setting Visibility...")
|
||||||
|
iconName: "configure"
|
||||||
|
onTriggered: Cura.Actions.configureSettingVisibility.trigger()
|
||||||
|
}
|
||||||
|
|
||||||
|
ExclusiveGroup { id: group }
|
||||||
|
}
|
@ -13,6 +13,8 @@ UM.PreferencesPage
|
|||||||
{
|
{
|
||||||
title: catalog.i18nc("@title:tab", "Setting Visibility");
|
title: catalog.i18nc("@title:tab", "Setting Visibility");
|
||||||
|
|
||||||
|
property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel()
|
||||||
|
|
||||||
property int scrollToIndex: 0
|
property int scrollToIndex: 0
|
||||||
|
|
||||||
signal scrollToSection( string key )
|
signal scrollToSection( string key )
|
||||||
@ -26,9 +28,8 @@ UM.PreferencesPage
|
|||||||
UM.Preferences.resetPreference("general/visible_settings")
|
UM.Preferences.resetPreference("general/visible_settings")
|
||||||
|
|
||||||
// After calling this function update Setting visibility preset combobox.
|
// After calling this function update Setting visibility preset combobox.
|
||||||
// Reset should set "Basic" setting preset
|
// Reset should set default setting preset ("Basic")
|
||||||
visibilityPreset.setBasicPreset()
|
visibilityPreset.currentIndex = 1
|
||||||
|
|
||||||
}
|
}
|
||||||
resetEnabled: true;
|
resetEnabled: true;
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ UM.PreferencesPage
|
|||||||
if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1)
|
if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1)
|
||||||
{
|
{
|
||||||
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
|
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.get(visibilityPreset.currentIndex).text)
|
UM.Preferences.setValue("cura/active_setting_visibility_preset", visibilityPreset.model.getItem(visibilityPreset.currentIndex).id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,83 +111,33 @@ UM.PreferencesPage
|
|||||||
|
|
||||||
ComboBox
|
ComboBox
|
||||||
{
|
{
|
||||||
property int customOptionValue: 100
|
|
||||||
|
|
||||||
function setBasicPreset()
|
|
||||||
{
|
|
||||||
var index = 0
|
|
||||||
for(var i = 0; i < presetNamesList.count; ++i)
|
|
||||||
{
|
|
||||||
if(model.get(i).text == "Basic")
|
|
||||||
{
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visibilityPreset.currentIndex = index
|
|
||||||
}
|
|
||||||
|
|
||||||
id: visibilityPreset
|
id: visibilityPreset
|
||||||
width: 150
|
width: 150 * screenScaleFactor
|
||||||
anchors
|
anchors
|
||||||
{
|
{
|
||||||
top: parent.top
|
top: parent.top
|
||||||
right: parent.right
|
right: parent.right
|
||||||
}
|
}
|
||||||
|
|
||||||
model: ListModel
|
model: settingVisibilityPresetsModel
|
||||||
{
|
textRole: "name"
|
||||||
id: presetNamesList
|
|
||||||
Component.onCompleted:
|
|
||||||
{
|
|
||||||
// returned value is Dictionary (Ex: {1:"Basic"}, The number 1 is the weight and sort by weight)
|
|
||||||
var itemsDict = UM.Preferences.getValue("general/visible_settings_preset")
|
|
||||||
var sorted = [];
|
|
||||||
for(var key in itemsDict) {
|
|
||||||
sorted[sorted.length] = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
sorted.sort();
|
|
||||||
for(var i = 0; i < sorted.length; i++) {
|
|
||||||
presetNamesList.append({text: itemsDict[sorted[i]], value: i});
|
|
||||||
}
|
|
||||||
|
|
||||||
// By agreement lets "Custom" option will have value 100
|
|
||||||
presetNamesList.append({text: "Custom", value: visibilityPreset.customOptionValue});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentIndex:
|
currentIndex:
|
||||||
{
|
{
|
||||||
// Load previously selected preset.
|
// Load previously selected preset.
|
||||||
var text = UM.Preferences.getValue("general/preset_setting_visibility_choice");
|
var index = settingVisibilityPresetsModel.find("id", settingVisibilityPresetsModel.activePreset)
|
||||||
|
if (index == -1)
|
||||||
|
|
||||||
|
|
||||||
var index = 0;
|
|
||||||
for(var i = 0; i < presetNamesList.count; ++i)
|
|
||||||
{
|
{
|
||||||
if(model.get(i).text == text)
|
return 0
|
||||||
{
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return index;
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated:
|
onActivated:
|
||||||
{
|
{
|
||||||
// TODO What to do if user is selected "Custom from Combobox" ?
|
var preset_id = settingVisibilityPresetsModel.getItem(index).id;
|
||||||
if (model.get(index).text == "Custom"){
|
settingVisibilityPresetsModel.setActivePreset(preset_id);
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var newVisibleSettings = CuraApplication.getVisibilitySettingPreset(model.get(index).text)
|
|
||||||
UM.Preferences.setValue("general/visible_settings", newVisibleSettings)
|
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +167,7 @@ UM.PreferencesPage
|
|||||||
exclude: ["machine_settings", "command_line_settings"]
|
exclude: ["machine_settings", "command_line_settings"]
|
||||||
showAncestors: true
|
showAncestors: true
|
||||||
expanded: ["*"]
|
expanded: ["*"]
|
||||||
visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
|
visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Loader
|
delegate: Loader
|
||||||
@ -259,19 +210,7 @@ UM.PreferencesPage
|
|||||||
{
|
{
|
||||||
id: settingVisibilityItem;
|
id: settingVisibilityItem;
|
||||||
|
|
||||||
UM.SettingVisibilityItem {
|
UM.SettingVisibilityItem { }
|
||||||
|
|
||||||
// after changing any visibility of settings, set the preset to the "Custom" option
|
|
||||||
visibilityChangeCallback : function()
|
|
||||||
{
|
|
||||||
// If already "Custom" then don't do nothing
|
|
||||||
if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1)
|
|
||||||
{
|
|
||||||
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
|
|
||||||
UM.Preferences.setValue("general/preset_setting_visibility_choice", visibilityPreset.model.get(visibilityPreset.currentIndex).text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -215,7 +215,8 @@ SettingItem
|
|||||||
{
|
{
|
||||||
text: model.name
|
text: model.name
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
color: {
|
color:
|
||||||
|
{
|
||||||
if (model.enabled) {
|
if (model.enabled) {
|
||||||
UM.Theme.getColor("setting_control_text")
|
UM.Theme.getColor("setting_control_text")
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,9 +26,20 @@ SettingItem
|
|||||||
textRole: "name"
|
textRole: "name"
|
||||||
|
|
||||||
onActivated:
|
onActivated:
|
||||||
|
{
|
||||||
|
if (model.getItem(index).enabled)
|
||||||
{
|
{
|
||||||
forceActiveFocus();
|
forceActiveFocus();
|
||||||
propertyProvider.setPropertyValue("value", model.getItem(index).index);
|
propertyProvider.setPropertyValue("value", model.getItem(index).index);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if (propertyProvider.properties.value == -1)
|
||||||
|
{
|
||||||
|
control.currentIndex = model.rowCount() - 1; // we know the last item is "Not overriden"
|
||||||
|
} else {
|
||||||
|
control.currentIndex = propertyProvider.properties.value; // revert to the old value
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onActiveFocusChanged:
|
onActiveFocusChanged:
|
||||||
@ -192,7 +203,14 @@ SettingItem
|
|||||||
{
|
{
|
||||||
text: model.name
|
text: model.name
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
color: UM.Theme.getColor("setting_control_text")
|
color:
|
||||||
|
{
|
||||||
|
if (model.enabled) {
|
||||||
|
UM.Theme.getColor("setting_control_text")
|
||||||
|
} else {
|
||||||
|
UM.Theme.getColor("action_button_disabled_text");
|
||||||
|
}
|
||||||
|
}
|
||||||
font: UM.Theme.getFont("default")
|
font: UM.Theme.getFont("default")
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
@ -13,12 +13,18 @@ SettingItem
|
|||||||
|
|
||||||
property string textBeforeEdit
|
property string textBeforeEdit
|
||||||
property bool textHasChanged
|
property bool textHasChanged
|
||||||
|
property bool focusGainedByClick: false
|
||||||
onFocusReceived:
|
onFocusReceived:
|
||||||
{
|
{
|
||||||
textHasChanged = false;
|
textHasChanged = false;
|
||||||
textBeforeEdit = focusItem.text;
|
textBeforeEdit = focusItem.text;
|
||||||
|
|
||||||
|
if(!focusGainedByClick)
|
||||||
|
{
|
||||||
|
// select all text when tabbing through fields (but not when selecting a field with the mouse)
|
||||||
focusItem.selectAll();
|
focusItem.selectAll();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
contents: Rectangle
|
contents: Rectangle
|
||||||
{
|
{
|
||||||
@ -93,14 +99,6 @@ SettingItem
|
|||||||
font: UM.Theme.getFont("default")
|
font: UM.Theme.getFont("default")
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea
|
|
||||||
{
|
|
||||||
id: mouseArea
|
|
||||||
anchors.fill: parent;
|
|
||||||
//hoverEnabled: true;
|
|
||||||
cursorShape: Qt.IBeamCursor
|
|
||||||
}
|
|
||||||
|
|
||||||
TextInput
|
TextInput
|
||||||
{
|
{
|
||||||
id: input
|
id: input
|
||||||
@ -142,6 +140,7 @@ SettingItem
|
|||||||
{
|
{
|
||||||
base.focusReceived();
|
base.focusReceived();
|
||||||
}
|
}
|
||||||
|
base.focusGainedByClick = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text")
|
color: !enabled ? UM.Theme.getColor("setting_control_disabled_text") : UM.Theme.getColor("setting_control_text")
|
||||||
@ -178,6 +177,22 @@ SettingItem
|
|||||||
}
|
}
|
||||||
when: !input.activeFocus
|
when: !input.activeFocus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent;
|
||||||
|
|
||||||
|
cursorShape: Qt.IBeamCursor
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
if(!input.activeFocus) {
|
||||||
|
base.focusGainedByClick = true;
|
||||||
|
input.forceActiveFocus();
|
||||||
|
}
|
||||||
|
mouse.accepted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,12 @@ Item
|
|||||||
{
|
{
|
||||||
id: base;
|
id: base;
|
||||||
|
|
||||||
property Action configureSettings;
|
property QtObject settingVisibilityPresetsModel: CuraApplication.getSettingVisibilityPresetsModel()
|
||||||
property bool findingSettings;
|
property Action configureSettings
|
||||||
signal showTooltip(Item item, point location, string text);
|
property bool findingSettings
|
||||||
signal hideTooltip();
|
property bool showingAllSettings
|
||||||
|
signal showTooltip(Item item, point location, string text)
|
||||||
|
signal hideTooltip()
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
@ -107,6 +109,57 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToolButton
|
||||||
|
{
|
||||||
|
id: settingVisibilityMenu
|
||||||
|
|
||||||
|
width: height
|
||||||
|
height: UM.Theme.getSize("setting_control").height
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
top: globalProfileRow.bottom
|
||||||
|
topMargin: UM.Theme.getSize("sidebar_margin").height
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: UM.Theme.getSize("sidebar_margin").width
|
||||||
|
}
|
||||||
|
style: ButtonStyle
|
||||||
|
{
|
||||||
|
background: Item {
|
||||||
|
UM.RecolorImage {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: UM.Theme.getSize("standard_arrow").width
|
||||||
|
height: UM.Theme.getSize("standard_arrow").height
|
||||||
|
sourceSize.width: width
|
||||||
|
sourceSize.height: width
|
||||||
|
color: control.enabled ? UM.Theme.getColor("setting_category_text") : UM.Theme.getColor("setting_category_disabled_text")
|
||||||
|
source: UM.Theme.getIcon("menu")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label: Label{}
|
||||||
|
}
|
||||||
|
menu: SettingVisibilityPresetsMenu
|
||||||
|
{
|
||||||
|
showingSearchResults: findingSettings
|
||||||
|
showingAllSettings: showingAllSettings
|
||||||
|
|
||||||
|
onShowAllSettings:
|
||||||
|
{
|
||||||
|
base.showingAllSettings = true;
|
||||||
|
base.findingSettings = false;
|
||||||
|
filter.text = "";
|
||||||
|
filter.updateDefinitionModel();
|
||||||
|
}
|
||||||
|
onShowSettingVisibilityProfile:
|
||||||
|
{
|
||||||
|
base.showingAllSettings = false;
|
||||||
|
base.findingSettings = false;
|
||||||
|
filter.text = "";
|
||||||
|
filter.updateDefinitionModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
id: filterContainer
|
id: filterContainer
|
||||||
@ -132,9 +185,9 @@ Item
|
|||||||
top: globalProfileRow.bottom
|
top: globalProfileRow.bottom
|
||||||
topMargin: UM.Theme.getSize("sidebar_margin").height
|
topMargin: UM.Theme.getSize("sidebar_margin").height
|
||||||
left: parent.left
|
left: parent.left
|
||||||
leftMargin: Math.round(UM.Theme.getSize("sidebar_margin").width)
|
leftMargin: UM.Theme.getSize("sidebar_margin").width
|
||||||
right: parent.right
|
right: settingVisibilityMenu.left
|
||||||
rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width)
|
rightMargin: Math.floor(UM.Theme.getSize("default_margin").width / 2)
|
||||||
}
|
}
|
||||||
height: visible ? UM.Theme.getSize("setting_control").height : 0
|
height: visible ? UM.Theme.getSize("setting_control").height : 0
|
||||||
Behavior on height { NumberAnimation { duration: 100 } }
|
Behavior on height { NumberAnimation { duration: 100 } }
|
||||||
@ -168,17 +221,9 @@ Item
|
|||||||
{
|
{
|
||||||
if(findingSettings)
|
if(findingSettings)
|
||||||
{
|
{
|
||||||
expandedCategories = definitionsModel.expanded.slice();
|
showingAllSettings = false;
|
||||||
definitionsModel.expanded = ["*"];
|
|
||||||
definitionsModel.showAncestors = true;
|
|
||||||
definitionsModel.showAll = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
definitionsModel.expanded = expandedCategories;
|
|
||||||
definitionsModel.showAncestors = false;
|
|
||||||
definitionsModel.showAll = false;
|
|
||||||
}
|
}
|
||||||
|
updateDefinitionModel();
|
||||||
lastFindingSettings = findingSettings;
|
lastFindingSettings = findingSettings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,6 +232,27 @@ Item
|
|||||||
{
|
{
|
||||||
filter.text = "";
|
filter.text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateDefinitionModel()
|
||||||
|
{
|
||||||
|
if(findingSettings || showingAllSettings)
|
||||||
|
{
|
||||||
|
expandedCategories = definitionsModel.expanded.slice();
|
||||||
|
definitionsModel.expanded = [""]; // keep categories closed while to prevent render while making settings visible one by one
|
||||||
|
definitionsModel.showAncestors = true;
|
||||||
|
definitionsModel.showAll = true;
|
||||||
|
definitionsModel.expanded = ["*"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(expandedCategories)
|
||||||
|
{
|
||||||
|
definitionsModel.expanded = expandedCategories;
|
||||||
|
}
|
||||||
|
definitionsModel.showAncestors = false;
|
||||||
|
definitionsModel.showAll = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea
|
MouseArea
|
||||||
@ -209,7 +275,7 @@ Item
|
|||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: Math.round(UM.Theme.getSize("sidebar_margin").width)
|
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||||
|
|
||||||
color: UM.Theme.getColor("setting_control_button")
|
color: UM.Theme.getColor("setting_control_button")
|
||||||
hoverColor: UM.Theme.getColor("setting_control_button_hover")
|
hoverColor: UM.Theme.getColor("setting_control_button_hover")
|
||||||
@ -374,6 +440,7 @@ Item
|
|||||||
key: model.key ? model.key : ""
|
key: model.key ? model.key : ""
|
||||||
watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
|
watchedProperties: [ "value", "enabled", "state", "validationState", "settable_per_extruder", "resolve" ]
|
||||||
storeIndex: 0
|
storeIndex: 0
|
||||||
|
removeUnusedValue: model.resolve == undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections
|
Connections
|
||||||
@ -491,9 +558,17 @@ Item
|
|||||||
MenuItem
|
MenuItem
|
||||||
{
|
{
|
||||||
//: Settings context menu action
|
//: Settings context menu action
|
||||||
visible: !findingSettings;
|
visible: !(findingSettings || showingAllSettings);
|
||||||
text: catalog.i18nc("@action:menu", "Hide this setting");
|
text: catalog.i18nc("@action:menu", "Hide this setting");
|
||||||
onTriggered: definitionsModel.hide(contextMenu.key);
|
onTriggered:
|
||||||
|
{
|
||||||
|
definitionsModel.hide(contextMenu.key);
|
||||||
|
// visible settings have changed, so we're no longer showing a preset
|
||||||
|
if (settingVisibilityPresetsModel.activePreset != "" && !showingAllSettings)
|
||||||
|
{
|
||||||
|
settingVisibilityPresetsModel.setActivePreset("custom");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MenuItem
|
MenuItem
|
||||||
{
|
{
|
||||||
@ -509,7 +584,7 @@ Item
|
|||||||
return catalog.i18nc("@action:menu", "Keep this setting visible");
|
return catalog.i18nc("@action:menu", "Keep this setting visible");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visible: findingSettings;
|
visible: (findingSettings || showingAllSettings);
|
||||||
onTriggered:
|
onTriggered:
|
||||||
{
|
{
|
||||||
if (contextMenu.settingVisible)
|
if (contextMenu.settingVisible)
|
||||||
@ -520,12 +595,17 @@ Item
|
|||||||
{
|
{
|
||||||
definitionsModel.show(contextMenu.key);
|
definitionsModel.show(contextMenu.key);
|
||||||
}
|
}
|
||||||
|
// visible settings have changed, so we're no longer showing a preset
|
||||||
|
if (settingVisibilityPresetsModel.activePreset != "" && !showingAllSettings)
|
||||||
|
{
|
||||||
|
settingVisibilityPresetsModel.setActivePreset("custom");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MenuItem
|
MenuItem
|
||||||
{
|
{
|
||||||
//: Settings context menu action
|
//: Settings context menu action
|
||||||
text: catalog.i18nc("@action:menu", "Configure setting visiblity...");
|
text: catalog.i18nc("@action:menu", "Configure setting visibility...");
|
||||||
|
|
||||||
onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu);
|
onTriggered: Cura.Actions.configureSettingVisibility.trigger(contextMenu);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ Rectangle
|
|||||||
property bool hideView: Cura.MachineManager.activeMachineName == ""
|
property bool hideView: Cura.MachineManager.activeMachineName == ""
|
||||||
|
|
||||||
// Is there an output device for this printer?
|
// Is there an output device for this printer?
|
||||||
|
property bool isNetworkPrinter: Cura.MachineManager.activeMachineNetworkKey != ""
|
||||||
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
|
||||||
@ -86,7 +87,8 @@ Rectangle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MachineSelection {
|
MachineSelection
|
||||||
|
{
|
||||||
id: machineSelection
|
id: machineSelection
|
||||||
width: base.width - configSelection.width - separator.width
|
width: base.width - configSelection.width - separator.width
|
||||||
height: UM.Theme.getSize("sidebar_header").height
|
height: UM.Theme.getSize("sidebar_header").height
|
||||||
@ -104,9 +106,10 @@ Rectangle
|
|||||||
anchors.left: machineSelection.right
|
anchors.left: machineSelection.right
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationSelection {
|
ConfigurationSelection
|
||||||
|
{
|
||||||
id: configSelection
|
id: configSelection
|
||||||
visible: printerConnected && !sidebar.monitoringPrint && !sidebar.hideSettings
|
visible: isNetworkPrinter
|
||||||
width: visible ? Math.round(base.width * 0.15) : 0
|
width: visible ? Math.round(base.width * 0.15) : 0
|
||||||
height: UM.Theme.getSize("sidebar_header").height
|
height: UM.Theme.getSize("sidebar_header").height
|
||||||
anchors.top: base.top
|
anchors.top: base.top
|
||||||
|
@ -178,6 +178,7 @@ Column
|
|||||||
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
|
text: catalog.i18nc("@action:inmenu", "Disable Extruder")
|
||||||
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
|
onTriggered: Cura.MachineManager.setExtruderEnabled(model.index, false)
|
||||||
visible: extruder_enabled
|
visible: extruder_enabled
|
||||||
|
enabled: Cura.MachineManager.numberExtrudersEnabled > 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +348,8 @@ Column
|
|||||||
id: materialSelection
|
id: materialSelection
|
||||||
|
|
||||||
property var activeExtruder: Cura.MachineManager.activeStack
|
property var activeExtruder: Cura.MachineManager.activeStack
|
||||||
property var currentRootMaterialName: activeExtruder.material.name
|
property var hasActiveExtruder: activeExtruder != null
|
||||||
|
property var currentRootMaterialName: hasActiveExtruder ? activeExtruder.material.name : ""
|
||||||
|
|
||||||
text: currentRootMaterialName
|
text: currentRootMaterialName
|
||||||
tooltip: currentRootMaterialName
|
tooltip: currentRootMaterialName
|
||||||
@ -366,6 +368,10 @@ Column
|
|||||||
property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported
|
property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported
|
||||||
|
|
||||||
function isMaterialSupported () {
|
function isMaterialSupported () {
|
||||||
|
if (!hasActiveExtruder)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return Cura.ContainerManager.getContainerMetaDataEntry(activeExtruder.material.id, "compatible") == "True"
|
return Cura.ContainerManager.getContainerMetaDataEntry(activeExtruder.material.id, "compatible") == "True"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,6 +474,74 @@ Column
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Material info row
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
id: materialInfoRow
|
||||||
|
height: Math.round(UM.Theme.getSize("sidebar_setup").height / 2)
|
||||||
|
visible: (Cura.MachineManager.hasVariants || Cura.MachineManager.hasMaterials) && !sidebar.monitoringPrint && !sidebar.hideSettings
|
||||||
|
|
||||||
|
anchors
|
||||||
|
{
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: UM.Theme.getSize("sidebar_margin").width
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: UM.Theme.getSize("sidebar_margin").width
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: UM.Theme.getSize("sidebar_setup").height
|
||||||
|
anchors.right: parent.right
|
||||||
|
width: Math.round(parent.width * 0.7 + UM.Theme.getSize("sidebar_margin").width)
|
||||||
|
|
||||||
|
UM.RecolorImage {
|
||||||
|
id: warningImage
|
||||||
|
anchors.right: materialInfoLabel.left
|
||||||
|
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||||
|
anchors.verticalCenter: parent.Bottom
|
||||||
|
source: UM.Theme.getIcon("warning")
|
||||||
|
width: UM.Theme.getSize("section_icon").width
|
||||||
|
height: UM.Theme.getSize("section_icon").height
|
||||||
|
color: UM.Theme.getColor("material_compatibility_warning")
|
||||||
|
visible: !Cura.MachineManager.isCurrentSetupSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: materialInfoLabel
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
text: "<a href='%1'>" + catalog.i18nc("@label", "Check compatibility") + "</a>"
|
||||||
|
font: UM.Theme.getFont("default")
|
||||||
|
color: UM.Theme.getColor("text")
|
||||||
|
linkColor: UM.Theme.getColor("text_link")
|
||||||
|
verticalAlignment: Text.AlignTop
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: {
|
||||||
|
// open the material URL with web browser
|
||||||
|
var version = UM.Application.version;
|
||||||
|
var machineName = Cura.MachineManager.activeMachine.definition.id;
|
||||||
|
var url = "https://ultimaker.com/materialcompatibility/" + version + "/" + machineName + "?utm_source=cura&utm_medium=software&utm_campaign=resources";
|
||||||
|
Qt.openUrlExternally(url);
|
||||||
|
}
|
||||||
|
onEntered: {
|
||||||
|
var content = catalog.i18nc("@tooltip", "Click to check the material compatibility on Ultimaker.com.");
|
||||||
|
base.showTooltip(
|
||||||
|
materialInfoRow,
|
||||||
|
Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0),
|
||||||
|
catalog.i18nc("@tooltip", content)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
onExited: base.hideTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UM.SettingPropertyProvider
|
UM.SettingPropertyProvider
|
||||||
{
|
{
|
||||||
id: machineExtruderCount
|
id: machineExtruderCount
|
||||||
|
@ -243,6 +243,81 @@ Item
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
|
anchors.topMargin: UM.Theme.getSize("sidebar_margin").height
|
||||||
|
|
||||||
|
// This Item is used only for tooltip, for slider area which is unavailable
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
function showTooltip (showTooltip)
|
||||||
|
{
|
||||||
|
if (showTooltip) {
|
||||||
|
var content = catalog.i18nc("@tooltip", "This quality profile is not available for you current material and nozzle configuration. Please change these to enable this quality profile")
|
||||||
|
base.showTooltip(qualityRow, Qt.point(-UM.Theme.getSize("sidebar_margin").width, customisedSettings.height), content)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
base.hideTooltip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id: unavailableLineToolTip
|
||||||
|
height: 20 // hovered area height
|
||||||
|
z: parent.z + 1 // should be higher, otherwise the area can be hovered
|
||||||
|
x: 0
|
||||||
|
anchors.verticalCenter: qualitySlider.verticalCenter
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: leftArea
|
||||||
|
width:
|
||||||
|
{
|
||||||
|
if (qualityModel.availableTotalTicks == 0) {
|
||||||
|
return qualityModel.qualitySliderStepWidth * qualityModel.totalTicks
|
||||||
|
}
|
||||||
|
return qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin - 10
|
||||||
|
}
|
||||||
|
height: parent.height
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false
|
||||||
|
onEntered: unavailableLineToolTip.showTooltip(true)
|
||||||
|
onExited: unavailableLineToolTip.showTooltip(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: rightArea
|
||||||
|
width: {
|
||||||
|
if(qualityModel.availableTotalTicks == 0)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return qualityModel.qualitySliderMarginRight - 10
|
||||||
|
}
|
||||||
|
height: parent.height
|
||||||
|
color: "transparent"
|
||||||
|
x: {
|
||||||
|
if (qualityModel.availableTotalTicks == 0) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var leftUnavailableArea = qualityModel.qualitySliderStepWidth * qualityModel.qualitySliderAvailableMin
|
||||||
|
var totalGap = qualityModel.qualitySliderStepWidth * (qualityModel.availableTotalTicks -1) + leftUnavailableArea + 10
|
||||||
|
|
||||||
|
return totalGap
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
enabled: Cura.SimpleModeSettingsManager.isProfileUserCreated == false
|
||||||
|
onEntered: unavailableLineToolTip.showTooltip(true)
|
||||||
|
onExited: unavailableLineToolTip.showTooltip(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Draw Unavailable line
|
// Draw Unavailable line
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
|
@ -101,7 +101,7 @@ UM.Dialog
|
|||||||
}
|
}
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
text: Cura.MachineManager.activeMachine.definition.name
|
text: (Cura.MachineManager.activeMachine == null) ? "" : Cura.MachineManager.activeMachine.definition.name
|
||||||
width: (parent.width / 3) | 0
|
width: (parent.width / 3) | 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
resources/themes/cura-light/icons/menu.svg
Normal file
3
resources/themes/cura-light/icons/menu.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">
|
||||||
|
<path d="m 30,23.75 v 2.5 q 0,0.50781 -0.37109,0.87891 Q 29.25781,27.5 28.75,27.5 H 1.25 Q 0.74219,27.5 0.37109,27.12891 0,26.75781 0,26.25 v -2.5 Q 0,23.24219 0.37109,22.87109 0.74219,22.5 1.25,22.5 h 27.5 q 0.50781,0 0.87891,0.37109 Q 30,23.24219 30,23.75 Z m 0,-10 v 2.5 q 0,0.50781 -0.37109,0.87891 Q 29.25781,17.5 28.75,17.5 H 1.25 Q 0.74219,17.5 0.37109,17.12891 0,16.75781 0,16.25 v -2.5 Q 0,13.24219 0.37109,12.87109 0.74219,12.5 1.25,12.5 h 27.5 q 0.50781,0 0.87891,0.37109 Q 30,13.24219 30,13.75 Z m 0,-10 v 2.5 Q 30,6.75781 29.62891,7.12891 29.25781,7.5 28.75,7.5 H 1.25 Q 0.74219,7.5 0.37109,7.12891 0,6.75781 0,6.25 V 3.75 Q 0,3.24219 0.37109,2.87109 0.74219,2.5 1.25,2.5 h 27.5 q 0.50781,0 0.87891,0.37109 Q 30,3.24219 30,3.75 Z" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 817 B |
@ -56,7 +56,6 @@ retraction_amount = 4.5
|
|||||||
retraction_count_max = 15
|
retraction_count_max = 15
|
||||||
retraction_extrusion_window = =retraction_amount
|
retraction_extrusion_window = =retraction_amount
|
||||||
retraction_hop = 2
|
retraction_hop = 2
|
||||||
retraction_hop_enabled = True
|
|
||||||
retraction_hop_only_when_collides = True
|
retraction_hop_only_when_collides = True
|
||||||
retraction_min_travel = 5
|
retraction_min_travel = 5
|
||||||
retraction_prime_speed = 15
|
retraction_prime_speed = 15
|
||||||
|
Loading…
x
Reference in New Issue
Block a user